【问题标题】:Remove whitespaces in XML string删除 XML 字符串中的空格
【发布时间】:2011-03-19 15:28:59
【问题描述】:

如何在 Python 2.6 中删除 XML 字符串中的空格和换行符?我尝试了以下软件包:

etree:这个 sn-p 保留原始空格:

xmlStr = '''<root>
    <head></head>
    <content></content>
</root>'''

xmlElement = xml.etree.ElementTree.XML(xmlStr)
xmlStr = xml.etree.ElementTree.tostring(xmlElement, 'UTF-8')
print xmlStr

我不能使用提供 method 参数的 Python 2.7。

minidom:一样:

xmlDocument = xml.dom.minidom.parseString(xmlStr)
xmlStr = xmlDocument.toprettyxml(indent='', newl='', encoding='UTF-8')

【问题讨论】:

标签: python xml xml-serialization python-2.6 elementtree


【解决方案1】:
xmlStr = ' '.join(xmlStr.split()))

这会将所有文本放在一行中,用单个空格替换多个空格。

xmlStr = ''.join(xmlStr.split()))

这将完全删除空格,包括文本内的空格,并且不能使用。

对于您提供的输入,第一种形式可能有风险(但您要求):

xmlStr = '''<root>
    <head></head>
    <content></content>
</root>'''
xmlStr = ' '.join(xmlStr.split())
print xmlStr
""" Output:
<root> <head></head> <content></content> </root>
"""

这将是有效的 xml。虽然可能需要使用某种 xml 检查器进行检查。顺便说一句,您确定要使用 XML 吗?你读过这篇文章吗: Python Is Not Java

【讨论】:

  • -1 你的建议会破坏像"""&lt;v xml:space="preserve"&gt;\t\tfoo&lt;/v&gt;"""这样的东西
  • 我不得不同意约翰的观点。这根本不保留 XML 语法。
【解决方案2】:

空白在 XML 文档中很重要。使用空格进行缩进是对 XML 的不良使用,因为它在实际上没有空格的地方引入了重要的数据——遗憾的是,这是常态。您为去除空白而采取的任何编程方法充其量只是一种猜测——您需要更好地了解 XML 所传达的内容才能正确去除空白,而无需踩到某些数据的脚趾。

【讨论】:

【解决方案3】:

最简单的解决方案可能是使用lxml,您可以在其中设置解析器选项以忽略元素之间的空白:

>>> from lxml import etree
>>> parser = etree.XMLParser(remove_blank_text=True)
>>> xml_str = '''<root>
>>>     <head></head>
>>>     <content></content>
>>> </root>'''
>>> elem = etree.XML(xml_str, parser=parser)
>>> print etree.tostring(elem)
<root><head/><content/></root>

这可能足以满足您的需求,但为了安全起见,请注意一些警告:

这只会删除元素之间的空白节点,并尽量不要删除具有混合内容的元素内部的空白节点:

>>> elem = etree.XML('<p> spam <a>ham</a> <a>eggs</a></p>', parser=parser)
>>> print etree.tostring(elem)
<p> spam <a>ham</a> <a>eggs</a></p>

文本节点的前导或尾随空格不会被删除。然而,在某些情况下,它仍会从混合内容中删除空白节点:如果解析器尚未遇到该级别的非空白节点。

>>> elem = etree.XML('<p><a> ham</a> <a>eggs</a></p>', parser=parser)
>>> print etree.tostring(elem)
<p><a> ham</a><a>eggs</a></p>

如果你不想这样,你可以使用xml:space="preserve",这将受到尊重。另一种选择是使用 dtd 并使用 etree.XMLParser(load_dtd=True),其中解析器将使用 dtd 来确定哪些空白节点是重要的。

除此之外,您必须编写自己的代码来删除您不想要的空格(迭代后代,并在适当的情况下,将仅包含空格的 .text.tail 属性设置为 None 或空字符串)

【讨论】:

  • 我发现,正如@Steven 所指出的,一些只包含空格的元素没有被清除。在调用etree.tostring:re.sub(r'&gt;\s+&lt;', '&gt;&lt;', xml_str) 之后,我使用了正则表达式来执行此操作
  • 请在第一个 sn-p 中将 etree.XML(xml_str, parser=p) 替换为 etree.XML(xml_str, parser=parser)
  • 如果你可以使用 Python 3.9,有一个新函数 xml.etree.ElementTree.indent 也可以帮助解决这个问题,而无需任何 lxml 依赖项。
【解决方案4】:

一个有点笨拙的解决方案没有 lxml :-)

data = """<root>

    <head></head>    <content></content>

</root>"""

data3 = []
data2 = data.split('\n')
for x in data2:
    y = x.strip()
    if y: data3.append(y)
data4 = ''.join(data3)
data5 = data4.replace("  ","").replace("> <","><")

print data5

Output: <root><head></head><content></content></root>

【讨论】:

    【解决方案5】:

    如果“非叶子”节点中的空白是我们试图删除的,那么下面的函数将会执行它(如果指定则递归):

    from xml.dom import Node
    
    def stripNode(node, recurse=False):
        nodesToRemove = []
        nodeToBeStripped = False
    
        for childNode in node.childNodes:
            # list empty text nodes (to remove if any should be)
            if (childNode.nodeType == Node.TEXT_NODE and childNode.nodeValue.strip() == ""):
                nodesToRemove.append(childNode)
    
            # only remove empty text nodes if not a leaf node (i.e. a child element exists)
            if childNode.nodeType == Node.ELEMENT_NODE:
                nodeToBeStripped = True
    
        # remove flagged text nodes
        if nodeToBeStripped:
            for childNode in nodesToRemove:
                node.removeChild(childNode)
    
        # recurse if specified
        if recurse:
            for childNode in node.childNodes:
                stripNode(childNode, True)
    

    但是,Thanatos 是正确的。空格可以表示 XML 中的数据,因此请谨慎使用。

    【讨论】:

      【解决方案6】:

      这是我很快想到的,因为我不想使用 lxml:

      from xml.dom import minidom
      from xml.dom.minidom import Node
      
      def remove_blanks(node):
          for x in node.childNodes:
              if x.nodeType == Node.TEXT_NODE:
                  if x.nodeValue:
                      x.nodeValue = x.nodeValue.strip()
              elif x.nodeType == Node.ELEMENT_NODE:
                  remove_blanks(x)
      
      xml = minidom.parse('file.xml')
      remove_blanks(xml)
      xml.normalize()
      with file('file.xml', 'w') as result:
          result.write(xml.toprettyxml(indent = '  '))
      

      我真的只需要重新缩进 XML 文件,否则缩进会损坏。它不尊重preserve 指令,但是,老实说,许多其他处理 XML 的软件也是如此,这是一个相当有趣的要求 :) 此外,您可以轻松地将这种功能添加到代码中上面(只检查space 属性,如果它的值为'preserve',则不要recur。)

      【讨论】:

      • 谢谢 - 我不想将 lxml 添加到我的项目中,这非常适合我的需求。
      • 太棒了。谢谢老兄。
      • 太棒了!这真的很有帮助
      【解决方案7】:
      xmlStr = xmlDocument.toprettyxml(indent='\t', newl='\n', encoding='UTF-8')
      fix = re.compile(r'((?<=>)(\n[\t]*)(?=[^<\t]))|(?<=[^>\t])(\n[\t]*)(?=<)')
      newXmlStr = re.sub(fix, '', xmlStr )
      

      来自this source

      【讨论】:

      • 什么是re?对我来说没有定义
      【解决方案8】:

      xml.dom.minidom 的 toprettyxml() 唯一困扰我的是它添加了空行。我似乎没有得到拆分组件,所以我只是写了一个简单的函数来删除空行:

      #!/usr/bin/env python
      
      import xml.dom.minidom
      
      # toprettyxml() without the blank lines
      def prettyPrint(x):
          for line in x.toprettyxml().split('\n'):
              if not line.strip() == '':
                  print line
      
      xml_string = "<monty>\n<example>something</example>\n<python>parrot</python>\n</monty>"
      
      # parse XML
      x = xml.dom.minidom.parseString(xml_string)
      
      # clean
      prettyPrint(x)
      

      这就是代码输出的内容:

      <?xml version="1.0" ?>
      <monty>
              <example>something</example>
              <python>parrot</python>
      </monty>
      

      如果我单独使用 toprettyxml(),即 print(toprettyxml(x)),它会添加不必要的空行:

      <?xml version="1.0" ?>
      <monty>
      
      
              <example>something</example>
      
      
              <python>parrot</python>
      
      
      </monty>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-09-21
        • 2017-11-20
        相关资源
        最近更新 更多