XSLT:平面XML到嵌套HTML列表



我是XSLT的新手。我知道我需要为每个组使用xsl:for,但除了基本列表之外,我什么都想不出来。某种递归会更好地工作吗?任何XSLT1.0或2.0解决方案都可以。

下面是示例XML。请注意,将数据组织到树结构中最重要的属性是@taxonomy。其他属性@taxonomyName和@level作为可选的辅助属性提供。

<?xml version="1.0" encoding="utf-8"?>
<documents>
    <document level="0" title="Root document test" taxonomy="" taxonomyName="" />
    <document level="1" title="Level one document test" taxonomy="CategoryI" taxonomyName="CategoryI" />
    <document level="1" title="Level one document test #2" taxonomy="CategoryII" taxonomyName="CategoryII" />
    <document level="2" title="Level two document test" taxonomy="CategoryIISubcategoryA" taxonomyName="SubcategoryA" />
    <document level="2" title="Level two document test #2" taxonomy="CategoryIISubcategoryA" taxonomyName="SubcategoryA" />
    <document level="3" title="Level three document test" taxonomy="CategoryIISubcategoryAMicrocategory1" taxonomyName="Microcategory1" />
    <document level="2" title="Level two, no level one test" taxonomy="CategoryIIISubcategoryZ" taxonomyName="SubcategoryZ" />
</documents>

以下是预期输出。(请注意,在输出中不需要缩进。我在这里这样做是为了可读性。)

<ul>
    <li>Root document test</li>
    <li>CategoryI
        <ul>
            <li>Level one document test</li>
        </ul>
    </li>
    <li>CategoryII
        <ul>
            <li>Level one document test #2</li>
            <li>SubcategoryA
                <ul>
                    <li>Level two document test</li>
                    <li>Level two document test #2</li>
                    <li>Microcategory1
                        <ul>
                            <li>Level three document test</li>
                        </ul>
                    </li>
                </ul>
            </li>
        </ul>
    </li>
    <li>CategoryIII
        <ul>
            <li>SubcategoryZ
                <ul>
                    <li>Level two, no subcategory test</li>
                </ul>
            </li>
        </ul>
    </li>
</ul>

这是我能做的最好的。

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:key name="contacts-by-taxonomy" match="document" use="@taxonomy" />
    <xsl:template match="documents">
        <ul>
            <xsl:for-each-group select="document" group-by="@taxonomy">
                <xsl:sort select="@taxonomy" />
                <li>
                    <h3><xsl:value-of select="current-grouping-key()"/></h3>
                    <ul>
                        <xsl:for-each select="current-group()">
                            <li><xsl:value-of select="@title"/></li>
                        </xsl:for-each>
                    </ul>
                </li>
            </xsl:for-each-group>
        </ul>
    </xsl:template>
</xsl:stylesheet>

我会一直努力,但如果有人能给我一件救生衣,我将永远感激。谢谢

好吧,这终于是我的解决方案了。:-)基本上,它在树中递归,在每个级别,它通过="@taxonomy的下一个级别"为每个组执行一个。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
   <xsl:output method="html" indent="yes" />   
   <xsl:template match="documents">
      <ul>
         <xsl:call-template name="tree-depth-n">
            <xsl:with-param name="population" select="document"/>
            <xsl:with-param name="depth" select="0"/>
            <xsl:with-param name="taxonomy-so-far" select="''"/>
         </xsl:call-template>
      </ul>
   </xsl:template>
   <!-- This template is called with a population that are all descendants
      of the same ancestors up to level n. -->      
   <xsl:template name="tree-depth-n">
      <xsl:param name="depth" required="yes"/>
      <xsl:param name="population" required="yes"/>
      <xsl:param name="taxonomy-so-far" required="yes"/>
      <!-- output a <li> for each document that is a leaf at this level,
      and a <li> for each sub-taxon of this level. --> 
      <xsl:for-each-group select="$population"
                    group-by="string(tokenize(@taxonomy, '\')[$depth + 2])">
         <xsl:sort select="@taxonomy" />
         <xsl:choose>
            <!-- process documents at this level. -->
            <xsl:when test="current-grouping-key() = ''">
              <xsl:for-each select="current-group()">
                 <li><xsl:value-of select="@title"/></li>
              </xsl:for-each>
            </xsl:when>
            <!-- process subcategories -->
            <xsl:otherwise>
               <li>
                  <h3><xsl:value-of select="current-grouping-key()"/></h3>
                  <ul>
                     <!-- recurse -->
                     <xsl:call-template name="tree-depth-n">
                        <xsl:with-param name="population" select="current-group()"/>
                        <xsl:with-param name="depth" select="$depth + 1"/>
                        <xsl:with-param name="taxonomy-so-far" 
                          select="concat($taxonomy-so-far, '\', current-grouping-key())"/>
                     </xsl:call-template>                    
                  </ul>
              </li>
            </xsl:otherwise>
         </xsl:choose>
      </xsl:for-each-group>      
   </xsl:template>
</xsl:stylesheet>

对于给定的输入,输出为:

<ul>
   <li>Root document test</li>
   <li>
      <h3>CategoryI</h3>
      <ul>
         <li>Level one document test</li>
      </ul>
   </li>
   <li>
      <h3>CategoryII</h3>
      <ul>
         <li>Level one document test #2</li>
         <li>
            <h3>SubcategoryA</h3>
            <ul>
               <li>Level two document test</li>
               <li>Level two document test #2</li>
               <li>
                  <h3>Microcategory1</h3>
                  <ul>
                     <li>Level three document test</li>
                  </ul>
               </li>
            </ul>
         </li>
      </ul>
   </li>
   <li>
      <h3>CategoryIII</h3>
      <ul>
         <li>
            <h3>SubcategoryZ</h3>
            <ul>
               <li>Level two, no level one test</li>
            </ul>
         </li>
      </ul>
   </li>
</ul>

我相信这正是你想要的。(我把<h3>放在那里,就像您在XSL尝试中一样,用于类别名称,而不是文档标题。)

相关内容

  • 没有找到相关文章

最新更新