2013-03-01 3 views
1

Это должно быть так просто! У меня есть документ XML, содержащий иерархию меню:XSLT 1.0: Генерация иерархии меню предка

<?xml version="1.0" encoding="utf-8"?> 
<menu page_id="18" language="en-GB"> 
    <item id="1" child_of="0"> 
     <menu_order>1</menu_order> 
     <title><![CDATA[Home]]></title> 
    </item> 
    <item id="18" child_of="0"> 
     <title><![CDATA[Page One]]></title> 
     <submenu child_of="18"> 
      <item id="20" child_of="18"> 
       <title><![CDATA[Sub Menu One]]></title> 
       <submenu child_of="20"> 
        <item id="26" child_of="20"> 
         <title><![CDATA[SubMenu 1-1]]></title> 
        </item> 
        <item id="27" child_of="20"> 
         <title><![CDATA[SubMenu 1-2]]></title> 
        </item> 
       </submenu> 
      </item> 
      <item id="21" child_of="18"> 
       <title><![CDATA[Sub Menu Two]]></title> 
       <submenu child_of="21"> 
        <item id="28" child_of="21"> 
         <title><![CDATA[SubMenu 2-1]]></title> 
        </item> 
        <item id="29" child_of="21"> 
         <title><![CDATA[SubMenu 2-2]]></title> 
         <submenu child_of="29"> 
          <item id="32" child_of="29"> 
           <title><![CDATA[SubMenu 2-2-1]]></title> 
          </item> 
          <item id="33" child_of="29"> 
           <title><![CDATA[SubMenu 2-2-2]]></title> 
          </item> 
         </submenu> 
        </item> 
        <item id="30" child_of="21"> 
         <title><![CDATA[SubMenu 2-3]]></title> 
        </item> 
        <item id="31" child_of="21"> 
         <title><![CDATA[SubMenu 2-4]]></title> 
        </item> 
       </submenu> 
      </item> 
      <item id="22" child_of="18"> 
       <title><![CDATA[Sub Menu Three]]></title> 
      </item> 
     </submenu> 
    </item> 
    <item id="19" child_of="0"> 
     <title><![CDATA[Page Two]]></title> 
    </item> 
</menu> 

Мне нужно, чтобы преобразовать его в список HTML, где (1), если активный щелкнул пункт меню/имеет подменю, он показывает подменю (только ребенок в меню для предметы) под ним. Например, нажав на пункт ид = «18» должен дать мне это:

<ul> 
    <li id="1">Home</li> 
    <li id="18">Page One 
     <ul> 
      <li id="20">Sub Menu One</li> 
      <li id="21">Sub Menu Two</li> 
      <li id="22">Sub Menu Three</li> 
     </ul> 
    </li> 
    <li id="19">Page Two</li> 
</ul> 

или (2), если элемент активного меню имеет предков, он оказывает все его непосредственные братьев и сестер и предков в структуре. Например, щелкнув элемент ID = «33» должен дать мне это:

<ul> 
    <li id="1">Home</li> 
    <li id="18">Page One<ul> 
      <li id="20">Sub Menu One</li> 
      <li id="21">Sub Menu Two<ul> 
        <li id="28">SubMenu 2-1</li> 
        <li id="29">SubMenu 2-2 
         <ul> 
          <li id="32">SubMenu 2-2-1</li> 
          <li id="33">SubMenu 2-2-2</li> 
         </ul> 
        </li> 
        <li id="30">SubMenu 2-3</li> 
        <li id="31">SubMenu 2-4</li> 
       </ul> 
      </li> 
      <li id="22">Sub Menu Three</li> 
     </ul> 
    </li> 
    <li id="19">Page Two</li> 
</ul> 

Моя беда в том, что это мой XSL стилей создает список с двумя предками субменю! Пожалуйста, помогите ... Я был на этом за ЧАСЫ! Вот мой XSLT:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:output indent="yes"/> 
    <!-- The DOM ID of the active menu item --> 
    <xsl:param name="activeItemID"/> 

    <xsl:template match="text()"> 
     <xsl:apply-templates/> 
    </xsl:template> 

    <xsl:template match="menu"> 
     <ul> 
      <xsl:choose> 
       <xsl:when test="//item[@id = $activeItemID]/@child_of = '0'"> 
        <xsl:choose> 
         <xsl:when test="//submenu[@child_of = $activeItemID]/node()"> 
          <xsl:apply-templates 
           select="//item[@child_of = '0'] | //submenu[@child_of = $activeItemID]"/> 
         </xsl:when> 
         <xsl:otherwise> 
          <xsl:apply-templates select="//item[@child_of = '0']"/> 
         </xsl:otherwise> 
        </xsl:choose> 
       </xsl:when> 
       <xsl:otherwise> 
        <xsl:choose> 
         <xsl:when test="//submenu[@child_of = $activeItemID]/node()"> 
          <xsl:apply-templates 
           select="//item[@child_of = '0'] | //submenu[@child_of = $activeItemID]/ancestor-or-self::submenu/item" 
          /> 
         </xsl:when> 
         <xsl:otherwise> 
          <xsl:apply-templates 
           select="//item[@child_of = '0'] | //item[@id = $activeItemID]/ancestor-or-self::submenu" 
          /> 
         </xsl:otherwise> 
        </xsl:choose> 
       </xsl:otherwise> 
      </xsl:choose> 
     </ul> 
    </xsl:template> 

    <xsl:template match="item"> 
     <li> 
      <xsl:value-of select="title" disable-output-escaping="no"/> 
      <xsl:apply-templates select="submenu[@child_of = $activeItemID]"/> 
     </li> 
    </xsl:template> 

    <xsl:template match="submenu"> 
     <ul> 
      <xsl:apply-templates select="item[@child_of = $activeItemID]"> 
       <xsl:sort select="menu_order" data-type="number"/> 
      </xsl:apply-templates> 
     </ul> 
    </xsl:template> 

</xsl:stylesheet> 

ответ

2

Этот XSLT должен делать то, что вы хотите сделать:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:output indent="yes"/> 
    <!-- The DOM ID of the active menu item --> 
    <xsl:param name="activeItemID" /> 

    <xsl:template match="menu | submenu"> 
    <ul> 
     <xsl:apply-templates select="item" /> 
    </ul> 
    </xsl:template> 

    <xsl:template match="item"> 
    <li id="{@id}"> 
     <xsl:value-of select="title" /> 
     <xsl:apply-templates select="submenu[..//@id = $activeItemID]"/> 
    </li> 
    </xsl:template> 
</xsl:stylesheet> 

При запуске на своем входе образца со значением параметра, как 18, она производит:

<ul> 
    <li id="1">Home</li> 
    <li id="18"> 
    Page One<ul> 
     <li id="20">Sub Menu One</li> 
     <li id="21">Sub Menu Two</li> 
     <li id="22">Sub Menu Three</li> 
    </ul> 
    </li> 
    <li id="19">Page Two</li> 
</ul> 

При запуске со значением параметра 33, оно производит:

<ul> 
    <li id="1">Home</li> 
    <li id="18"> 
    Page One<ul> 
     <li id="20">Sub Menu One</li> 
     <li id="21"> 
     Sub Menu Two<ul> 
      <li id="28">SubMenu 2-1</li> 
      <li id="29"> 
      SubMenu 2-2<ul> 
       <li id="32">SubMenu 2-2-1</li> 
       <li id="33">SubMenu 2-2-2</li> 
      </ul> 
      </li> 
      <li id="30">SubMenu 2-3</li> 
      <li id="31">SubMenu 2-4</li> 
     </ul> 
     </li> 
     <li id="22">Sub Menu Three</li> 
    </ul> 
    </li> 
    <li id="19">Page Two</li> 
</ul> 

У вашего XSLT была некоторая логика сортировки, но элемент, который использовался для сортировки, как представляется, присутствовал в исходном XML в одном месте. Это то, что вы хотели использовать? Вы пропустили большинство элементов menu_order из исходного XML для простоты?

+0

@JLRische: Большое вам спасибо! Это работает отлично и именно то, что мне нужно. Да, у меня есть своя логика в полной версии, но в этом примере ошибочно осталось несколько узлов. Еще раз спасибо. – Kevin

+0

Могу ли я спросить, как создать вариацию структуры меню с помощью XSLT, чтобы исключить элементы, где @child_of = '0'? Спасибо. – Kevin

Смежные вопросы