2010-04-20 46 views
1

我使用XSLT在umbraco中創建了一個菜單。菜單使用通常的ul和li元素,而且我只顯示菜單的第一級。目標是創建一個菜單,當我單擊一個父節點(位於頂層)時展開以顯示子菜單。使用xslt爲Umbraco創建菜單

我在xslt之後我需要在點擊時暴露子菜單。

我想我會需要利用祖先或自身來檢測當前菜單和父菜單和顯示它們,也是$當前頁變量。

我有以下XSLT:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp "&#x00A0;"> ]> 
<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:msxml="urn:schemas-microsoft-com:xslt" 
    xmlns:umbraco.library="urn:umbraco.library" xmlns:Exslt.ExsltCommon="urn:Exslt.ExsltCommon" xmlns:Exslt.ExsltDatesAndTimes="urn:Exslt.ExsltDatesAndTimes" xmlns:Exslt.ExsltMath="urn:Exslt.ExsltMath" xmlns:Exslt.ExsltRegularExpressions="urn:Exslt.ExsltRegularExpressions" xmlns:Exslt.ExsltStrings="urn:Exslt.ExsltStrings" xmlns:Exslt.ExsltSets="urn:Exslt.ExsltSets" xmlns:tagsLib="urn:tagsLib" xmlns:urlLib="urn:urlLib" 
    exclude-result-prefixes="msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets tagsLib urlLib "> 

<xsl:output method="xml" omit-xml-declaration="yes"/> 

<xsl:param name="currentPage"/> 

<xsl:template match="/"> 
    <div id="kb-categories"> 
     <h3>Categories</h3> 
     <xsl:call-template name="drawNodes"> 
      <xsl:with-param name="parent" select="$currentPage/ancestor-or-self::node [@level=1]"/> 
     </xsl:call-template> 
    </div> 
</xsl:template> 

<xsl:template name="drawNodes"> 
    <xsl:param name="parent"/> 
    <xsl:if test="(umbraco.library:IsProtected($parent/@id, $parent/@path) = 0 or (umbraco.library:IsProtected($parent/@id, $parent/@path) = 1)) and $parent/@level = 1">   
     <ul class="kb-menuLevel1" >  
     <xsl:for-each select="$parent/node [string(./data [@alias='showInMenu']) = 1]"> 
      <li> 
       <a href="/kb{umbraco.library:NiceUrl(@id)}"> 
        <xsl:value-of select="@nodeName"/> 
       </a>     
       <xsl:variable name="level" select="@level" /> 
       <xsl:if test="(count(./node [string(./data [@alias='showInMenu']) = '1']) &gt; 0)"> 
        <xsl:call-template name="drawNodes">  
         <xsl:with-param name="parent" select="."/>  
        </xsl:call-template> 
       </xsl:if> 
      </li> 
     </xsl:for-each> 
     </ul> 
    </xsl:if> 
    <xsl:if test="(umbraco.library:IsProtected($parent/@id, $parent/@path) = 0 or (umbraco.library:IsProtected($parent/@id, $parent/@path) = 1)) and $parent/@level &gt; 1">  
     <ul class="kb-menuLevel{@level}" style="display: none;">    
     <xsl:for-each select="$parent/node [string(./data [@alias='showInMenu']) = 1]"> 
      <li> 
       <a href="/kb{umbraco.library:NiceUrl(@id)}"> 
        <xsl:value-of select="@nodeName"/> 
       </a>     
       <xsl:variable name="level" select="@level" /> 
       <xsl:if test="(count(./node [string(./data [@alias='showInMenu']) = '1']) &gt; 0)"> 
        <xsl:call-template name="drawNodes">  
         <xsl:with-param name="parent" select="."/>  
        </xsl:call-template> 
       </xsl:if> 
      </li> 
     </xsl:for-each> 
     </ul> 
    </xsl:if> 

</xsl:template> 

</xsl:stylesheet> 

我懷疑這可能使用應用模板加以改進,但我還沒有了,要加快(我的學習XSLT的這是唯一的第二天)。

我的菜單:

  • 菜單項目1
  • 菜單項2
  • 菜單項3
  • 菜單項4

當我點擊菜單項2我會進入菜單項2的頁面,子菜單也會顯示:

  • 菜單項1
  • 菜單項2
    - 菜單項目2.1
    - 菜單項目2.2
  • 菜單項3
  • 菜單項4

等向下嵌套菜單。

下面是上述的一些示例xml。

<root> 
    <node id="1" nodeTypeAlias="kbHomepage" nodeName="Home" level="1"> 
     <data alias="introduction"> 
      <![CDATA[<p>Welcome</p>]]> 
     </data> 
     <node id="2" nodeTypeAlias="guide" nodeName="Menu Item 1" level="2"> 
      <data alias="bodyText"> 
       <![CDATA[<p>This is some text</p>]]> 
      </data> 
      <data alias="showInMenu">1</data> 
      <data alias="menuName">Menu Item 1</data> 
     </node>  
     <node id="3" nodeTypeAlias="guide" nodeName="Menu Item 2" level="2"> 
      <data alias="bodyText"> 
       <![CDATA[<p>This is some text</p>]]> 
      </data> 
      <data alias="showInMenu">1</data> 
      <data alias="menuName">Menu Item 2</data> 
      <node id="4" nodeTypeAlias="guide" nodeName="Menu Item 2.1" level="3"> 
       <data alias="bodyText"> 
        <![CDATA[<p>Some Text</p>]]> 
       </data> 
       <data alias="showInMenu">1</data> 
       <data alias="menuName">Menu Item 2.1</data> 
      </node> 
      <node id="5" nodeTypeAlias="guide" nodeName="Menu Item 2.2" level="3"> 
       <data alias="bodyText"> 
        <![CDATA[<p>Some Text</p>]]> 
       </data> 
       <data alias="showInMenu">1</data> 
       <data alias="menuName">Menu Item 2.2</data> 
       <node id="6" nodeTypeAlias="guide" nodeName="Item 2.2.1 Guide" level="4"> 
        <data alias="bodyText"> 
         <![CDATA[<p>Some Text</p>]]> 
        </data> 
        <data alias="showInMenu">0</data> 
        <data alias="menuName"></data> 
       </node> 
      </node> 
     </node>  
     <node id="8" nodeTypeAlias="guide" nodeName="Menu Item 3" level="2"> 
      <data alias="bodyText"> 
       <![CDATA[<p>This is some text</p>]]> 
      </data> 
      <data alias="showInMenu">1</data> 
      <data alias="menuName">Menu Item 3</data> 
     </node>  
     <node id="9" nodeTypeAlias="guide" nodeName="Menu Item 4" level="2"> 
      <data alias="bodyText"> 
       <![CDATA[<p>This is some text</p>]]> 
      </data> 
      <data alias="showInMenu">1</data> 
      <data alias="menuName">Menu Item 4</data> 
     </node>  
    </node> 
    <node id="7" nodeTypeAlias="someAlias" nodeName="Some Other Page" level="1"> 
     <data alias="bodyText"> 
      <![CDATA[<p>This is some text</p>]]> 
     </data>   
    </node>  
</root> 

編輯:幾乎下面做什麼,我需要:

<xsl:variable name="visibleChidren" select="node[data[@alias='showInMenu'] = 1 and (@level = 2 or descendant-or-self::*[generate-id($currentPage) = generate-id(.)] or preceding-sibling::*[generate-id($currentPage) = generate-id(.)] or following-sibling::*[generate-id($currentPage) = generate-id(.)])]" /> 

我只需要還包括從當前頁面的直接孩子。

回答

0

我想出我需要做什麼,我想要什麼。關鍵線是:

<xsl:variable name="visibleChidren" select="node[data[@alias='showInMenu'] = 1 and (@level = 2 or descendant-or-self::*[generate-id($currentPage) = generate-id(.)] or preceding-sibling::*[generate-id($currentPage) = generate-id(.)] or following-sibling::*[generate-id($currentPage) = generate-id(.)] or parent::*[generate-id($currentPage) = generate-id(.)])]" /> 

從整個XSLT:

<!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp "&#x00A0;"> ]> 
<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:msxml="urn:schemas-microsoft-com:xslt" 
    xmlns:umbraco.library="urn:umbraco.library" xmlns:Exslt.ExsltCommon="urn:Exslt.ExsltCommon" xmlns:Exslt.ExsltDatesAndTimes="urn:Exslt.ExsltDatesAndTimes" xmlns:Exslt.ExsltMath="urn:Exslt.ExsltMath" xmlns:Exslt.ExsltRegularExpressions="urn:Exslt.ExsltRegularExpressions" xmlns:Exslt.ExsltStrings="urn:Exslt.ExsltStrings" xmlns:Exslt.ExsltSets="urn:Exslt.ExsltSets" xmlns:tagsLib="urn:tagsLib" xmlns:urlLib="urn:urlLib" 
    exclude-result-prefixes="msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets tagsLib urlLib "> 

    <xsl:output method="xml" omit-xml-declaration="yes"/> 

    <xsl:param name="currentPage"/> 
    <xsl:variable name="currentLevel" select="$currentPage/@level" /> 

    <xsl:template match="/"> 
    <div id="kb-categories"> 
     <h3>Categories</h3> 
     <xsl:apply-templates mode="list" select="$currentPage/ancestor-or-self::node [@nodeTypeAlias = 'kbHomepage']" /> 
    </div> 
    </xsl:template> 

    <!-- matches anything with <node> children and makes a list out of them --> 
    <xsl:template match="node" mode="list"> 
    <!-- select only sub-nodes that have 'showInMenu' = 1 --> 
    <xsl:variable name="visibleChidren" select="node[data[@alias='showInMenu'] = 1 and (@level = 2 or descendant-or-self::*[generate-id($currentPage) = generate-id(.)] or preceding-sibling::*[generate-id($currentPage) = generate-id(.)] or following-sibling::*[generate-id($currentPage) = generate-id(.)] or parent::*[generate-id($currentPage) = generate-id(.)])]" /> 
    <xsl:if test="$visibleChidren"> 
     <ul> 
     <xsl:apply-templates mode="item" select="$visibleChidren" /> 
     </ul> 
    </xsl:if> 
    </xsl:template> 

    <xsl:template match="node" mode="item"> 
     <li> 
     <a href="/kb{umbraco.library:NiceUrl(@id)}"> 
      <xsl:value-of select="@nodeName"/> 
     </a> 
     <xsl:apply-templates mode="list" select="." /> 
     </li> 
    </xsl:template> 

</xsl:stylesheet> 
2

我試過了(用我關於Umbraco的非常有限的知識)來清理你的代碼並刪除冗餘。它看起來好像可以與您提供的XML樣本一起工作,但我無法真正地針對Umbraco進行測試。

<!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp "&#x00A0;"> ]> 
<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:msxml="urn:schemas-microsoft-com:xslt" 
    xmlns:umbraco.library="urn:umbraco.library" xmlns:Exslt.ExsltCommon="urn:Exslt.ExsltCommon" xmlns:Exslt.ExsltDatesAndTimes="urn:Exslt.ExsltDatesAndTimes" xmlns:Exslt.ExsltMath="urn:Exslt.ExsltMath" xmlns:Exslt.ExsltRegularExpressions="urn:Exslt.ExsltRegularExpressions" xmlns:Exslt.ExsltStrings="urn:Exslt.ExsltStrings" xmlns:Exslt.ExsltSets="urn:Exslt.ExsltSets" xmlns:tagsLib="urn:tagsLib" xmlns:urlLib="urn:urlLib" 
    exclude-result-prefixes="msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets tagsLib urlLib "> 

    <xsl:output method="xml" omit-xml-declaration="yes" encoding="utf-8" /> 

    <xsl:param name="currentPage" /> 

    <xsl:template match="/"> 
    <div id="kb-categories"> 
     <h3>Categories</h3> 
     <xsl:apply-templates mode="list" select="/root/node[@nodeTypeAlias='kbHomepage']" /> 
    </div> 
    </xsl:template> 

    <!-- matches anything with <node> children and creates an <ul> --> 
    <xsl:template match="*[node]" mode="list"> 
    <!-- prepare a list of all visible children --> 
    <xsl:variable name="visibleChidren" select="node[ 
     data[@alias='showInMenu'] = 1 
     and (
     not(umbraco.library:IsProtected(@id, @path)) 
     or umbraco.library:IsLoggedOn() 
    ) 
    ]" /> 
    <!-- prepare a CSS class for the "selected path" --> 
    <xsl:variable name="display"> 
     <xsl:if test=".//node[generate-id() = generate-id($currentPage)]"> 
     <xsl:text>visible</xsl:text> 
     </xsl:if> 
    </xsl:variable> 
    <xsl:if test="$visibleChidren"> 
     <ul class="menu kb-menuLevel{$visibleChidren[1]/@level} {$display}"> 
     <xsl:apply-templates mode="item" select="$visibleChidren" /> 
     </ul> 
    </xsl:if> 
    </xsl:template> 

    <!-- matches <node> elements and turns them into list items --> 
    <xsl:template match="node" mode="item"> 
    <li> 
     <xsl:if test="generate-id() = generate-id($currentPage)"> 
     <xsl:attribute name="class">selected</xsl:attribute> 
     </xsl:if> 
     <a href="/kb{{umbraco.library:NiceUrl(@id)}}"> 
     <xsl:value-of select="@nodeName" /> 
     </a> 
     <!-- if there are any child nodes, render them --> 
     <xsl:if test="node"> 
     <xsl:apply-templates mode="list" select="." /> 
     </xsl:if> 
    </li> 
    </xsl:template> 

</xsl:stylesheet> 

爲您提供以下服務。請注意,我已經逃過<a href...屬性值模板 - 刪除上面的雙花括號再次啓用它們:

<div id="kb-categories"> 
    <h3>Categories</h3> 
    <ul class="menu kb-menuLevel2 visible"> 
    <li> 
     <a href="/kb{umbraco.library:NiceUrl(@id)}">Menu Item 1</a> 
    </li> 
    <li> 
     <a href="/kb{umbraco.library:NiceUrl(@id)}">Menu Item 2</a> 
     <ul class="menu kb-menuLevel3 visible"> 
     <li class="selected"> 
      <a href="/kb{umbraco.library:NiceUrl(@id)}">Menu Item 2.1</a> 
     </li> 
     <li> 
      <a href="/kb{umbraco.library:NiceUrl(@id)}">Menu Item 2.2</a> 
     </li> 
     </ul> 
    </li> 
    <li> 
     <a href="/kb{umbraco.library:NiceUrl(@id)}">Menu Item 3</a> 
    </li> 
    <li> 
     <a href="/kb{umbraco.library:NiceUrl(@id)}">Menu Item 4</a> 
    </li> 
    </ul> 
</div> 

現在你可以做在CSS:

ul.menu { 
    display: hidden; 
} 
ul.menu.visible { 
    display: block; 
} 
ul.menu li.selected { 
    font-weight: bold; 
} 

是否幫助你嗎?

+0

@rob_g:在我們實現節點的可視性,請確認是否到目前爲止我的代碼產生正確的HTML輸出。 – Tomalak 2010-04-20 10:06:09

+0

Tomalak,我已經添加了XML。菜單應該只顯示2級節點,除非點擊菜單項。說菜單項2被點擊,然後菜單項2下的所有2級節點和所有3級節點應該是可見的。點擊菜單項2將會打開它的頁面(由正在生成的元素決定,一旦這個頁面打開,$ currentPage指向它,我希望當前頁面足以做我所需要的:顯示所有直接$ currentPage的所有祖先以及所有祖先都達到幷包括2級。謝謝。 – 2010-04-21 00:18:13

+0

感謝您的幫助Tomalak – 2010-04-21 02:22:25