如何使用XSLT根据其依赖关系对某些XML元素进行排序?

时间:2011-09-26 09:44:35

标签: xslt sorting

我想对以下XML文件进行排序:

<root>
  <element name="a" depends="b,c" />
  <element name="b" depends="c" />
  <element name="c" />
</root>

结果如下:

<root>
  <element name="c" />
  <element name="b" depends="c" />
  <element name="a" depends="b,c" />
</root>

我的依赖关系可以使用树(无循环)建模。 depends =“b,c”表示取决于b和c。 我想通过使用XSLT来做到这一点的好方法。也许,你有什么想法吗? 谢谢!

1 个答案:

答案 0 :(得分:1)

此XSLT 2.0转换

<xsl:stylesheet version="2.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="/*">
     <root>
      <xsl:call-template name="directDependents"/>
     </root>
 </xsl:template>

 <xsl:template name="directDependents">
  <xsl:param name="pCore" as="element()*"/>

  <xsl:variable name="vNewDependents" select=
  "/*/element
       [not(. intersect $pCore)
      and
       not(tokenize(@depends, ',')[not(. = $pCore/@name)])
       ]
  "/>

  <xsl:if test="$vNewDependents">
   <xsl:sequence select="$vNewDependents"/>
   <xsl:call-template name="directDependents">
    <xsl:with-param name="pCore" select="$pCore | $vNewDependents"/>
   </xsl:call-template>
  </xsl:if>
 </xsl:template>
</xsl:stylesheet>

应用于(第二个)提供的XML文档

<root>
    <element name="a" depends="b" />
    <element name="b" depends="c" />
    <element name="c" />
</root>

生成想要的正确结果

<root>
   <element name="c"/>
   <element name="b" depends="c"/>
   <element name="a" depends="b"/>
</root>

更新:这是一个更“XSLT 2.0外观解决方案”(未经测试 - 将在我回家时纠正任何错误):

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

 <xsl:template match="/*">
     <root>
      <xsl:sequence select="my:directDependents(/..)"/>
     </root>
 </xsl:template>

 <xsl:function name="my:directDependents">
  <xsl:param name="pCore" as="element()*"/>

  <xsl:sequence select=
  "for $vNewDependents in
    /*/element
           [not(. intersect $pCore)
          and
           not(tokenize(@depends, ',')[not(. = $pCore/@name)])
           ]
    return
      if($vNewDependents)
        then
         (
          $vNewDependents,
          my:directDependents($pCore | $vNewDependents)
          )
        else ()
  "/>
 </xsl:function>
</xsl:stylesheet>