用python捣碎xml

Ser*_*nko 5 python xml

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

<node1>
    <node2>
        <node3>foo</node3>
    </node2>
</node1>
Run Code Online (Sandbox Code Playgroud)

我希望将最终结果压缩成单行:

<node1><node2><node3>foo</node3></node2></node1>
Run Code Online (Sandbox Code Playgroud)

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

到目前为止,我有几个想法:(1)将xml解析为文本并查找标记的开始和结束<和>(2)另一种方法是加载xml文档并逐个节点地打印出一个新的通过连接标签来记录文档.

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

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

Van*_*ale 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)
Run Code Online (Sandbox Code Playgroud)

结果是:

<node1><node2><node3>foo  </node3></node2></node1>
Run Code Online (Sandbox Code Playgroud)

编辑: Triptych的回答提醒我有关CDATA的要求,因此创建解析器对象的行应该看起来像这样:

parser = etree.XMLParser(remove_blank_text=True, strip_cdata=False)
Run Code Online (Sandbox Code Playgroud)


Joh*_*iss 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>
Run Code Online (Sandbox Code Playgroud)

这应该够了吧.

在python中你可以使用lxml(直接链接到主页上的示例)来转换它.

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

xsltproc test.xsl  test.xml
Run Code Online (Sandbox Code Playgroud)

test.xsl上面的文件和test.xmlXML文件在哪里.


Tri*_*ych 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
Run Code Online (Sandbox Code Playgroud)