Domanda

Sto cercando di creare un menu CSS dropdrown multilivello per un sito Web che sto facendo sul sistema di gestione dei contenuti di umbraco.

Devo costruirlo per avere la seguente struttura:

<ul id="nav">
  <li><a href="..">Page #1</a></li>
  <li>
    <a href="..">Page #2</a>
    <ul>
      <li><a href="..">Subpage #1</a></li>
      <li><a href="..">Subpage #2</a></li>        
    </ul>
  </li>
</ul>

Quindi ora sto cercando di capire come eseguire l'annidamento usando XSLT. Questo è quello che ho finora:

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

<xsl:param name="currentPage"/>

<!-- update this variable on how deep your menu should be -->
<xsl:variable name="maxLevelForMenu" select="4"/>

<xsl:template match="/">
  <ul id="nav">
    <xsl:call-template name="drawNodes">  
      <xsl:with-param 
       name="parent" 
       select="$currentPage/ancestor-or-self::node [@level=1]"
      />  
    </xsl:call-template>
  </ul>
</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 umbraco.library:IsLoggedOn() = 1)">
    <xsl:for-each select="$parent/node [string(./data [@alias='umbracoNaviHide']) != '1' and @level &lt;= $maxLevelForMenu]"> 
      <li>
        <a href="{umbraco.library:NiceUrl(@id)}">
          <xsl:value-of select="@nodeName"/>
        </a>  
        <xsl:if test="count(./node [string(./data [@alias='umbracoNaviHide']) != '1' and @level &lt;= $maxLevelForMenu]) &gt; 0">   
          <xsl:call-template name="drawNodes">    
            <xsl:with-param name="parent" select="."/>    
          </xsl:call-template>  
        </xsl:if> 
      </li>
    </xsl:for-each>
  </xsl:if>
</xsl:template>

Quello che non riesco a capire è come verificare se il primo livello (qui Pagina # 1 e Pagina # 2) ha figli, e se aggiungono il <ul> extra per contenere il <li> i bambini.

Qualcuno là fuori per indicarmi la giusta direzione?

È stato utile?

Soluzione

Prima di tutto, non è necessario passare il parametro a parent. Il contesto trasporterà queste informazioni.

Ecco il foglio di stile XSL che dovrebbe risolvere il tuo problema:

<!-- update this variable on how deep your menu should be -->
<xsl:variable name="maxLevelForMenu" select="4"/>

<!--- match the document root --->
<xsl:template match="/root">
  <div id="nav">
    <xsl:call-template name="SubTree" />
  </div>
</xsl:template>

<!-- this will be called by xsl:apply-templates -->
<xsl:template match="node">
  <!-- the node is either protected, or the user is logged on (no need to check for IsProtected twice) -->
  <xsl:if test="umbraco.library:IsProtected($parent/@id, $parent/@path) = 0 or umbraco.library:IsLoggedOn() = 1">
    <li>
      <a href="{umbraco.library:NiceUrl(@id)}"><xsl:value-of select="@nodeName"/></a>
      <xsl:call-template name="SubTree" />
    </li>
  </xsl:if>
</xsl:template>

<xsl:template name="SubTree">
  <!-- render sub-tree only if there are any child nodes --->
  <xsl:if test="node">
    <ul>
      <xsl:apply-templates select="node[data[@alias='umbracoNaviHide'] != '1'][@level &lt;= $maxLevelForMenu]">
        <!-- ensure sorted output of the child nodes --->
        <xsl:sort select="@sortOrder" data-type="number" />
      </xsl:apply-templates>
    </ul>
  </xsl:if>
</xsl:template>

Questo è l'XML su cui l'ho provato (non so molto su Umbraco, ma dopo aver visto alcuni esempi spero di essermi avvicinato a un documento Umbraco):

<root id="-1">
  <node id="1" level="1" sortOrder="1" nodeName="Page #1">
    <data alias="umbracoNaviHide">0</data>
  </node>
  <node id="2" level="1" sortOrder="2" nodeName="Page #2">
    <data alias="umbracoNaviHide">0</data>
    <node id="3" level="2" sortOrder="2" nodeName="Subpage #2.2">
      <data alias="umbracoNaviHide">0</data>
    </node>
    <node id="4" level="2" sortOrder="1" nodeName="Subpage #2.1">
      <data alias="umbracoNaviHide">0</data>
      <node id="5" level="3" sortOrder="3" nodeName="Subpage #2.1.1">
        <data alias="umbracoNaviHide">0</data>
      </node>
    </node>
    <node id="6" level="2" sortOrder="3" nodeName="Subpage #2.3">
      <data alias="umbracoNaviHide">1</data>
    </node>
  </node>
  <node id="7" level="1" sortOrder="3" nodeName="Page #3">
    <data alias="umbracoNaviHide">1</data>
  </node>
</root>

Questo è l'output:

<div id="nav">
  <ul>
    <li><a href="http://foo/">Page #1</a></li>
    <li><a href="http://foo/">Page #2</a>
      <ul>
        <li><a href="http://foo/">Subpage #2.1</a>
          <ul>
            <li><a href="http://foo/">Subpage #2.1.1</a></li>
          </ul>
        </li>
        <li><a href="http://foo/">Subpage #2.2</a></li>
      </ul>
    </li>
  </ul>
</div>

Altri suggerimenti

Non c'è nulla di molto speciale in questo problema. La seguente soluzione verifica che l'elenco dei nodi per

<xsl:apply-templates/>

non è vuoto, prima di applicare i modelli:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes"/>
  <xsl:variable name="vLevel" select="0"/>

    <xsl:template match="root">
      <xsl:variable name="vnextLevelNodes"
           select="node[@level = $vLevel+1]"/>
      <xsl:if test="$vnextLevelNodes">
       <ul>
         <xsl:apply-templates select="$vnextLevelNodes"/>
       </ul>
      </xsl:if>
    </xsl:template>

    <xsl:template match="node">
  <!-- the node is either protected, or the user is logged on (no need to check for IsProtected twice) -->
    <!-- <xsl:if test=
      "umbraco.library:IsProtected($parent/@id, $parent/@path) = 0
      or
       umbraco.library:IsLoggedOn() = 1"> -->
    <xsl:if test="1">
        <li>
          <!-- <a href="{umbraco.library:NiceUrl(@id)}"> -->
          <a href="'umbraco.library:NiceUrl(@id)'">
            <xsl:value-of select="@nodeName"/>
          </a>

                  <xsl:variable name="vnextLevelNodes"
                       select="node[@level = current()/@level+1]"/>
                  <xsl:if test="$vnextLevelNodes">
                   <ul>
                     <xsl:apply-templates select="$vnextLevelNodes"/>
                   </ul>
                  </xsl:if>
        </li>
    </xsl:if>
    </xsl:template>
</xsl:stylesheet>

Ho usato il seguente documento sorgente XML:

<root id="-1">
    <node id="1" level="1" sortOrder="1" nodeName="Page #1">
        <data alias="umbracoNaviHide">0</data>
    </node>
    <node id="2" level="1" sortOrder="2" nodeName="Page #2">
        <data alias="umbracoNaviHide">0</data>
        <node id="3" level="2" sortOrder="2" nodeName="Subpage #2.2">
            <data alias="umbracoNaviHide">0</data>
        </node>
        <node id="4" level="2" sortOrder="1" nodeName="Subpage #2.1">
            <data alias="umbracoNaviHide">0</data>
            <node id="5" level="3" sortOrder="3" nodeName="Subpage #2.1.1">
                <data alias="umbracoNaviHide">0</data>
            </node>
        </node>
        <node id="6" level="2" sortOrder="3" nodeName="Subpage #2.3">
            <data alias="umbracoNaviHide">1</data>
        </node>
    </node>
    <node id="7" level="1" sortOrder="3" nodeName="Page #3">
        <data alias="umbracoNaviHide">1</data>
    </node>
</root>

Inoltre, ho commentato qualsiasi codice che fa riferimento alle funzioni di estensione di Umbraco, poiché non ho accesso ad esse.

Quando la trasformazione di cui sopra viene applicata su questo documento XML di origine, viene prodotto il risultato desiderato desiderato:

<ul>
    <li>
        <a href="'umbraco.library:NiceUrl(@id)'">Page #1</a>
    </li>
    <li>
        <a href="'umbraco.library:NiceUrl(@id)'">Page #2</a>
        <ul>
            <li>
                <a href="'umbraco.library:NiceUrl(@id)'">Subpage #2.2</a>
            </li>
            <li>
                <a href="'umbraco.library:NiceUrl(@id)'">Subpage #2.1</a>
                <ul>
                    <li>
                        <a href="'umbraco.library:NiceUrl(@id)'">Subpage #2.1.1</a>
                    </li>
                </ul>
            </li>
            <li>
                <a href="'umbraco.library:NiceUrl(@id)'">Subpage #2.3</a>
            </li>
        </ul>
    </li>
    <li>
        <a href="'umbraco.library:NiceUrl(@id)'">Page #3</a>
    </li>
</ul>

Spero che questo abbia aiutato.

Saluti,

Dimitre Novatchev

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top