4

我正试图围绕 xslt。关于stackoverflow帮助的一些问题( XSLT模板和递归 以及 XSLT for-each循环,基于变量的过滤器 )但我仍然有点困惑。我想我“将模板视为函数”(https://stackoverflow.com/questions/506348/how-do-i-know-my-xsl-is-efficient-and-beautiful

无论如何...我的数据是

<Entities>
    <Entity ID="8" SortValue="0" Name="test" ParentID="0" />
    <Entity ID="14" SortValue="2" Name="test2" ParentID="8" />
    <Entity ID="16" SortValue="1" Name="test3" ParentID="8" />
    <Entity ID="17" SortValue="3" Name="test4" ParentID="14" />
    <Entity ID="18" SortValue="3" Name="test5" ParentID="0" />
</Entities>

我想要的输出基本上是“树视图”

<ul>
    <li id="entity8">
        test
        <ul>
            <li id="entity16">
                test3
            </li>
            <li id="entity14">
                test2
                <ul>
                    <li id="entity17">
                        test4
                    </li>
                </ul>
            </li>
        </ul>
    </li>
    <li id="entity18">
        test5
    </li>
</ul>

到目前为止,我所拥有的 XSLT 是错误的,因为它肯定“将模板视为函数”,并且在执行时还会抛出 StackOverflowException (:-))

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
    <xsl:output method="html" indent="yes"/>

    <xsl:template match="Entities">
        <ul>
            <li>
                <xsl:value-of select="local-name()"/>
                <xsl:apply-templates/>
            </li>
        </ul>
    </xsl:template>

    <xsl:template match="//Entities/Entity[@ParentID=0]">
        <xsl:call-template name="recursive">
            <xsl:with-param name="parentEntityID" select="0"></xsl:with-param>
        </xsl:call-template>
     </xsl:template>

    <xsl:template name="recursive">
        <xsl:param name="parentEntityID"></xsl:param>
        <xsl:variable name="counter" select="//Entities/Entity[@ParentID=$parentEntityID]"></xsl:variable>

        <xsl:if test="count($counter) > 0">
            <xsl:if test="$parentEntityID > 0">
            </xsl:if>
                <li>
                    <xsl:variable name="entityID" select="@ID"></xsl:variable>
                    <xsl:variable name="sortValue" select="@SortValue"></xsl:variable>
                    <xsl:variable name="name" select="@Name"></xsl:variable>
                    <xsl:variable name="parentID" select="@ParentID"></xsl:variable>                    

                    <a href=?ID={$entityID}&amp;ParentEntityID={$parentID}">
                        <xsl:value-of select="$name"/>
                    </a>

                    <xsl:call-template name="recursive">
                        <xsl:with-param name="parentEntityID" select="$entityID"></xsl:with-param>
                    </xsl:call-template>

                </li>           
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

我知道如何通过代码做到这一点,没问题。不过,这一次,我正在寻找 xslt 中的解决方案,对此我将不胜感激。

4

2 回答 2

6

尽管call-template命名模板是该语言的一个非常有用的功能,但如果您发现自己更喜欢它们,apply-templates这可能表明您仍在考虑函数而不是模板。如果您在命名模板中做的第一件事是选择要操作的节点集,则尤其如此。

这是您尝试执行的操作的简单版本。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
    <xsl:template match="/">
        <ul>
           <xsl:apply-templates select="Entities/Entity[@ParentID=0]" />
        </ul>
    </xsl:template>

    <xsl:template match="Entity">
        <li>
           <xsl:value-of select="@Name" />
           <xsl:apply-templates select="../Entity[@ParentID=current()/@ID]" />
        </li>
    </xsl:template>
</xsl:stylesheet>

请注意,不需要计数器,因为“父”的值提供了必要的上下文。

另请注意Entities,无论它们在树中的哪个位置,它们都以相同的方式运行,它们包含它们的@Name值,并将模板应用于Entity@ParentID 与当前级别的@ID 匹配的任何对象。

于 2012-11-30T12:16:38.617 回答
1

正确有效的解决方案(当前接受的答案不会产生想要的嵌套ul元素:

<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="kChildren" match="Entity" use="@ParentID"/>

 <xsl:template match="/*[Entity]">
     <ul>
       <xsl:apply-templates select="key('kChildren', '0')">
            <xsl:sort select="@SortValue" data-type="number"/>
       </xsl:apply-templates>
     </ul>
 </xsl:template>

 <xsl:template match="Entity">
   <li id="entity{@ID}">
      <xsl:value-of select="concat('&#xA;               ', @Name, '&#xA;')"/>
      <xsl:if test="key('kChildren', @ID)">
          <ul>
            <xsl:apply-templates select="key('kChildren', @ID)">
              <xsl:sort select="@SortValue" data-type="number"/>
            </xsl:apply-templates>
          </ul>
      </xsl:if>
   </li>
 </xsl:template>
</xsl:stylesheet>

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

<Entities>
    <Entity ID="8" SortValue="0" Name="test" ParentID="0" />
    <Entity ID="14" SortValue="2" Name="test2" ParentID="8" />
    <Entity ID="16" SortValue="1" Name="test3" ParentID="8" />
    <Entity ID="17" SortValue="3" Name="test4" ParentID="14" />
    <Entity ID="18" SortValue="3" Name="test5" ParentID="0" />
</Entities>

产生了想要的正确结果:

<ul>
   <li id="entity8">
               test
<ul>
         <li id="entity16">
               test3
</li>
         <li id="entity14">
               test2
<ul>
               <li id="entity17">
               test4
</li>
            </ul>
         </li>
      </ul>
   </li>
   <li id="entity18">
               test5
</li>
</ul>
于 2012-11-30T13:57:57.733 回答