【问题标题】:Python how to strip white-spaces from xml text nodesPython如何从xml文本节点中去除空格
【发布时间】:2013-10-17 18:46:40
【问题描述】:

我有一个xml文件如下

<Person>
<name>

 My Name

</name>
<Address>My Address</Address>
</Person>

标签有额外的新行,是否有任何快速的 Pythonic 方法来修剪它并生成新的 xml。

我找到了这个,但它只修剪标签之间而不是值 https://skyl.org/log/post/skyl/2010/04/remove-insignificant-whitespace-from-xml-string-with-python/

更新 1 - 处理在 &lt;name&gt; 标记中有尾部空格的以下 xml

<Person>
<name>

 My Name<shortname>My</short>

</name>
<Address>My Address</Address>
</Person>

两种xml都接受的答案句柄

更新 2 - 我在下面的答案中发布了我的版本,我正在使用它来删除所有类型的空格并在带有 xml 编码的文件中生成漂亮的 xml

https://stackoverflow.com/a/19396130/973699

【问题讨论】:

  • 使用 JSON 可能会更成功
  • @Temere 这正被其他应用程序使用,在我的 python 程序进行验证之前
  • 您的附加示例(已接受的答案不起作用)格式不正确。注意开始和结束标签。顺便说一句,你正在“移动球门柱”。我认为你应该问一个新问题。
  • @mzjn 是的,我本可以提出不同的问题,但我认为这是相关的,因此如果此线程本身存在最佳解决方案,那就太好了。我已经在回答 stackoverflow.com/a/19396130/973699 中发布了我的版本
  • @mzjn 我刚读到这个,下次我会注意的。 meta.stackexchange.com/questions/153360/…

标签: python xml python-2.7 xml-parsing lxml


【解决方案1】:

我正在使用旧版本的 Python (2.3),但目前我仍坚持使用标准库。为了显示一个非常向后兼容的答案,我用xml.domxml.minidom 函数编写了这个。

import codecs
from xml.dom import minidom

# Read in the file to a DOM data structure.
original_document = minidom.parse("original_document.xml")

# Open a UTF-8 encoded file, because it's fairly standard for XML.
stripped_file = codecs.open("stripped_document.xml", "w", encoding="utf8")

# Tell minidom to format the child text nodes without any extra whitespace.
original_document.writexml(stripped_file, indent="", addindent="", newl="")

stripped_file.close()

虽然不是BeautifulSoup,但这个解决方案非常优雅,并且充分利用了底层 API。请注意,实际的格式只有一行:)

此处使用的 API 调用文档:

【讨论】:

    【解决方案2】:

    Birei 使用 lxml 给出的已接受答案完美地完成了这项工作,但我想修剪所有类型的空白/空格、空白行并在 xml 文件中重新生成漂亮的 xml。

    下面的代码做了我想做的事

    from lxml import etree
    
    #discard strings which are entirely white spaces
    myparser = etree.XMLParser(remove_blank_text=True)
    
    root = etree.parse('xmlfile',myparser)
    
    #from Birei's answer 
    for elem in root.iter('*'):
        if elem.text is not None:
            elem.text = elem.text.strip()
        if elem.tail is not None:
            elem.tail = elem.tail.strip()
    
    #write the xml file with pretty print and xml encoding
    root.write('xmlfile', pretty_print=True, encoding="utf-8", xml_declaration=True)
    

    【讨论】:

      【解决方案3】:

      使用lxml,您可以遍历所有元素并检查它是否有文本到strip()

      from lxml import etree
      
      tree = etree.parse('xmlfile')
      root = tree.getroot()
      
      for elem in root.iter('*'):
          if elem.text is not None:
              elem.text = elem.text.strip()
      
      print(etree.tostring(root))
      

      它产生:

      <Person><name>My Name</name>
      <Address>My Address</Address>
      </Person>
      

      UPDATE 也删除 tail 文本:

      from lxml import etree
      
      tree = etree.parse('xmlfile')
      root = tree.getroot()
      
      for elem in root.iter('*'):
          if elem.text is not None:
              elem.text = elem.text.strip()
          if elem.tail is not None:
              elem.tail = elem.tail.strip()
      
      print(etree.tostring(root, encoding="utf-8", xml_declaration=True))
      

      【讨论】:

      • 完美,唯一的问题是它没有像 那样保留 xml 版本标签
      • @DevC:您的数据不包括它。打印时可以添加:print(etree.tostring(root, encoding="utf-8", xml_declaration=True))
      • 不,我正在尝试的实际 xml 文件有这个,但最终结果没有显示这个。我不想硬编码它,因为它可能会改变。
      • 我让你的回答被接受,但它在上述更新条件下不起作用
      • @DevC:这种两边都被文本包围的元素的混合内容,可以使用tail 属性提取,该属性也可以被剥离。我已经更新了答案以适应您的新情况。
      【解决方案4】:

      您可以使用。遍历所有元素,并为每个包含一些文本的元素,将其替换为其剥离版本:

      from bs4 import BeautifulSoup
      
      soup = BeautifulSoup(open('xmlfile', 'r'), 'xml')
      
      for elem in soup.find_all():
          if elem.string is not None:
              elem.string = elem.string.strip()
      
      print(soup)
      

      假设xmlfile 包含问题中提供的内容,则得出:

      <?xml version="1.0" encoding="utf-8"?>
      <Person>
      <name>My Name</name>
      <Address>My Address</Address>
      </Person>
      

      【讨论】:

      • 我假设BeautifulSoup会抽象xml的一些细节,所以他最好直接处理lxml或其他解析器以获得通用解决方案,除非他的xml受到控制。
      • @Birei 是的,正如巴塞尔所提到的,我正在寻找使用像 lxml/etree 或 minidom 这样的 xml 解析器来完成它
      【解决方案5】:

      您必须以这种或另一种方式进行 xml 解析,因此可能使用xml.sax 并在每个事件处复制到输出流(跳过ignorableWhitespace),并根据需要添加标记标记。在这里查看示例代码http://www.knowthytools.com/2010/03/sax-parsing-with-python.html

      【讨论】:

      • 如果你展示一个例子,那真的很有帮助。下班时无法访问该链接,这是此处唯一与 2.3 兼容的标准库答案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-08-20
      • 2017-11-03
      • 2010-11-02
      • 2021-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多