【问题标题】:How to write XML declaration using xml.etree.ElementTree如何使用 xml.etree.ElementTree 编写 XML 声明
【发布时间】:2019-07-26 10:42:35
【问题描述】:

我正在使用ElementTree 在 Python 中生成 XML 文档,但在转换为纯文本时,tostring 函数不包含 XML declaration

from xml.etree.ElementTree import Element, tostring

document = Element('outer')
node = SubElement(document, 'inner')
node.NewValue = 1
print tostring(document)  # Outputs "<outer><inner /></outer>"

我需要我的字符串包含以下 XML 声明:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>

但是,似乎没有任何记录在案的方法。

是否有合适的方法来呈现ElementTree 中的 XML 声明?

【问题讨论】:

    标签: python xml elementtree


    【解决方案1】:

    我会使用 lxml(参见 http://lxml.de/api.html)。

    那么你可以:

    from lxml import etree
    document = etree.Element('outer')
    node = etree.SubElement(document, 'inner')
    print(etree.tostring(document, xml_declaration=True))
    

    【讨论】:

      【解决方案2】:

      我惊讶地发现ElementTree.tostring() 似乎没有办法。但是,您可以使用 ElementTree.ElementTree.write() 将您的 XML 文档写入假文件:

      from io import BytesIO
      from xml.etree import ElementTree as ET
      
      document = ET.Element('outer')
      node = ET.SubElement(document, 'inner')
      et = ET.ElementTree(document)
      
      f = BytesIO()
      et.write(f, encoding='utf-8', xml_declaration=True) 
      print(f.getvalue())  # your XML file, encoded as UTF-8
      

      this question。即使那样,我认为如果不自己编写前缀,您也无法获得“独立”属性。

      【讨论】:

      • 为什么要在这里定义“node”变量?
      • 感谢这一行 et.write(f, encoding='utf-8', xml_declaration=True) 拯救了我的一天
      • 'et.write()' 是否有漂亮的打印参数?或任何其他方式来生成带有换行符的 xml?
      【解决方案3】:

      我最近遇到这个问题,经过一些代码挖掘,我发现以下代码sn -p是函数ElementTree.write的定义

      def write(self, file, encoding="us-ascii"):
          assert self._root is not None
          if not hasattr(file, "write"):
              file = open(file, "wb")
          if not encoding:
              encoding = "us-ascii"
          elif encoding != "utf-8" and encoding != "us-ascii":
              file.write("<?xml version='1.0' encoding='%s'?>\n" % 
           encoding)
          self._write(file, self._root, encoding, {})
      

      所以答案是,如果您需要将 XML 标头写入文件,请设置 encoding 参数而不是 utf-8us-ascii,例如UTF-8

      【讨论】:

      • 这将是一个很好的虽然脆弱的 hack,但它似乎不起作用(在此之前编码可能是小写的)。此外,ElementTree.ElementTree.write() 被记录为具有 xml_declaration 参数(请参阅接受的答案)。但是ElementTree.tostring() 没有那个参数,这是原问题中提出的方法。
      【解决方案4】:

      我会使用ET:

      try:
          from lxml import etree
          print("running with lxml.etree")
      except ImportError:
          try:
              # Python 2.5
              import xml.etree.cElementTree as etree
              print("running with cElementTree on Python 2.5+")
          except ImportError:
              try:
                  # Python 2.5
                  import xml.etree.ElementTree as etree
                  print("running with ElementTree on Python 2.5+")
              except ImportError:
                  try:
                      # normal cElementTree install
                      import cElementTree as etree
                      print("running with cElementTree")
                  except ImportError:
                     try:
                         # normal ElementTree install
                         import elementtree.ElementTree as etree
                         print("running with ElementTree")
                     except ImportError:
                         print("Failed to import ElementTree from any known place")
      
      document = etree.Element('outer')
      node = etree.SubElement(document, 'inner')
      print(etree.tostring(document, encoding='UTF-8', xml_declaration=True))
      

      【讨论】:

        【解决方案5】:

        如果您只想打印,这很有效。当我尝试将其发送到文件时出现错误...

        import xml.dom.minidom as minidom
        import xml.etree.ElementTree as ET
        from xml.etree.ElementTree import Element, SubElement, Comment, tostring
        
        def prettify(elem):
            rough_string = ET.tostring(elem, 'utf-8')
            reparsed = minidom.parseString(rough_string)
            return reparsed.toprettyxml(indent="  ")
        

        【讨论】:

          【解决方案6】:

          If you include the encoding='utf8', you will get an XML header:

          xml.etree.ElementTree.tostring 使用 encoding='utf8' 编写 XML 编码声明

          示例 Python 代码(适用于 Python 2 和 3):

          import xml.etree.ElementTree as ElementTree
          
          tree = ElementTree.ElementTree(
              ElementTree.fromstring('<xml><test>123</test></xml>')
          )
          root = tree.getroot()
          
          print('without:')
          print(ElementTree.tostring(root, method='xml'))
          print('')
          print('with:')
          print(ElementTree.tostring(root, encoding='utf8', method='xml'))
          

          Python 2 输出:

          $ python2 example.py
          without:
          <xml><test>123</test></xml>
          
          with:
          <?xml version='1.0' encoding='utf8'?>
          <xml><test>123</test></xml>
          

          在 Python 3 中,您会注意到 the b prefix 表示返回字节文字(就像 Python 2 一样):

          $ python3 example.py
          without:
          b'<xml><test>123</test></xml>'
          
          with:
          b"<?xml version='1.0' encoding='utf8'?>\n<xml><test>123</test></xml>"
          

          【讨论】:

          • 在 Python 3 中,转义字符将在打印时显示在声明中。 &lt;?xml version=\'1.0\' encoding=\'utf8\'?&gt;
          • 这个答案的帮助是想知道为什么你做了这么多Elementree.Elementree(Elementree.fromstring(... 而我现在意识到fromstring 返回一个element 而不是ElementTree,而parse 方法确实返回ElementTree。这使得尝试使用字符串在测试套件中模拟 xml 文件非常令人困惑!如果您使用该元素并运行tostring,它允许那些编码和方法参数,但输出缺少&lt;?xml 声明行,现在我看到这是因为它不是完整的文档。
          • 请注意,utf8 不是有效的字符编码字符串。这也是 Python3 添加声明并将整个内容作为字节而不是字符串返回的原因。
          • @mbirth 因此该方法应声明为“tobytes”而不是“tostring”。
          • @MarekMarczak 不,XML 应该是 encoding='utf-8' 才有效。
          【解决方案7】:

          ElementTree 包用法的最小工作示例:

          import xml.etree.ElementTree as ET
          
          document = ET.Element('outer')
          node = ET.SubElement(document, 'inner')
          node.text = '1'
          res = ET.tostring(document, encoding='utf8', method='xml').decode()
          print(res)
          

          输出是:

          <?xml version='1.0' encoding='utf8'?>
          <outer><inner>1</inner></outer>
          

          【讨论】:

          【解决方案8】:

          在声明中包含“独立”

          我没有找到在文档中添加 standalone 参数的任何替代方法,因此我调整了 ET.tosting 函数以将其作为参数。

          from xml.etree import ElementTree as ET
          
          # Sample
          document = ET.Element('outer')
          node = ET.SubElement(document, 'inner')
          et = ET.ElementTree(document)
          
           # Function that you need   
           def tostring(element, declaration, encoding=None, method=None,):
               class dummy:
                   pass
               data = []
               data.append(declaration+"\n")
               file = dummy()
               file.write = data.append
               ET.ElementTree(element).write(file, encoding, method=method)
               return "".join(data)
          # Working example
          xdec = """<?xml version="1.0" encoding="UTF-8" standalone="no" ?>"""    
          xml = tostring(document, encoding='utf-8', declaration=xdec)
          

          【讨论】:

            【解决方案9】:

            另一个非常简单的选择是将所需的标头连接到 xml 字符串,如下所示:

            xml = (bytes('<?xml version="1.0" encoding="UTF-8"?>\n', encoding='utf-8') + ET.tostring(root))
            xml = xml.decode('utf-8')
            with open('invoice.xml', 'w+') as f:
                f.write(xml)
            

            【讨论】:

            • 它给出了这个错误:TypeError: str() 最多接受 1 个参数(给定 2 个)
            【解决方案10】:

            简单

            Python 2 和 3 的示例(encoding 参数必须是 utf8):

            import xml.etree.ElementTree as ElementTree
            
            tree = ElementTree.ElementTree(ElementTree.fromstring('<xml><test>123</test></xml>'))
            root = tree.getroot()
            print(ElementTree.tostring(root, encoding='utf8', method='xml'))
            

            从 Python 3.8 开始,这些东西有 xml_declaration 参数:

            3.8 版中的新功能:xml_declaration 和 default_namespace 参数。

            xml.etree.ElementTree.tostring(element, encoding="us-ascii", 方法="xml", *, xml_declaration=None, default_namespace=None, short_empty_elements=True) 生成 XML 的字符串表示 元素,包括所有子元素。 element 是一个 Element 实例。 encoding 1 是输出编码(默认为 US-ASCII)。采用 encoding="unicode" 生成一个 Unicode 字符串(否则,一个 生成字节串)。方法是“xml”、“html”或“text” (默认为“xml”)。 xml_declaration、default_namespace 和 short_empty_elements 与 ElementTree.write() 中的含义相同。 返回包含 XML 数据的(可选)编码字符串。

            Python 3.8 及更高版本的示例:

            import xml.etree.ElementTree as ElementTree
            
            tree = ElementTree.ElementTree(ElementTree.fromstring('<xml><test>123</test></xml>'))
            root = tree.getroot()
            print(ElementTree.tostring(root, encoding='unicode', method='xml', xml_declaration=True))
            

            【讨论】:

              【解决方案11】:

              xml_declaration 参数

              是否有合适的方法在 ElementTree 中呈现 XML 声明?

              是的,并且不需要使用.tostring 函数。根据ElementTree Documentation,你应该创建一个ElementTree对象,创建Element和SubElements,设置树的根,最后在.write函数中使用xml_declaration参数,所以声明行包含在输出文件中。

              你可以这样做:

              import xml.etree.ElementTree as ET
              
              tree = ET.ElementTree("tree")
              
              document = ET.Element("outer")
              node1 = ET.SubElement(document, "inner")
              node1.text = "text"
              
              tree._setroot(document)
              tree.write("./output.xml", encoding = "UTF-8", xml_declaration = True)  
              

              输出文件是:

              <?xml version='1.0' encoding='UTF-8'?>
              <outer><inner>text</inner></outer>
              

              【讨论】:

              • 这对我有用,似乎是最“正确”的解决方案
              猜你喜欢
              • 1970-01-01
              • 2021-12-27
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-11-06
              • 1970-01-01
              • 2011-11-25
              相关资源
              最近更新 更多