代码之家  ›  专栏  ›  技术社区  ›  Sergey Golovchenko

用python处理XML

  •  5
  • Sergey Golovchenko  · 技术社区  · 17 年前

    我需要删除XML标记之间的空白,例如,如果原始XML如下所示:

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

    我希望最终结果是 嘎吱作响的 到单线:

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

    请注意,我将无法控制XML结构,因此解决方案应该足够通用,能够处理任何有效的XML。另外,XML可能包含CDATA块,我需要从中排除这些块。 嘎吱嘎吱 让它们保持原样。

    到目前为止,我有两个想法:(1)将XML解析为文本,并查找标记的开始和结束位置<和>(2)另一种方法是加载XML文档并逐节点执行,然后打印出 新的 通过连接标记来记录。

    我认为这两种方法都可以,但我不想在这里重新设计方向盘,所以可能有一个Python库已经做了类似的事情?如果没有,那么在推出我自己的产品时需要注意的任何问题/陷阱 克朗彻 ?有什么建议吗?

    编辑 感谢大家的回答/建议,Triptych和van Gale的解决方案对我都有效,并且完全满足我的需要。希望我能接受这两个答案。

    4 回复  |  直到 17 年前
        1
  •  4
  •   Kenan Banks    17 年前

    很简单很漂亮的汤。

    此解决方案假定可以从字符数据的尾部去除空白。
    例子: <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
    
        2
  •  8
  •   Van Gale    17 年前

    这很容易用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)
    
        3
  •  5
  •   Johannes Weiss    17 年前

    我会使用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文件。

        4
  •  2
  •   David Z    17 年前

    不是一个真正的解决方案,但既然您要求提供建议:我建议您不要自己进行解析(除非您想学习如何编写复杂的解析器),因为正如您所说,并不是所有的空格都应该被删除。不仅有CDATA块,还有带有“xml:space=preserve”属性的元素,这些属性与 <pre> 在XHTML中(其中所包含的空白实际上有意义),编写一个能够识别这些元素并只保留空白的解析器是可能的,但不太愉快。

    我将使用解析方法,即加载文档并逐节点打印出来。这样,您就可以很容易地识别哪些节点可以去掉空间,哪些节点不能去掉空间。python标准库中有一些模块,我从未使用过这些模块;-)这些模块可能对您有用……尝试 xml.dom 或者我不确定你能不能 xml.parsers.expat .