首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >XSLT:排序路径跟踪

XSLT:排序路径跟踪
EN

Stack Overflow用户
提问于 2012-08-23 19:18:00
回答 2查看 169关注 0票数 2

我有以下输入:

代码语言:javascript
复制
<articles>
  <item name="B">
    <item name="Bb">
      <item name="Bbb"/>
      <item name="Abb"/>
    </item>
    <item name="Ab">
      <item name="Bab"/>
      <item name="Aab"/>
    </item>
  </item>
  <item name="A">
    <item name="Ba">
      <item name="Bba"/>
      <item name="Aba"/>
    </item>
    <item name="Aa">
      <item name="Baa"/>
      <item name="Aaa"/>
    </item>
  </item>
  <item name="D"/>
  <item name="C">
    <item name="Ac"/>
  </item>
</articles>

并需要以下输出:

代码语言:javascript
复制
A-Aa-Aaa
A-Aa-Baa
A-Ba-Aba
A-Ba-BBa
B-Ab-Aab
B-Ab-Bab
B-Bb-Abb
B-Bb-Bbb
C-Ac
D

也就是说,每条路径都应该明确,并在每个级别上进行排序。我有以下XSLT,它可以生成路径,但是除了第一层之外,我不知道如何排序。

代码语言:javascript
复制
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="text"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="articles">
    <xsl:apply-templates select="//item[not(item)]">
      <xsl:sort select="ancestor-or-self::item[parent::articles]/@name"/>
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="item">
    <xsl:for-each select="ancestor-or-self::item">
      <xsl:value-of select="@name"/>
      <xsl:choose>
        <xsl:when test="not(item)">
          <xsl:text>&#xA;</xsl:text>
        </xsl:when>
        <xsl:otherwise>-</xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

恐怕我目前的方法是一条死胡同。想法?

EN

回答 2

Stack Overflow用户

发布于 2012-08-23 20:02:37

注意到,XSLT2.0解决方案(第二部分)的要短得多,也更简单。

I.这里是一个简单的两遍解决方案

代码语言:javascript
复制
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="http://exslt.org/common">
 <xsl:output method="text"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="/">
  <xsl:variable name="vrtfPass1">
    <xsl:apply-templates/>
  </xsl:variable>

  <xsl:for-each select="ext:node-set($vrtfPass1)/*">
   <xsl:sort/>
   <xsl:value-of select="concat(., '&#xA;')"/>
  </xsl:for-each>
 </xsl:template>

 <xsl:template match="item[not(item)]">
     <x>
      <xsl:for-each select="ancestor-or-self::item">
       <xsl:if test="not(position() = 1)">-</xsl:if>
       <xsl:value-of select="@name"/>
      </xsl:for-each>
     </x>
 </xsl:template>
</xsl:stylesheet>

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

代码语言:javascript
复制
<articles>
  <item name="B">
    <item name="Bb">
      <item name="Bbb"/>
      <item name="Abb"/>
    </item>
    <item name="Ab">
      <item name="Bab"/>
      <item name="Aab"/>
    </item>
  </item>
  <item name="A">
    <item name="Ba">
      <item name="Bba"/>
      <item name="Aba"/>
    </item>
    <item name="Aa">
      <item name="Baa"/>
      <item name="Aaa"/>
    </item>
  </item>
  <item name="D"/>
  <item name="C">
    <item name="Ac"/>
  </item>
</articles>

生成所需的正确结果:

代码语言:javascript
复制
A-Aa-Aaa
A-Aa-Baa
A-Ba-Aba
A-Ba-Bba
B-Ab-Aab
B-Ab-Bab
B-Bb-Abb
B-Bb-Bbb
C-Ac
D

请注意:这是一个通用的解决方案,可以正确处理任何嵌套的item元素。

说明

我们执行两遍transformation.

  • The第一遍的结果是:B-Bb-Bbb-Bb-Abb B-Ab-Bab B-Ab-Aab A-Ba-Bba A-Ba-Bba A-Aa-Aa-Baa A-Aa-Aaa D C-Ac-Ac

  • 第一遍的处理使用只与叶item元素匹配的单个模板。对于每个叶item元素,其以短划线分隔的完整路径将作为名为x.

  • The second item的元素的内容简单地对第一次遍历的结果进行排序。

II. XSLT2.0解决方案

代码语言:javascript
复制
<xsl:stylesheet version="2.0"   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text"/>

 <xsl:template match="/">
     <xsl:for-each-group select="//item[not(item)]"
     group-by="string-join(ancestor-or-self::item/@name, '-')">
      <xsl:sort select="current-grouping-key()"/>
      <xsl:sequence select="current-grouping-key(), '&#xA;'"/>
     </xsl:for-each-group>
 </xsl:template>
</xsl:stylesheet>
票数 3
EN

Stack Overflow用户

发布于 2012-08-23 19:52:53

不是很漂亮,但下面的3个项目的深度是这样做的,并且每个额外的级别都需要额外的排序。我相信大师将能够更通用地做到这一点:)

代码语言:javascript
复制
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="text"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="/">
        <xsl:apply-templates/>
    </xsl:template>

    <xsl:template match="articles">
        <xsl:apply-templates select="//item[not(item)]">
            <xsl:sort select="ancestor-or-self::item[parent::articles]/@name"/>
            <xsl:sort select="ancestor-or-self::item[parent::item[parent::articles]]/@name"/>
            <xsl:sort select="ancestor-or-self::item[parent::item[parent::item[parent::articles]]]/@name"/>
        </xsl:apply-templates>
    </xsl:template>

    <xsl:template match="item">
        <xsl:for-each select="ancestor-or-self::item">
            <xsl:value-of select="@name"/>
            <xsl:choose>
                <xsl:when test="not(item)">
                    <xsl:text>&#xA;</xsl:text>
                </xsl:when>
                <xsl:otherwise>-</xsl:otherwise>
            </xsl:choose>
        </xsl:for-each>
    </xsl:template>

</xsl:stylesheet>
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12090372

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档