用python捣碎xml

时间:2009-03-20 18:22:31

标签: python xml

我需要删除xml标记之间的空格,例如如果原始的xml看起来像:

<node1>
    <node2>
        <node3>foo</node3>
    </node2>
</node1>

我希望最终结果是 crunched 到单行:

<node1><node2><node3>foo</node3></node2></node1>

请注意,我无法控制xml结构,因此解决方案应该足够通用,以便能够处理任何有效的xml。此外,xml可能包含CDATA块,我需要从 crunching 中排除这些块并保持原样。

到目前为止,我有几个想法:(1)将xml解析为文本并查找标记的开头和结尾&lt;和&gt; (2)另一种方法是加载xml文档并逐个节点地输出并通过连接标记打印出 new 文档。

我认为任何一种方法都可行,但我宁愿不在这里重新发明轮子,所以可能有一个python库已经做了这样的事情?如果没有,那么在推出我自己的 cruncher 时需要注意的任何问题/陷阱?有什么建议吗?

修改的 谢谢大家的回答/建议,Triptych和Van Gale的解决方案都适合我,并且完全符合我的要求。希望我能接受这两个答案。

4 个答案:

答案 0 :(得分:8)

使用lxml很容易处理(注意:这个特殊功能不在ElementTree中):

from lxml import etree

parser = etree.XMLParser(remove_blank_text=True)

foo = """<node1>
    <node2>
        <node3>foo  </node3>
    </node2>
</node1>"""

bar = etree.XML(foo, parser)
print etree.tostring(bar,pretty_print=False,with_tail=True)

结果:

<node1><node2><node3>foo  </node3></node2></node1>

编辑: Triptych的回答提醒我有关CDATA的要求,因此创建解析器对象的行实际上应如下所示:

parser = etree.XMLParser(remove_blank_text=True, strip_cdata=False)

答案 1 :(得分:5)

我使用XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" encoding="UTF-8" omit-xml-declaration="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="*">
        <xsl:copy>
            <xsl:copy-of select="@*" />
            <xsl:apply-templates />
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

这应该可以解决问题。

在python中,您可以使用lxml (direct link to sample on homepage)对其进行转换。

对于某些测试,请使用xsltproc,示例:

xsltproc test.xsl  test.xml

其中test.xsl是上面的文件,test.xml是您的XML文件。

答案 2 :(得分:4)

使用BeautifulSoup非常简单。

此解决方案假设可以从字符数据的尾端删除空格 示例:<foo> bar </foo>变为<foo>bar</foo>

它会正确地忽略评论和CDATA。

import BeautifulSoup

s = """
<node1>
    <node2>
        <node3>foo</node3>
    </node2>
    <node3>
      <!-- I'm a comment! Leave me be! -->
    </node3>
    <node4>
    <![CDATA[
      I'm CDATA!  Changing me would be bad!
    ]]>
    </node4>
</node1>
"""

soup = BeautifulSoup.BeautifulStoneSoup(s)

for t in soup.findAll(text=True):
   if type(t) is BeautifulSoup.NavigableString: # Ignores comments and CDATA
      t.replaceWith(t.strip())

print soup

答案 3 :(得分:2)

不是解决方案,但是因为你提出了建议:我建议你不要自己解析(除非你想学习如何编写一个复杂的解析器)因为,正如你所说,并不是所有空格都应该删除。不仅有CDATA块,还有带有“xml:space = preserve”属性的元素,它们对应于XHTML中的<pre>(封闭的空格实际上有意义),并编写了一个能够解析的解析器认识到这些元素,只留下白色空间是可能的,但却是令人不快的。

我会使用解析方法,即加载文档并逐个节点地打印出来。这样,您可以轻松识别哪些节点可以剥离空间,哪些节点不可以。 Python标准库中有一些模块,我从未使用过这些模块;-)对您有用...尝试xml.dom,或者我不确定您是否可以使用{{xml.parsers.expat执行此操作1}}。