Xml 按子元素的属性值排序父元素

Xml 按子元素的属性值排序父元素,xml,xslt,Xml,Xslt,我正试图找出一种(相对)有效的方法来对XSLT中的元素进行排序,这样我就不必回到Java代码中去处理DOM了 如果我有这样一个文件: <?xml-stylesheet type="text/xsl" href="test.xsl"?> <Root> <Player name="Jane Doe"> <Location distance="90"/> <Location distance="45"/> </P

我正试图找出一种(相对)有效的方法来对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英里以内,所以他离得更近,他的节点需要排序在Jane Doe的上方,Jane Doe最近的位置是45英里

这样的事情可能吗?如果没有,没什么大不了的。在开始DOM操作之前,我只想把这个问题抛到一边。

使用XSLT2.0(以及类似Saxon 9的XSLT2.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转换

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

当此转换应用于提供的XML文档时

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

生成所需的正确排序结果

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


我对尝试摸索有点恼火,为什么每个玩家元素中都有两个距离元素,如果这很重要,并且像排序顺序一样恒定,如果一个解决方案应该/能够考虑到这一点?在XSLT2.0中,这很容易,例如,
,因此假设您的DOM代码是Java DOM代码,您可以使用XSLT2.0和Saxon 9而不是DOM。XSLT 1.0当然也可以,但可能需要两个步骤,首先确定每个
播放器的最小距离,然后根据第一步的结果对它们进行排序。这是因为您查看的数据只是我在企业世界中使用的数据的演示。请放心,我使用的真实数据有多个“位置”(没有,不是节点)的原因。Martin Honnen-不幸的是,我们使用XSLT 1.0,因为我们正在处理一个旧的工作环境。我相信我们运行的是Java 6…即使Java 8也没有Oracle的XSLT 2.0,但只使用Saxonica的Saxon,我认为Saxon应该使用Java 6。Dimitre,非常感谢!在Kay之外,在阅读XSL文章时,您是我唯一信任的“权威”。你似乎对每个问题都有答案。