【问题标题】:Sorting XML file with XSLT or Python based on attribute of child element基于子元素的属性使用 XSLT 或 Python 对 XML 文件进行排序
【发布时间】:2017-11-14 09:01:29
【问题描述】:

我有一些结构如下的 XML 文件:

<titles>
  <title mode="example" name="name_example">
    <titleselect>
      <attribute_a>attrib_a</attribute_a>
      <attribute_b>attrib_b</attribute_b>
      <attribute_c>attrib_c</attribute_c>
      <sort_attribute>New York</sort_attribute>
    </titleselect>
  </title>
  <title mode="another_example" name="another_name">
    <titleselect>
      <attribute_a>attrib_a</attribute_a>
      <attribute_b>attrib_b</attribute_b>
      <attribute_c>attrib_c</attribute_c>
      <sort_attribute>Boston</sort_attribute>
    </titleselect>
  </title>
  <title mode="final_example" name="final_name">
    <titleselect>
      <attribute_a>attrib_a</attribute_a>
      <attribute_b>attrib_b</attribute_b>
      <attribute_c>attrib_c</attribute_c>
      <sort_attribute>Chicago</sort_attribute>
    </titleselect>
  </title>
</titles>

我正在尝试按“sort_attribute”的字母顺序对“标题”进行排序。我想要的输出是这样的:

<titles>
      <title mode="another_example" name="another_name">
        <titleselect>
          <attribute_a>attrib_a</attribute_a>
          <attribute_b>attrib_b</attribute_b>
          <attribute_c>attrib_c</attribute_c>
          <sort_attribute>Boston</sort_attribute>
        </titleselect>
      </title>
      <title mode="final_example" name="final_name">
        <titleselect>
          <attribute_a>attrib_a</attribute_a>
          <attribute_b>attrib_b</attribute_b>
          <attribute_c>attrib_c</attribute_c>
          <sort_attribute>Chicago</sort_attribute>
        </titleselect>
      </title>
      <title mode="example" name="name_example">
        <titleselect>
          <attribute_a>attrib_a</attribute_a>
          <attribute_b>attrib_b</attribute_b>
          <attribute_c>attrib_c</attribute_c>
          <sort_attribute>New York</sort_attribute>
        </titleselect>
      </title>
    </titles>

有没有办法实现这一点,最好使用 XSLT 或 Python? 我对 XSLT 的世界完全陌生,但我尝试过应用来自其他相关问题的一些解决方案,例如XSLT sort parent element based on child element attribute 无济于事。

【问题讨论】:

  • 是的,这很简单。您链接到的答案已经很好了,您尝试应用它的目的是什么?

标签: python xml xslt


【解决方案1】:

如果您仍然对 Python 解决方案感兴趣,可以使用ElementTree 来实现。

它是如何工作的:

  1. 获取所有title 节点
  2. 从根节点中删除每一个
  3. 根据sort_attribute标签对内存中的title节点进行排序
  4. 以正确的顺序将每个 title 节点添加回根元素


import xml.etree.ElementTree as ET


def get_sort_attribute_tag_value(node):
    return node.find('titleselect').find('sort_attribute').text

with open('test.xml') as f:
    xml_node = ET.fromstring(f.read())

title_nodes = xml_node.findall('title')

for title_node in title_nodes:
    xml_node.remove(title_node)

title_nodes.sort(key=get_sort_attribute_tag_value)

for title_node in title_nodes:
    xml_node.append(title_node)

print(ET.tostring(xml_node).decode())

# in order to save as a new file
with open('new_file.xml', 'w') as f:
    f.write(ET.tostring(xml_node).decode())

输出:

<titles>
    <title mode="another_example" name="another_name">
        <titleselect>
            <attribute_a>attrib_a</attribute_a>
            <attribute_b>attrib_b</attribute_b>
            <attribute_c>attrib_c</attribute_c>
            <sort_attribute>Boston</sort_attribute>
        </titleselect>
    </title>
    <title mode="final_example" name="final_name">
        <titleselect>
            <attribute_a>attrib_a</attribute_a>
            <attribute_b>attrib_b</attribute_b>
            <attribute_c>attrib_c</attribute_c>
            <sort_attribute>Chicago</sort_attribute>
        </titleselect>
    </title>
    <title mode="example" name="name_example">
        <titleselect>
            <attribute_a>attrib_a</attribute_a>
            <attribute_b>attrib_b</attribute_b>
            <attribute_c>attrib_c</attribute_c>
            <sort_attribute>New York</sort_attribute>
        </titleselect>
    </title>
</titles>

【讨论】:

  • 是否可以将结果写入新的 XML 文件?
【解决方案2】:

作为 XSLT 替代方案,根据 Tomalek 的评论,使用模板捕获父 titles,然后按所需的 sort_attribute(实际上是一个元素)排序并复制内部 title 内容,这非常简单:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

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

  <xsl:template match="titles">
    <xsl:copy>
      <xsl:apply-templates select="title">
        <xsl:sort select="titleselect/sort_attribute" data-type="text" order="ascending"/>
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

【讨论】:

  • 非常感谢,这完全解决了我的问题!我认为 match 属性阻止了我之前的尝试成功。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-03-02
  • 2010-10-09
  • 2019-06-10
  • 2019-05-08
  • 2021-08-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多