按子元素的属性值对父元素进行排序

时间:2016-06-04 16:34:03

标签: xml xslt

我正在尝试找出一种(相对)有效的方法来排序XSLT中的元素,这样我就不必回到我的Java代码中并弄乱DOM了。

如果我有这样的文件:

   
<?xml-stylesheet type="text/xsl" href="test.xsl"?>
<Root>
  <Player name="Jane Doe">
    <Location distance="90"/>
    <Location distance="45"/>
  </Player>
  <Player name="John Doe">
    <Location distance="50"/>
    <Location distance="20"/>
  </Player>
</Root>

我的目标是按最近位置的距离对球员进行排序。换句话说,由于John Doe的位置在20英里范围内,他距离更近,他的节点需要在最近位置为45英里的Jane Doe之上进行分类。

这样的事情是否可能?如果没有,没有大事。在开始操作DOM之前,我只是想把它扔出去。

2 个答案:

答案 0 :(得分:2)

这是一个简短的XSLT 1.0转换

<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="/*">
    <xsl:copy>
      <xsl:apply-templates>
        <xsl:sort select="*/@distance[not(. > ../../*/@distance)]" data-type="number"/>
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

在提供的XML文档上应用此转换时

<Root>
    <Player name="Jane Doe">
        <Location distance="90"/>
        <Location distance="45"/>
    </Player>
    <Player name="John Doe">
        <Location distance="50"/>
        <Location distance="20"/>
    </Player>
</Root>

生成了正确排序的结果

<Root>
   <Player name="John Doe">
      <Location distance="50"/>
      <Location distance="20"/>
   </Player>
   <Player name="Jane Doe">
      <Location distance="90"/>
      <Location distance="45"/>
   </Player>
</Root>

答案 1 :(得分:0)

使用XSLT 2.0(和Saxon 9之类的XSLT 2.0处理器)可以使用

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">

    <xsl:output indent="yes"/>

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

    <xsl:template match="Root">
        <xsl:copy>
            <xsl:apply-templates select="Player">
                <xsl:sort select="min(Location/@distance)"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

这是一个XSLT 1.0解决方案,使用exsl:node-set处理在变量中创建的结果树片段,其中使用通常的XSLT 1.0排序方法识别最小距离并按排序顺序获取第一个项目: / p>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
    xmlns:exsl="http://exslt.org/common"
    exclude-result-prefixes="exsl">

    <xsl:output indent="yes"/>

    <xsl:variable name="players-rtf">
        <xsl:for-each select="Root/Player">
            <xsl:copy>
                <xsl:attribute name="min-dist">
                    <xsl:for-each select="Location/@distance">
                        <xsl:sort select="." data-type="number"/>
                        <xsl:if test="position() = 1">
                            <xsl:value-of select="."/>
                        </xsl:if>
                    </xsl:for-each>
                </xsl:attribute>
                <xsl:copy-of select="@* | *"/>
            </xsl:copy>
        </xsl:for-each>
    </xsl:variable>

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

    <xsl:template match="Root">
        <xsl:copy>
            <xsl:apply-templates select="exsl:node-set($players-rtf)/Player">
                <xsl:sort select="@min-dist" data-type="number"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Player/@min-dist"/>

</xsl:stylesheet>