2

ノード構造からブレッドクラムトライアルを生成するテンプレートを作成するのが困難です。これまでは正しく機能していませんでした。アイテムのパスをどのように歩くべきかという私の考えにはいくつかの欠陥があります。

次のページ構造を検討してください。

<!-- ===== SITE PAGE STRUCTURE ===================================== -->
<index>
   <item section="home" id="index"></item>
   <item section="service" id="index">
      <item id="content-management-systems">
         <item id="p1-1"/>
         <item id="p1-2"/>
         <item id="p1-3"/>
      </item>
      <item id="online-stores"></item>
      <item id="search-engines-and-ir"></item>
      <item id="web-applications"></item>
   </item>

   <item section="solutions" id="index">
      <item id="document-clustering"></item>
   </item>
   <item section="company" id="index">
      <item section="company" id="about"></item>
      <item section="company" id="philosophy" ></item>
      ...
   </item>
...
</item>

このサイトインデックスは、階層内のxmlコンテンツページのサイト構造を表します(メニューと見なします)。これには、ホーム、会社、サービス、ソリューションなどのようにサイトセクションを表すセクションが含まれます。これらのセクションには、ページを含むサブセクション、または通常のコンテンツページを含めることができます。コンテンツページ(タイトル、テキストコンテンツなどのxmlコンテンツ)は、アイテムツリーの@id属性によって識別されます。@id属性は主に、htmlにレンダリングされるページ全体のコンテンツをフェッチするために使用されます。ブレッドクラムテンプレートは、アイテムノードの@id属性を使用して、ページのタイトルを取得します(ブレッドクラムトレイルに表示されます)。

ツリー内のターゲットセクション属性@sectionとターゲットページ属性@idをチェックして、ツリーをウォークする次のテンプレートを実装しようとしています。祖先の@section属性と@idを、その軸の各ノードの$ item_targetと比較して、ターゲットitem_targetが見つかるまで、軸を下に移動することを期待しています。

次に例を示します。属性*$item_section =service*とページID*target item_target = p1-1 *は、セクションブランチ " service "(深さ1)まで再帰的に「ウォーク」する必要があります。ターゲットページ@idがにあるかどうかを確認してください。このレベル。この場合は見つからないため、次のアイテムノードレベル(この場合はcontent-management-systemsであり、ターゲットアイテムページp1-1が見つかります)に対して(apply-templatesを介して)次の再帰呼び出しを行います。 、したがって、証跡プロセスは終了します。

結果は次のようになります。

ホーム>>サービス>>コンテンツ管理システム>>p1-1

しかし残念ながら、少なくともすべての場合において、正しく機能しているわけではありません。また、もっと簡単に解決できるかもしれません。トップ(レベル0)からターゲットページ(アイテムノード)までリーフとして歩く再帰テンプレートとして実装しようとしています。

    <!-- walk item path to generate a breadcrumb trail -->
    <xsl:template name="breadcrumb">
        <a>
            <xsl:attribute name="href">
                <xsl:text>/</xsl:text>
                <xsl:value-of select="$req-lg"/>
                <xsl:text>/home/index</xsl:text>
            </xsl:attribute>
            <xsl:value-of select="'Home'"/>
        </a>

        <xsl:apply-templates select="$content/site/index" mode="Item-Path">
            <xsl:with-param name="item_section" select="'service'"/>
            <xsl:with-param name="item_target" select="'search-engines-and-ir'"/>
            <xsl:with-param name="depth" select="0"/>
        </xsl:apply-templates>
    </xsl:template>

    <xsl:template match="item" mode="Item-Path">
        <xsl:param name="item_section" />
        <xsl:param name="item_target" />
        <xsl:param name="depth" />
        <!--
        depth=<xsl:value-of select="$depth"/>
        count=<xsl:value-of select="count(./node())"/><br/>
-->
        <xsl:variable name="cur-id" select="@id"/>
        <xsl:variable name="cur-section" select="@section"/>
        <xsl:choose>    
            <xsl:when test="@id=$item_target">
                &gt;&gt;
                <a>
                    <xsl:attribute name="href">
                        <xsl:text>/</xsl:text>
                                            <!-- req-lg: global langauge variable -->
                        <xsl:value-of select="$req-lg"/>
                        <xsl:text>/</xsl:text>
                        <xsl:value-of select="$item_section"/>
                        <xsl:text>/</xsl:text>
                        <xsl:if test="$depth = 2">
                            <xsl:value-of select="../@id"/>
                            <xsl:text>/</xsl:text>
                        </xsl:if>
                        <xsl:value-of select="@id"/>
                    </xsl:attribute>
                    <xsl:value-of 
                        select="$content/page[@id=$cur-id]/title"/>
                </a>
            </xsl:when>
            <xsl:otherwise>
                <xsl:if test="ancestor-or-self::item/@section = $item_section and count(./node()) > 0">
                &gt;&gt;:
                <a>
                    <xsl:attribute name="href">
                        <xsl:text>/</xsl:text>
                                            <!-- req-lg: global langauge variable -->
                        <xsl:value-of select="$req-lg"/>
                        <xsl:text>/</xsl:text>
                        <xsl:value-of select="$item_section"/>
                        <xsl:text>/</xsl:text>
                        <xsl:if test="$depth = 2">
                            <xsl:value-of select="../@id"/>
                            <xsl:text>/</xsl:text>
                        </xsl:if>
                        <xsl:value-of select="@id"/>
                    </xsl:attribute>
                    <xsl:value-of 
                        select="$content/page[@id=$cur-id and @section=$item_section]/title"/>
                </a>
                </xsl:if>
            </xsl:otherwise>
        </xsl:choose>

        <xsl:apply-templates select="item" mode="Item-Path">
            <xsl:with-param name="item_section" select="$item_section"/>
            <xsl:with-param name="item_target" select="$item_target"/>
            <xsl:with-param name="depth" select="$depth + 1"/>
        </xsl:apply-templates>

    </xsl:template>

したがって、テンプレートブレッドクラムのハードコードされたパラメーターとして、target section='service'およびtargetpage='search-engines-and-ir'のように、次のような出力が期待されます。

ホーム>>サービス>>検索エンジンと-ir

しかし、出力は

ホーム>>サービス>>コンテンツ管理システム>>検索エンジンと-ir

これは明らかに正しくありません。

誰かがこの問題を修正する方法のヒントを教えてもらえますか?その深さのチェックを避けることはさらにエレガントですが、今まで私は他の方法を考えることができません、私はもっとエレガントな解決策があると確信しています。

XSLT 1.0(PHP5経由のlibxml)を使用しています。

私の質問が十分に明確であることを願っています、そうでない場合は、質問してください:-)事前に助けてくれてありがとう!

4

2 に答える 2

2

これと同じくらい簡単です:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

 <xsl:key name="kNodeById" match="item" use="@id"/>

 <xsl:template match="/">
  <xsl:text>home</xsl:text>
  <xsl:call-template name="findPath">
   <xsl:with-param name="pStart" select="'service'"/>
   <xsl:with-param name="pEnd" select="'search-engines-and-ir'"/>
  </xsl:call-template>
 </xsl:template>

 <xsl:template name="findPath">
  <xsl:param name="pStart"/>
  <xsl:param name="pEnd"/>

  <xsl:for-each select=
  "key('kNodeById', $pEnd)
       [ancestor::item[@section=$pStart]]
        [1]
         /ancestor-or-self::item
                [not(descendant::item[@section=$pStart])]
  ">

   <xsl:value-of select=
    "concat('>>', @id[not(../@section)], @section)"/>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

必要な正しい結果が生成されます。

home>>service>>search-engines-and-ir

  1. このソリューションは、階層内の任意のノードからその子孫ノードのいずれかに、階層内の任意のノードからブレッドクラムを出力します。より正確には、属性がに等しい最初の(itemドキュメント順で)場合、ブレッドクラムは、属性が-に等しい最も内側の祖先からその要素に生成されます。id$pEndsection$pStartitem

  2. //このソリューションは、「end」item要素を効率的に見つけるためにキーを使用しているため、を使用するどのソリューションよりもはるかに効率的であるはずです。


II。XSLT 2.0ソリューション:

はるかに短くて簡単-XPathe2.0単一式:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

 <xsl:key name="kNodeById" match="item" use="@id"/>

 <xsl:template match="/">
  <xsl:value-of select=
  "string-join(
       (
        'home',
       key('kNodeById', $pEnd)
          [ancestor::item[@section=$pStart]]
              [1]
                /ancestor-or-self::item
                [not(descendant::item[@section=$pStart])]
                       /(@id[not(../@section)], @section)[1]

        ),
      '>>'
        )
  "/>
 </xsl:template>
</xsl:stylesheet>
于 2012-10-05T05:19:26.717 に答える
1

祖先または自己::軸を反復処理するだけです。これは再帰なしで簡単に実行できます。例えば...

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>

<xsl:template match="/">
  <html><body>
    <xsl:call-template name="bread-crumbs">
      <xsl:with-param name="items" select="*/item" />
      <xsl:with-param name="section" select="'service'" />
      <xsl:with-param name="leaf" select="'p1-2'" />
    </xsl:call-template>  
  </body></html>
</xsl:template>

<xsl:template name="bread-crumbs">
  <xsl:param name="items" />
  <xsl:param name="section" />
  <xsl:param name="leaf" />
  <xsl:value-of select="concat($section,'&gt;&gt;')" />
  <xsl:for-each select="$items/self::item[@section=$section]//item[@id=$leaf]/
                        ancestor-or-self::item[not(@section)]">
    <xsl:value-of select="@id" />
    <xsl:if test="position() != last()">
      <xsl:value-of select="'&gt;&gt;'" />
    </xsl:if>  
  </xsl:for-each>  
</xsl:template>  

</xsl:stylesheet>

...サンプル入力の結果...

<html>
  <body>service&gt;&gt;content-management-systems&gt;&gt;p1-2</body>
</html> 

...次のようにレンダリングされます...

service>>content-management-systems>>p1-2
于 2012-10-05T04:51:52.973 に答える