2010-01-21 5 views
1

최근까지는 XSLT가 완전히 새로운 것이기까지 잠시 동안 Dynamicweb이라는 덴마크 CMS가있는 메뉴/하위 메뉴에서 작업했습니다.어린이가 XSLT를 사용하는 경우 부모 요소에 클래스를 지정하십시오.

Dynamicweb 특정 질문 또는 XSLT 관련 질문 인 경우 알 수 없지만 어쨌든 물어 봅니다.

나의 현재 XSLT 문서는 다음과 같습니다

<xsl:template match="//Page"> 
    <xsl:param name="depth"/> 
    <li> 
     <xsl:attribute name="id"> 
      <xsl:value-of select="concat('', translate(translate(@MenuText, translate(@MenuText, $validRange, ''), ''), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'))" /> 
     </xsl:attribute> 

     <a> 
      <xsl:attribute name="class"> 
       <!-- Add .inpath class --> 
       <xsl:if test="@InPath='True'"> 
        <xsl:text> inpath</xsl:text> 
       </xsl:if> 

       <!-- Add .firstitem class --> 
       <xsl:if test="position() = 1"> 
        <xsl:text> firstitem</xsl:text> 
       </xsl:if> 

       <!-- Add .miditem class --> 
       <xsl:if test="position() &gt; 1 and position() &lt; count(//Page)"> 
        <xsl:text> miditem</xsl:text> 
       </xsl:if> 

       <!-- Add .lastitem class --> 
       <xsl:if test="position() = count(//Page)"> 
        <xsl:text> lastitem</xsl:text> 
       </xsl:if> 

       <!-- Add .active class --> 
       <xsl:if test="@Active = 'True'"> 
        <xsl:text> active</xsl:text> 
       </xsl:if> 
      </xsl:attribute> 

      <!-- Add link ID (URL friendly menu text) --> 
      <xsl:attribute name="id"> 
       <xsl:value-of select="concat('anchor-', translate(translate(@MenuText, translate(@MenuText, $validRange, ''), ''), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'))" /> 
      </xsl:attribute> 

      <!-- Add link URL --> 
      <xsl:attribute name="href"> 
       <xsl:value-of select="@FriendlyHref" disable-output-escaping="yes" /> 
      </xsl:attribute> 

      <!-- Add link text --> 
      <span><xsl:value-of select="@MenuText" disable-output-escaping="yes" /></span> 
     </a> 
     <xsl:if test="count(Page) and @MenuText != 'Home'"> 
      <ul class="level{@AbsoluteLevel+1}"> 
       <xsl:apply-templates select="Page"> 
        <xsl:with-param name="depth" select="$depth+1"/> 
       </xsl:apply-templates> 
      </ul> 
     </xsl:if> 
    </li> 

</xsl:template> 

당신은 내가 activeinpath에 대한 Dynamicweb 태그를 기반으로 클래스를 추가하는 방법을 볼 수 있습니다. 문제는 문서 (여기에 붙여 넣지 않음)에 있습니다. 은 하위 메뉴 (ulli)를 인쇄하는 코드입니다. 하위 메뉴 항목을 클릭하면 해당 항목은 active 클래스가되지만 부모에게 active 클래스도 제공 할 수 있습니까?

업데이트 : 원시 XML (지저분한 XML에 대해 유감입니다)이 추가되었습니다.

<?xml version="1.0" encoding="utf-8"?> 
<NavigationTree> 
    <Settings> 
    <Pageview ID="1" AreaID="1" MenuText="Home" Title="Home" NavigationName="" /> 
    <Setting Level="1"> 
     <NavigationImage Value="" /> 
     <NavigationMouseoverImage Value="" /> 
     <NavigationActiveImage Value="" /> 
     <NavigationImgAfter Value="" /> 
     <NavigationDividerImage Value="" /> 
     <NavigationHideSpacer Value="True" /> 
     <NavigationSpace Value="0" /> 
    </Setting> 
    <Setting Level="2"> 
     <NavigationImage Value="" /> 
     <NavigationMouseoverImage Value="" /> 
     <NavigationActiveImage Value="" /> 
     <NavigationImgAfter Value="" /> 
     <NavigationDividerImage Value="" /> 
     <NavigationHideSpacer Value="" /> 
     <NavigationSpace Value="0" /> 
    </Setting> 
    <Setting Level="3"> 
     <NavigationImage Value="" /> 
     <NavigationMouseoverImage Value="" /> 
     <NavigationActiveImage Value="" /> 
     <NavigationImgAfter Value="" /> 
     <NavigationDividerImage Value="" /> 
     <NavigationHideSpacer Value="" /> 
     <NavigationSpace Value="0" /> 
    </Setting> 
    <Setting Level="4"> 
     <NavigationImage Value="" /> 
     <NavigationMouseoverImage Value="" /> 
     <NavigationActiveImage Value="" /> 
     <NavigationImgAfter Value="" /> 
     <NavigationDividerImage Value="" /> 
     <NavigationHideSpacer Value="" /> 
     <NavigationSpace Value="3" /> 
    </Setting> 
    <Setting Level="5"> 
     <NavigationImage Value="" /> 
     <NavigationMouseoverImage Value="" /> 
     <NavigationActiveImage Value="" /> 
     <NavigationImgAfter Value="" /> 
     <NavigationDividerImage Value="" /> 
     <NavigationHideSpacer Value="" /> 
     <NavigationSpace Value="3" /> 
    </Setting> 
    </Settings> 
    <Page ID="1" AreaID="1" MenuText="Home" MouseOver="" Href="Default.aspx?ID=1" FriendlyHref="/default/home.aspx" Image="" ImageActive="" ImageMouseOver="" Title="" Allowclick="True" ShowInSitemap="True" AbsoluteLevel="1" RelativeLevel="1" Sort="1" LastInLevel="False" InPath="True" ChildCount="3" class="L1_Active" Active="True" IsPagePasswordProtected="False" IsPageUserProtected="False" CanAccessPasswordProtectedPage="False" CanAccessUserProtectedPage="True"> 
    <Page ID="6" AreaID="1" MenuText="News" MouseOver="" Href="Default.aspx?ID=6" FriendlyHref="/default/home/news.aspx" Image="" ImageActive="" ImageMouseOver="" Title="" Allowclick="True" ShowInSitemap="True" AbsoluteLevel="2" RelativeLevel="2" Sort="1" LastInLevel="False" InPath="False" ChildCount="0" class="L2" Active="False" IsPagePasswordProtected="False" IsPageUserProtected="False" CanAccessPasswordProtectedPage="False" CanAccessUserProtectedPage="True" /> 
    <Page ID="7" AreaID="1" MenuText="About" MouseOver="" Href="Default.aspx?ID=7" FriendlyHref="/default/home/about.aspx" Image="" ImageActive="" ImageMouseOver="" Title="" Allowclick="True" ShowInSitemap="True" AbsoluteLevel="2" RelativeLevel="2" Sort="2" LastInLevel="False" InPath="False" ChildCount="0" class="L2" Active="False" IsPagePasswordProtected="False" IsPageUserProtected="False" CanAccessPasswordProtectedPage="False" CanAccessUserProtectedPage="True" /> 
    <Page ID="8" AreaID="1" MenuText="Presence" MouseOver="" Href="Default.aspx?ID=8" FriendlyHref="/default/home/presence.aspx" Image="" ImageActive="" ImageMouseOver="" Title="" Allowclick="True" ShowInSitemap="True" AbsoluteLevel="2" RelativeLevel="2" Sort="3" LastInLevel="True" InPath="False" ChildCount="0" class="L2" Active="False" IsPagePasswordProtected="False" IsPageUserProtected="False" CanAccessPasswordProtectedPage="False" CanAccessUserProtectedPage="True" /> 
    </Page> 
    <Page ID="2" AreaID="1" MenuText="Hygiene" MouseOver="" Href="Default.aspx?ID=14" FriendlyHref="/default/hygiene.aspx" Image="" ImageActive="" ImageMouseOver="" Title="" Allowclick="False" ShowInSitemap="True" AbsoluteLevel="1" RelativeLevel="1" Sort="2" LastInLevel="False" InPath="False" ChildCount="2" class="L1" Active="False" IsPagePasswordProtected="False" IsPageUserProtected="False" CanAccessPasswordProtectedPage="False" CanAccessUserProtectedPage="True"> 
    <Page ID="14" AreaID="1" MenuText="Professional" MouseOver="" Href="Default.aspx?ID=14" FriendlyHref="/default/hygiene/professional.aspx" Image="/Files/Navigation/menu_antibac_01.gif" ImageActive="/Files/Navigation/menu_antibac_02.gif" ImageMouseOver="/Files/Navigation/menu_antibac_02.gif" Title="" Allowclick="True" ShowInSitemap="True" AbsoluteLevel="2" RelativeLevel="2" Sort="1" LastInLevel="False" InPath="False" ChildCount="0" class="L2" Active="False" IsPagePasswordProtected="False" IsPageUserProtected="False" CanAccessPasswordProtectedPage="False" CanAccessUserProtectedPage="True" /> 
    <Page ID="15" AreaID="1" MenuText="Private" MouseOver="" Href="Default.aspx?ID=15" FriendlyHref="/default/hygiene/private.aspx" Image="/Files/Navigation/menu_antibac_01.gif" ImageActive="/Files/Navigation/menu_antibac_02.gif" ImageMouseOver="/Files/Navigation/menu_antibac_02.gif" Title="" Allowclick="True" ShowInSitemap="True" AbsoluteLevel="2" RelativeLevel="2" Sort="2" LastInLevel="True" InPath="False" ChildCount="0" class="L2" Active="False" IsPagePasswordProtected="False" IsPageUserProtected="False" CanAccessPasswordProtectedPage="False" CanAccessUserProtectedPage="True" /> 
    </Page> 
    <Page ID="3" AreaID="1" MenuText="Household &amp; Leisure" MouseOver="" Href="Default.aspx?ID=3" FriendlyHref="/default/household---leisure.aspx" Image="" ImageActive="" ImageMouseOver="" Title="" Allowclick="True" ShowInSitemap="True" AbsoluteLevel="1" RelativeLevel="1" Sort="3" LastInLevel="False" InPath="False" ChildCount="0" class="L1" Active="False" IsPagePasswordProtected="False" IsPageUserProtected="False" CanAccessPasswordProtectedPage="False" CanAccessUserProtectedPage="True" /> 
    <Page ID="4" AreaID="1" MenuText="Car Care" MouseOver="" Href="Default.aspx?ID=4" FriendlyHref="/default/car-care.aspx" Image="" ImageActive="" ImageMouseOver="" Title="" Allowclick="True" ShowInSitemap="True" AbsoluteLevel="1" RelativeLevel="1" Sort="4" LastInLevel="False" InPath="False" ChildCount="1" class="L1" Active="False" IsPagePasswordProtected="False" IsPageUserProtected="False" CanAccessPasswordProtectedPage="False" CanAccessUserProtectedPage="True"> 
    <Page ID="20" AreaID="1" MenuText="Carix" MouseOver="" Href="Default.aspx?ID=20" FriendlyHref="/default/car-care/carix.aspx" Image="/Files/Navigation/menu_carix_01.gif" ImageActive="/Files/Navigation/menu_carix_02.gif" ImageMouseOver="/Files/Navigation/menu_carix_02.gif" Title="" Allowclick="True" ShowInSitemap="True" AbsoluteLevel="2" RelativeLevel="2" Sort="1" LastInLevel="True" InPath="False" ChildCount="0" class="L2" Active="False" IsPagePasswordProtected="False" IsPageUserProtected="False" CanAccessPasswordProtectedPage="False" CanAccessUserProtectedPage="True" /> 
    </Page> 
    <Page ID="5" AreaID="1" MenuText="Industrial Chemicals" MouseOver="" Href="Default.aspx?ID=5" FriendlyHref="/default/industrial-chemicals.aspx" Image="" ImageActive="" ImageMouseOver="" Title="" Allowclick="True" ShowInSitemap="True" AbsoluteLevel="1" RelativeLevel="1" Sort="5" LastInLevel="True" InPath="False" ChildCount="0" class="L1" Active="False" IsPagePasswordProtected="False" IsPageUserProtected="False" CanAccessPasswordProtectedPage="False" CanAccessUserProtectedPage="True" /> 
</NavigationTree> 
+0

예, 할 수있는 방법이 있습니다 (아마도). 어쨌든, 나는 XSLT를 작성하고 테스트하기 위해 샘플 입력 문서가 필요할 것이다. 질문에 하나를 추가하십시오. :) – Tomalak

+0

귀하의 XML은 모두 소문자이며, 귀하의 XSLT는 대소 문자가 혼용됩니다. 뭐가 맞습니까? – Tomalak

+0

죄송합니다, 나는 XML을 prettifier 통해 넣어 : P 혼합 경우가 맞습니다! –

답변

1

나는 당신의 문제에 대한 해결책을 만들었습니다 (나는 주로 그 과정에서 당신의 접근 방식 수정 한) :

(20 페이지에 "활성"으로 설정된 경우) 결과

<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:variable name="upper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" /> 
    <xsl:variable name="lower" select="'abcdefghijklmnopqrstuvwxyz'" /> 
    <xsl:variable name="validRange" select="concat($upper, $lower)" /> 

    <xsl:template match="NavigationTree"> 
    <ul class="level1"> 
     <xsl:apply-templates select="Page"> 
     <xsl:sort select="@Sort" data-type="number" /> 
     </xsl:apply-templates> 
    </ul> 
    </xsl:template> 

    <xsl:template match="Page"> 
    <xsl:variable name="idText" select=" 
     translate(
     translate(@MenuText, translate(@MenuText, $validRange, ''), ''), $upper, $lower 
    ) 
    " /> 
    <li id="{$idText}"> 
     <a href="{@FriendlyHref}" id="anchor-{$idText}"> 
     <xsl:attribute name="class"> 
      <xsl:if test="position() = 1">firstitem </xsl:if> 
      <xsl:if test="position() &gt; 1 and position() &lt; last()">miditem </xsl:if> 
      <xsl:if test="position() = last()">lastitem </xsl:if> 
      <xsl:if test="@InPath='True'">inpath </xsl:if> 
      <!-- the descendant-or-self XPath axis solves your question! --> 
      <xsl:if test="descendant-or-self::Page[@Active='True']">active </xsl:if> 
     </xsl:attribute> 
     <span> 
      <xsl:value-of select="@MenuText" /> 
     </span> 
     </a> 

     <xsl:if test="Page"> 
     <ul class="level{Page/@AbsoluteLevel}"> 
      <xsl:apply-templates select="Page"> 
      <xsl:sort select="@Sort" data-type="number" /> 
      </xsl:apply-templates> 
     </ul> 
     </xsl:if> 
    </li> 
    </xsl:template> 

</xsl:stylesheet> 

<ul class="level1"> 
    <li id="home"> 
    <a href="/default/home.aspx" id="anchor-home" class="firstitem inpath"> 
     <span>Home</span> 
    </a> 
    <ul class="level2"> 
     <li id="news"> 
     <a href="/default/home/news.aspx" id="anchor-news" class="firstitem"> 
      <span>News</span> 
     </a> 
     </li> 
     <li id="about"> 
     <a href="/default/home/about.aspx" id="anchor-about" class="miditem"> 
      <span>About</span> 
     </a> 
     </li> 
     <li id="presence"> 
     <a href="/default/home/presence.aspx" id="anchor-presence" class="lastitem"> 
      <span>Presence</span> 
     </a> 
     </li> 
    </ul> 
    </li> 
    <li id="hygiene"> 
    <a href="/default/hygiene.aspx" id="anchor-hygiene" class="miditem"> 
     <span>Hygiene</span> 
    </a> 
    <ul class="level2"> 
     <li id="professional"> 
     <a href="/default/hygiene/professional.aspx" id="anchor-professional" class="firstitem"> 
      <span>Professional</span> 
     </a> 
     </li> 
     <li id="private"> 
     <a href="/default/hygiene/private.aspx" id="anchor-private" class="lastitem"> 
      <span>Private</span> 
     </a> 
     </li> 
    </ul> 
    </li> 
    <li id="householdleisure"> 
    <a href="/default/household---leisure.aspx" id="anchor-householdleisure" class="miditem"> 
     <span>Household &amp; Leisure</span> 
    </a> 
    </li> 
    <li id="carcare"> 
    <a href="/default/car-care.aspx" id="anchor-carcare" class="miditem active"> 
     <span>Car Care</span> 
    </a> 
    <ul class="level2"> 
     <li id="carix"> 
     <a href="/default/car-care/carix.aspx" id="anchor-carix" class="firstitem lastitem active"> 
      <span>Carix</span> 
     </a> 
     </li> 
    </ul> 
    </li> 
    <li id="industrialchemicals"> 
    <a href="/default/industrial-chemicals.aspx" id="anchor-industrialchemicals" class="lastitem"> 
     <span>Industrial Chemicals</span> 
    </a> 
    </li> 
</ul> 

disable-output-escaping="yes"을 원하지 않는다는 점에 유의하십시오. 조작 된 XML을 생성 할 것이므로 제거했습니다.

+0

와우, 정말 고마워요! 이것은 원본 코드보다 훨씬 좋아 보입니다. D –

+0

신속한 후속 질문이 있습니다. 부모 페이지에있는 경우에만 메뉴 요소를 인쇄하여 테스트 할 수 있습니까? –

+0

@rebellion : "부모 페이지에 있음"을 정의하십시오. – Tomalak

5

음, 관찰의 커플 :

  1. 당신은 match='//Page'에 선도적 인 슬래시가 필요하지 않습니다. match 속성의 XPath는 노드를 탐색하지 않고 템플리트를 선택하는 데 사용됩니다.

  2. depth 매개 변수는 필요하지 않습니다. Page의 깊이는 Page 조상의 수이기 때문에 count(ancestor::Page)을 사용하여 깊이를 계산할 수 있습니다.

  3. Page 요소 트리를 걸어서 Active 속성을 가져 오려면 ancestor-or-self::Page[last()]/@Active을 사용하십시오. 상위 또는 자체 축은 컨텍스트 노드로 시작하고 TLE에 도달 할 때까지 부모, 부모의 부모 등을 포함하는 노드의 목록입니다. Page 부분은 해당 축에서 Page 요소 만 찾으며 [last()] 조건자는 해당 Page 요소의 마지막 요소를 찾습니다.이 요소는 항상 최상위 레벨 Page 요소입니다.

  4. 나는 count(//Page)의 사용이 장기적으로 당신을 잘 지원하지 않는다고 강력히 의심합니다. 소스 트리에있는 모든 요소는 발견 된 위치와 상관없이 모두 하나씩 계산됩니다. 그게 니가 원하는거야? 아니면 현재 Page 요소가 형제 인 Page 요소와 관련이 있는지 알고 싶습니까? 그렇다면 position() != 1 and position() != last()을 사용해도됩니다. position()이 컨텍스트 노드의 위치를 ​​표현 컨텍스트와 관련하여 반환하기 때문에이 방법이 효과적입니다. 즉, xsl:apply-templates select='*'이 호출되면 요소 세트를 만들고 각각에 대해 일치하는 템플리트를 찾습니다. 그것은 표현 문맥입니다. 해당 목록의 세 번째 요소는 position()이고 3은

  5. 입니다. test='count(Page)을 수행 할 필요가 없습니다. 같은 일을합니다. 자식 Page 요소가 있으면 true로 평가됩니다. 그것은 더 읽기 쉽고 가능성이 더 빠릅니다.

편집

법인 Tomalak의 관찰 (주석 참조).

편집하는 것은

알다시피, 나는 실제로 이러한 질문을 읽어야합니다. 당신의 맥락에서, 부모 요소 그것을 또는이 활성화되어 그 아이들 중 하나가, 내가 무슨 짓을했는지의 반대, 당신은 할 거라고 클래스를 제공합니다 :

<xsl:if test="@Active='True' or Page[@Active = 'True']"> 
    <xsl:text> active</xsl:text> 
</xsl:if> 

을하지만, Tomalak의 예는, 사용하는 descendant-or-self 축은 어디서나 메뉴가 활성화되어 있으면 메뉴를 활성화하는 것이 목적이라면 사용하려는 것일 확률이 높습니다. 또한이 작업을 수행 할 수 있습니다 :

<xsl:if test="@Active='True' or .//Page[@Active = 'True']"> 
    <xsl:text> active</xsl:text> 
</xsl:if> 

으로 ".//"는 descendant::에 대한 정말 그냥 바로 가기입니다.

+1

+1 - 좋은 분석! (P.S. :'ancestor-or-self :: Page [last()]/@ Active'도 작동합니다). – Tomalak

+1

알다시피, 나는 1999 년 이래로 XSLT로 하루 종일 일해 왔으며 그 명백한 관용구가 결코 나에게 일어나지 않았다. 나는 아마 내 코드베이스에서'X [position() = last()]'를 수백 번 발견했다. 쳇. –

+0

포괄적 인 목록 주셔서 감사합니다. 이것은 많은 도움이됩니다! 내가 언급 한 많은 것들을 인식하지 못했습니다 (CMS와 함께 제공되는 템플릿 만 수정했습니다). 그러나'ancestor-or-self :: Page [last()]/@ Active'를 어떻게 사용하는지 모르겠습니다. 나는 그것을 '에서 사용하려고 시도했지만 작동하지 않았다 :/ –

관련 문제