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、ツリー内のどこにあるかに関係なく、すべてが同じように動作し、値が含まれており、@ParentID が現在のレベルの @ID と一致@Nameするすべてのオブジェクトにテンプレートを適用することに注意してください。Entity

于 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 に答える