基于xml文本属性对xml文件进行排序

时间:2016-07-19 14:04:46

标签: python xml lxml

我有一个xml文件,其中元素以某种随机顺序存在。我必须比较这些文件,但由于元素顺序的变化,需要手动操作。

我正在寻找一些方法来对这些文件进行排序。有人可以给我一些指针/解决这个问题的方法。我尝试阅读lxml(ElementTree和Element类)的文档,但似乎没有一种方法可以根据xml文本对子元素进行排序。

我可以根据Name对元素进行排序,但在属性元素中,如何对legal元素子进行排序?

输入: -

<root>
    <attribute Name="attr2">
            <v>
              <cstat>
                <s>nObjDef2</s>
                <s>nObjDef1</s>
              </cstat>
            </v>
            <objects>
              <legal>
                <o>otype2</o>
                <o>otype1</o>
              </legal>
            </objects>
    </attribute>
    <attribute Name="attr1">
            <v>
              <cstat>
                <s>nObjDef2</s>
                <s>nObjDef1</s>
              </cstat>
            </v>
            <objects>
              <legal>
                <o>otype2</o>
                <o>otype1</o>
              </legal>
            </objects>
    </attribute>
</root>

预期产出:

<root>
    <attribute Name="attr1">
            <v>
              <cstat>
                <s>nObjDef1</s>
                <s>nObjDef2</s>
              </cstat>
            </v>
            <objects>
              <legal>
                <o>otype1</o>
                <o>otype2</o>
              </legal>
            </objects>
    </attribute>
    <attribute Name="attr2">
            <v>
              <cstat>
                <s>nObjDef1</s>
                <s>nObjDef2</s>
              </cstat>
            </v>
            <objects>
              <legal>
                <o>otype1</o>
                <o>otype2</o>
              </legal>
            </objects>
    </attribute>
</root> 

2 个答案:

答案 0 :(得分:0)

如果要按文本对子项进行排序,只需找到合法节点并使用 child.text 作为键对子项进行排序:

x = """<root>
    <attribute Name="attr2">
            <v>
              <cstat>
                <s>nObjDef2</s>
                <s>nObjDef1</s>
              </cstat>
            </v>
            <objects>
              <legal>
                <o>otype2</o>
                <o>otype1</o>
              </legal>
            </objects>
    </attribute>
    <attribute Name="attr1">
            <v>
              <cstat>
                <s>nObjDef2</s>
                <s>nObjDef1</s>
              </cstat>
            </v>
            <objects>
              <legal>
                <o>otype2</o>
                <o>otype1</o>
              </legal>
            </objects>
    </attribute>
</root>
"""

对每个节点进行排序:

from lxml import etree

xml = etree.fromstring(x)

for node in xml.xpath("//legal"):
    node[:] = sorted(node, key=lambda ch: ch.text)

这将重新排序孩子:

print(etree.tostring(xml, pretty_print=1).decode("utf-8"))

给你:

<root>
    <attribute Name="attr2">
            <v>
              <cstat>
                <s>nObjDef2</s>
                <s>nObjDef1</s>
              </cstat>
            </v>
            <objects>
              <legal>
                <o>otype1</o>
              <o>otype2</o>
                </legal>
            </objects>
    </attribute>
    <attribute Name="attr1">
            <v>
              <cstat>
                <s>nObjDef2</s>
                <s>nObjDef1</s>
              </cstat>
            </v>
            <objects>
              <legal>
                <o>otype1</o>
              <o>otype2</o>
                </legal>
            </objects>
    </attribute>
</root>

或者更有效的方法,使用operator.attrgetter代替lambda:

from lxml import etree
from operator import attrgetter
xml = etree.fromstring(x)

for node in xml.xpath("//legal"):
    node[:] = sorted(node, key=attrgetter("text"))

答案 1 :(得分:0)

考虑XSLT,这是专门用于操作和转换XML文件的专用语言。 Python的lxml可以运行XSLT 1.0脚本。具体来说,XSLT维护可以在模板中运行的<xsl:sort>方法:

enum Color { Red = 3 , Green = 5 }