首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >HTML列表- XSLT多个嵌套For Each循环

HTML列表- XSLT多个嵌套For Each循环
EN

Stack Overflow用户
提问于 2012-02-03 05:00:38
回答 3查看 10.8K关注 0票数 3

我正在尝试从xml/xsl生成一个多层嵌套的html列表。

例如,首选的html输出为:

代码语言:javascript
复制
<ul>
 <li>Level 1 - Item 1</li>
    <ul>
        <li>Level 2 - Item 1-1</li>
        <li>Level 2 - Item 1-2</li>
    </ul>

<li> Level 1 - Item 2</li>
    <ul>
        <li>Level 2 - Item 2-1
            <ul>
                <li>Level 3 - Item 2-1-1</li>
                <li>Level 3 - Item 2-1-2</li>
                <li>Level 3 - Item 2-1-3</li>
            </ul>
        </li>
        <li>Level 2 - Item 2-2
            <ul>
                <li>Level 3 - Item 2-2-1</li>
                <li>Level 3 - Item 2-2-2</li>
            </ul>
        </li>
</ul>

XML:

代码语言:javascript
复制
<doc>

    <item>
        <one>Level 1 - Item 1</one>
            <two>Level 2 - Item 1-1</two>
            <two>Level 2 - Item 1-2</two>
    </item>

    <item>
        <one>Level 2 - Item 2</one>
            <two>Level 2 - Item 2-1</two>
                <three>Level 3 - Item 2-1-1</three>
                <three>Level 3 - Item 2-1-2</three>
                <three>Level 3 - Item 2-1-3</three>
            <two>Level 2 - Item 2-2</two>
                <three>Level 3 - Item 2-2-1</three>
                <three>Level 3 - Item 2-2-2</three> 
    </item>

</doc>

我糟糕的XSL尝试:

代码语言:javascript
复制
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
    <html>
    <body>
    <xsl:for-each select="doc/item">
    <li><xsl:value-of select="one" />
    <ul>
    <xsl:for-each select="two">
    <li><xsl:value-of select="."/>
    <xsl:for-each select="../three"><ul><li><xsl:value-of select="."/></li></ul></xsl:for-each>
    </li>
    </xsl:for-each>
    </ul>
    </li>
    </xsl:for-each>
    </body>
    </html>
    </xsl:template>
    </xsl:stylesheet>

这是我在下面得到的..。请注意,当有一个3级项目时,所有项目都已合并,然后显示在两者之下。

代码语言:javascript
复制
    <li>Level 1 - Item 1<ul>
    <li>Level 2 - Item 1-1</li>
    <li>Level 2 - Item 1-2</li>
    </ul>
    </li>
    <li>Level 2 - Item 2<ul>
    <li>Level 2 - Item 2-1<ul>
    <li>Level 3 - Item 2-1-1</li>
    </ul>

    <ul>
    <li>Level 3 - Item 2-1-2</li>
    </ul>
    <ul>
    <li>Level 3 - Item 2-1-3</li>
    </ul>
    <ul>
    <li>Level 3 - Item 2-2-1</li>
    </ul>
    <ul>
    <li>Level 3 - Item 2-2-2</li>
    </ul>
    </li>

    <li>Level 2 - Item 2-2<ul>
    <li>Level 3 - Item 2-1-1</li>
    </ul>
    <ul>
    <li>Level 3 - Item 2-1-2</li>
    </ul>
    <ul>
    <li>Level 3 - Item 2-1-3</li>
    </ul>
    <ul>
    <li>Level 3 - Item 2-2-1</li>
    </ul>

    <ul>
    <li>Level 3 - Item 2-2-2</li>
    </ul>
    </li>
    </ul>
    </li>

请为我提供1.0的解决方案,然后当然显示2.0的例子,以帮助他人以及。

谢谢!

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-02-03 08:23:08

下面是一个处理输入XML的XSLT 1.0解决方案。

代码语言:javascript
复制
<xsl:stylesheet 
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:my="http://tempuri.org"
  exclude-result-prefixes="my"
>
  <xsl:output indent="yes" />

  <!-- define which elements are where in the hierarchy -->
  <my:level name="one"   higher="" deeper="two,three" />
  <my:level name="two"   higher="one" deeper="three"  />
  <my:level name="three" higher="one,two" deeper="" />

  <xsl:template match="doc">
    <body>
      <xsl:apply-templates mode="ul" select="item/*[1]" />
    </body>
  </xsl:template>

  <xsl:template match="one|two|three" mode="ul">
    <ul>
      <xsl:apply-templates mode="li" select="." />
    </ul>
  </xsl:template>

  <xsl:template match="one|two|three" mode="li">
    <xsl:variable name="myName" select="name()" />
    <xsl:variable name="myID"   select="generate-id()" />
    <!-- select the appropriate hierarchy info for this node -->
    <xsl:variable name="level"  select="
      document('')/*/my:level[@name = $myName]
    " />
    <li>
      <xsl:value-of select="." />
      <!-- create <ul> if immediately follwing sibling is deeper -->
      <xsl:apply-templates mode="ul" select="
        following-sibling::*[1][contains($level/@deeper, name())]
      " />
    </li>
    <!-- process contiguous following siblings of same level -->
    <xsl:apply-templates mode="li" select="
      following-sibling::*[name() = $myName][
        generate-id(
          preceding-sibling::*[contains($level/@higher, name())][1]/following-sibling::*[1]
        ) 
        = $myID
      ]
    " />
  </xsl:template>

</xsl:stylesheet>

给定问题中的输入文档,它将生成以下输出:

代码语言:javascript
复制
<body>
  <ul>
    <li>Level 1 - Item 1
      <ul>
        <li>Level 2 - Item 1-1</li>
        <li>Level 2 - Item 1-2</li>
      </ul>
    </li>
  </ul>
  <ul>
    <li>Level 2 - Item 2
      <ul>
        <li>Level 2 - Item 2-1
          <ul>
            <li>Level 3 - Item 2-1-1</li>
            <li>Level 3 - Item 2-1-2</li>
            <li>Level 3 - Item 2-1-3</li>
          </ul>
        </li>
        <li>Level 2 - Item 2-2
          <ul>
            <li>Level 3 - Item 2-2-1</li>
            <li>Level 3 - Item 2-2-2</li>
          </ul>
        </li>
      </ul>
    </li>
  </ul>
</body>

坦率地说,我现在太累了,无法详细解释解决方案。不过,我还是留下了一些评论。可以说,这是相当复杂的。

如果您的XML看起来像这样(即正确嵌套):

代码语言:javascript
复制
<doc>
  <item title="Level 1 - Item 1">
    <item title="Level 2 - Item 1-1" />
    <item title="Level 2 - Item 1-2" />
  </item>
  <item title="Level 2 - Item 2">
    <item title="Level 2 - Item 2-1">
      <item title="Level 3 - Item 2-1-1" />
      <item title="Level 3 - Item 2-1-2" />
      <item title="Level 3 - Item 2-1-3" />
    </item>
    <item title="Level 2 - Item 2-2">
      <item title="Level 3 - Item 2-2-1" />
      <item title="Level 3 - Item 2-2-2" />
    </item>
  </item>
</doc>

将产生与上面相同的HTML结果的解决方案将如下所示:

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

  <xsl:template match="doc">
    <body>
      <xsl:for-each select="item">
        <ul>
          <xsl:apply-templates select="." />
        </ul>
      </xsl:for-each>
    </body>
  </xsl:template>

  <xsl:template match="item">
    <li>
      <xsl:value-of select="@title" />
      <xsl:if test="item">
        <ul>
          <xsl:apply-templates select="item" />
        </ul>
      </xsl:if>
    </li>
  </xsl:template>
</xsl:stylesheet>
票数 4
EN

Stack Overflow用户

发布于 2012-02-03 08:41:24

试试下面的方法。说明:选择前面有相同的前两个同级的所有“三个”同级。我在XML中运行了这段代码,并获得了所需的输出(参见下面的xslt)。

代码语言:javascript
复制
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
    <xsl:template match="/">
        <html>
            <body>
                <xsl:for-each select="doc/item">
                    <li>
                        <xsl:value-of select="one" />
                        <ul>
                            <xsl:for-each select="two">
                                <li>
                                    <xsl:value-of select="."/>
                                    <ul>
                                        <xsl:for-each select="following-sibling::three[preceding-sibling::two[1]=current()]">
                                                <li>
                                                    <xsl:value-of select="."/>
                                                </li>
                                        </xsl:for-each>
                                    </ul>
                                </li>
                            </xsl:for-each>
                        </ul>
                    </li>
                </xsl:for-each>
            </body>
        </html>
    </xsl:template>
    </xsl:stylesheet>

输出:

代码语言:javascript
复制
<html>
    <body>
        <li>Level 1 - Item 1
            <ul>
                <li>Level 2 - Item 1-1
                    <ul></ul>
                </li>
                <li>Level 2 - Item 1-2
                    <ul></ul>
                </li>
            </ul>
        </li>
        <li>Level 2 - Item 2
            <ul>
                <li>Level 2 - Item 2-1
                    <ul>
                        <li>Level 3 - Item 2-1-1</li>
                        <li>Level 3 - Item 2-1-2</li>
                        <li>Level 3 - Item 2-1-3</li>
                    </ul>
                </li>
                <li>Level 2 - Item 2-2
                    <ul>
                        <li>Level 3 - Item 2-2-1</li>
                        <li>Level 3 - Item 2-2-2</li>
                    </ul>
                </li>
            </ul>
        </li>
    </body>
</html>
票数 4
EN

Stack Overflow用户

发布于 2012-02-03 11:17:38

这个转换很简单(没有内联XML,没有document() document()函数),简短而高效的转换

代码语言:javascript
复制
<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:key name="kFollowing" match="two"
  use="generate-id(preceding-sibling::one[1])"/>

 <xsl:key name="kFollowing" match="three"
  use="generate-id(preceding-sibling::two[1])"/>

 <xsl:template match="/*">
  <ul>
    <xsl:apply-templates select="item/one" mode="inGroup"/>
  </ul>
 </xsl:template>

 <xsl:template match="one|two" mode="inGroup">
  <li><xsl:value-of select="concat(., '&#xA;')"/>
    <xsl:variable name="vGroup" select=
        "key('kFollowing', generate-id())"/>
    <xsl:apply-templates select=
       "$vGroup[1]">
     <xsl:with-param name="pGroup" select="$vGroup"/>
    </xsl:apply-templates>
  </li>
 </xsl:template>

 <xsl:template match="two|three">
  <xsl:param name="pGroup"/>

  <xsl:if test="position() = 1">
     <ul>
      <xsl:apply-templates select="$pGroup" mode="inGroup"/>
     </ul>
  </xsl:if>
 </xsl:template>

 <xsl:template match="three" mode="inGroup">
  <li><xsl:value-of select="."/></li>
 </xsl:template>
</xsl:stylesheet>

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

代码语言:javascript
复制
<doc>
    <item>
        <one>Level 1 - Item 1</one>
        <two>Level 2 - Item 1-1</two>
        <two>Level 2 - Item 1-2</two>
    </item>
    <item>
        <one>Level 2 - Item 2</one>
        <two>Level 2 - Item 2-1</two>
        <three>Level 3 - Item 2-1-1</three>
        <three>Level 3 - Item 2-1-2</three>
        <three>Level 3 - Item 2-1-3</three>
        <two>Level 2 - Item 2-2</two>
        <three>Level 3 - Item 2-2-1</three>
        <three>Level 3 - Item 2-2-2</three>
    </item>
</doc>

生成所需的、正确的结果

代码语言:javascript
复制
<ul>
    <li>Level 1 - Item 1
        <ul>
            <li>Level 2 - Item 1-1
            </li>
            <li>Level 2 - Item 1-2
            </li>
        </ul>
    </li>
    <li>Level 2 - Item 2
        <ul>
            <li>Level 2 - Item 2-1
                <ul>
                    <li>Level 3 - Item 2-1-1</li>
                    <li>Level 3 - Item 2-1-2</li>
                    <li>Level 3 - Item 2-1-3</li>
                </ul>
            </li>
            <li>Level 2 - Item 2-2
                <ul>
                    <li>Level 3 - Item 2-2-1</li>
                    <li>Level 3 - Item 2-2-2</li>
                </ul>
            </li>
        </ul>
    </li>
</ul>

,浏览器将其显示为

  • Level 1- Item 1
    • Level 2- Item 1-1
    • Level 2- Item 1-2

  • Level 2- Item 2
    • Level 2- Item 2-1
      • Level 3- Item 2-1-1
      • Level 3- Item 2-1-2
      • Level 3- Item 2-1-3

代码语言:javascript
复制
- Level 2 - Item 2-2                 
    - Level 3 - Item 2-2-1
    - Level 3 - Item 2-2-2

说明

  1. 只有一个键kFollowing (有两个独立的定义),它根据逻辑父元素(分别是onetwo)的generate-id()值对任何twothree元素进行索引。这有助于我们拥有一个同时匹配onetwo的模板elements.
  2. Every组中的第一个(twothree)元素被匹配并在no模式下处理。在此模板中,将生成包装ul,然后在名为inGroup.

的模式下处理组中的所有元素(作为参数传递

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

https://stackoverflow.com/questions/9119927

复制
相关文章

相似问题

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