基于xml文本属性的xml文件排序

2024-10-04 11:22:00 发布

您现在位置:Python中文网/ 问答频道 /正文

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

我想找个方法把这些文件分类。有人能给我一些关于这个问题的建议/方法吗。我试图阅读lxml(ElementTree和Element类)的文档,但似乎没有一种方法可以根据xml文本对子元素进行排序。在

我可以根据名称对元素进行排序,但是在属性元素中,如何才能对合法元素childs进行排序?在

输入:-

<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>

预期产量:

^{pr2}$

Tags: 文件方法name元素objects排序顺序attribute
2条回答

如果要按文本对子节点进行排序,只需找到合法节点并使用对子节点进行排序子级.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>
"""

对每个节点进行排序:

^{pr2}$

这将重新排列子对象:

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"))

考虑一下XSLT,这是专门为操作和转换XML文件而设计的专用语言。Python的lxml可以运行xslt1.0脚本。具体来说,XSLT维护了可以在模板内运行的^{}方法:

import lxml.etree as et

# LOAD XML (FROM FILE) AND XSL (FROM STRING)
xml = et.parse('Input.xml')

xslstr = '''<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output version="1.0" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>

  <!  Identity Transform  >
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>  

  <!  Sort Children Text of Nodes  >
  <xsl:template match="cstat|legal">
    <xsl:copy>
      <xsl:apply-templates select="*">
        <xsl:sort select="." order="ascending" data-type="text"/>
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>

</xsl:transform>'''

xslt = et.fromstring(xslstr)

# TRANSFORM SOURCE TO NEW TREE
transform = et.XSLT(xslt)
newdom = transform(xml)
print(newdom)

# OUTPUT TO FILE
tree_out = et.tostring(newdom, encoding='UTF-8', pretty_print=True, xml_declaration=True)

xmlfile = open('Output.xml','wb')
xmlfile.write(tree_out)
xmlfile.close()

相关问题 更多 >