xsl用于订购xml的子节点

时间:2011-10-02 18:13:25

标签: xml xslt sorting

以下是示例xml

<Data version="2.0">
   <Group>
        <Item>3</Item>
        <Item>1</Item>
        <Item>2</Item>
   </Group>
   <Group>
        <Item>7</Item>
        <Item>5</Item>
   </Group>
</Data>

为了按Group by Item值排序节点,我尝试使用以下xsl:

  <xsl:template match="/Data">

    <xsl:apply-templates select="Group">
      <xsl:sort select="Item" />
    </xsl:apply-templates>

  </xsl:template>

但是只获取值,即使没有排序:

    3
    1
    2

    7
    5

所以问题是:1。为什么排序不起作用2.如何保留所有节点并保持xml的结构?

2 个答案:

答案 0 :(得分:4)

这就是你想要的:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Group">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates select="Item">
                <xsl:sort select="text()" />
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>    
</xsl:stylesheet>

第一个模板是“身份模板”(Google it),它将输入复制到输出不变。然后,对于Group节点,我们将其复制到输出(<xsl:copy>),复制其属性,然后在对它们进行排序后复制嵌套的Item节点。它们被复制,因为内部<xsl:apply-templates select="Item">最终使用Identity模板,因为Item节点没有更具体的模板。

请注意,如果Group个节点可以包含Item个节点以外的其他内容,则必须确保它也被复制。上面的模板会丢弃它们。

答案 1 :(得分:2)

@ Jim的答案基本上是正确的。

但是,应用于稍微更现实的XML文档,例如

<Data version="2.0">
   <Group>
        <Item>3</Item>
        <Item>1</Item>
        <Item>10</Item>
        <Item>2</Item>
   </Group>
   <Group>
        <Item>7</Item>
        <Item>5</Item>
   </Group>
</Data>

产生的结果显然你想要什么(10在2和3之前出现):

<?xml version="1.0" encoding="utf-8"?>
<Data version="2.0">

   <Group>
      <Item>1</Item>
      <Item>10</Item>
      <Item>2</Item>
      <Item>3</Item>
   </Group>

   <Group>
      <Item>5</Item>
      <Item>7</Item>
   </Group>

</Data>

这是一个正确的解决方案(也略短):

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

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

 <xsl:template match="Group">
  <Group>
   <xsl:apply-templates select="*">
    <xsl:sort data-type="number"/>
   </xsl:apply-templates>
  </Group>
 </xsl:template>
</xsl:stylesheet>

将此转换应用于同一XML文档(上图)时,会生成所需的正确结果

<Data version="2.0">
   <Group>
      <Item>1</Item>
      <Item>2</Item>
      <Item>3</Item>
      <Item>10</Item>
   </Group>
   <Group>
      <Item>5</Item>
      <Item>7</Item>
   </Group>
</Data>

说明:使用 <xsl:sort> data-type属性指定排序键值应视为数字,而不是(默认的)字符串。