【问题标题】:inserting newlines in xml file generated via xml.etree.ElementTree in python在通过python中的xml.etree.ElementTree生成的xml文件中插入换行符
【发布时间】:2010-06-22 17:12:47
【问题描述】:

我在 python 中使用 xml.etree.ElementTree 创建了一个 xml 文件。然后我使用

tree.write(filename, "UTF-8") 

将文档写入文件。

但是当我使用文本编辑器打开文件名时,标签之间没有换行符。一切都是一条大线

如何以“漂亮打印”的格式写出文档,以便在所有 xml 标记之间有新行(希望有缩进等)?

【问题讨论】:

    标签: python xml


    【解决方案1】:

    我找到了一种避免新库和重新解析 xml 的新方法。 您只需要将根元素传递给此函数(请参见下面的说明):

    def indent(elem, level=0):
        i = "\n" + level*"  "
        if len(elem):
            if not elem.text or not elem.text.strip():
                elem.text = i + "  "
            if not elem.tail or not elem.tail.strip():
                elem.tail = i
            for elem in elem:
                indent(elem, level+1)
            if not elem.tail or not elem.tail.strip():
                elem.tail = i
        else:
            if level and (not elem.tail or not elem.tail.strip()):
                elem.tail = i
    

    xml.etree.ElementTree.Element 实例上有一个名为“tail”的属性。 该属性可以在节点之后设置一个字符串:

    "<a>text</a>tail"
    

    我发现了一个 2004 年的链接,讲述了一个 Element Library Functions 使用这个“尾巴”来缩进一个元素。

    例子:

    root = ET.fromstring("<fruits><fruit>banana</fruit><fruit>apple</fruit></fruits>""")
    tree = ET.ElementTree(root)
    
    indent(root)
    # writing xml
    tree.write("example.xml", encoding="utf-8", xml_declaration=True)
    

    “example.xml”的结果:

    <?xml version='1.0' encoding='utf-8'?>
    <fruits>
        <fruit>banana</fruit>
        <fruit>apple</fruit>
    </fruits>
    

    【讨论】:

    • 他向您提出了一个很好的解决方案 - 如果有什么安慰的话,我正在使用您的代码并且效果很好!
    • 我也喜欢你的解决方案。我只需要将函数中的第一行更改为不使用“/n”,而是使用os.linesep 以便在记事本(Windows)中正确获取新行。
    • 确实很棒的解决方案!事实上,当您将新的 SubElements 附加到 lxml 中的节点时,新元素没有设置尾部空白。因此,即使使用 lxml 包,您的解决方案也是必要的。
    • 惊人的解决方案!希望它被内置到库中。
    • 这很棒。正是我需要的。谢谢
    【解决方案2】:

    我认为最简单的解决方案是切换到lxml 库。在大多数情况下,您只需将导入从 import xml.etree.ElementTree as etree 更改为 from lxml import etree 或类似的。

    然后您可以在序列化时使用pretty_print 选项:

    tree.write(filename, pretty_print=True)
    

    (也可通过etree.tostring 获得)

    【讨论】:

    • 谢谢史蒂文。这就是我最终要做的。
    • 但这不适用于添加到树中的新创建元素。他们仍然看起来很笨拙
    • pretty_print 选项有什么作用? documentation 说它“启用格式化的 XML”,但是格式化 XML 是什么意思?
    【解决方案3】:

    ElementTree 中没有漂亮的打印支持,但您可以使用其他 XML 模块。

    例如xml.dom.minidom.Node.toprettyxml():

    Node.toprettyxml([indent=""[, newl=""[, encoding=""]]])

    返回文档的精美打印版本。 indent 指定缩进字符串,默认为制表符; newl 指定在每行末尾发出的字符串,默认为 \n。

    使用indentnewl 来满足您的要求。

    使用默认格式字符的示例:

    >>> from xml.dom import minidom
    >>> from xml.etree import ElementTree
    >>> tree1=ElementTree.XML('<tips><tip>1</tip><tip>2</tip></tips>')
    >>> ElementTree.tostring(tree1)
    '<tips><tip>1</tip><tip>2</tip></tips>'
    >>> print minidom.parseString(ElementTree.tostring(tree1)).toprettyxml()
    <?xml version="1.0" ?>
    <tips>
        <tip>
            1
        </tip>
        <tip>
            2
        </tip>
    </tips>
    
    >>> 
    

    【讨论】:

    • 很好的答案,但唯一的问题是:为什么 minidom 会插入多余的空格(对于 12 ;在 xml 中很重要)?
    • 好问题 ;-) 小心使用。
    • 感谢回答!它几乎为我醒来。唯一的问题是当我执行ET.tostring(main, encoding='utf8', method='xml').decode() 时,它会从标题中删除encoding="utf-8"。解决了toprettyxml(encoding='utf8')
    【解决方案4】:

    不使用外部库,您可以通过将每个元素的tail属性设置为'\n',轻松实现输出中每个XML标签之间的换行。

    您还可以在此处指定换行符后的制表符数。但是,在 OP 的用例选项卡中,使用外部库可能更容易实现,或者参见 Erick M. Sprengel 的回答。

    我在尝试使用 python 中的 xml.etree.ElementTree 修改 xml 文档时遇到了同样的问题。就我而言,我正在解析 xml 文件,清除某些元素(使用 Element.clear()),然后将结果写回文件。

    对于我已清除的每个元素,在输出文件中其标记后没有新行。

    ElementTree 的 Element.clear() 文档指出:

    此函数移除所有子元素,清除所有属性,并将文本和尾部属性设置为无。

    这让我意识到元素的文本和尾部属性是确定输出格式的方式。就我而言,我能够将已清除元素的这些属性设置为与清除之前相同的值。对于根 xml 元素的第一级子元素,此尾部值最终为 '\n\t',选项卡数表示输出中显示的选项卡数。

    【讨论】:

      【解决方案5】:

      According to this thread 你最好的选择是安装pyXml 并将其用于prettyprint ElementTree xml 内容(因为默认情况下 ElementTree 在 Python 中似乎没有漂亮的打印机):

      import xml.etree.ElementTree as ET
      
      from xml.dom.ext.reader import Sax2
      from xml.dom.ext import PrettyPrint
      from StringIO import StringIO
      
      def prettyPrintET(etNode):
          reader = Sax2.Reader()
          docNode = reader.fromString(ET.tostring(etNode))
          tmpStream = StringIO()
          PrettyPrint(docNode, stream=tmpStream)
          return tmpStream.getvalue()
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-04-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-02
        相关资源
        最近更新 更多