Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Connie DeCinko 931 posts 1160 karma points
    Mar 11, 2011 @ 17:43
    Connie DeCinko
    0

    Conditional for-each?

    The code below works, but is bloated and full of redundancy.  How can I rewrite it, perhaps making the for-each statement (the only difference between the blocks) conditional?

          <xsl:choose>
            <xsl:when test="count(current()/child::* [@isDoc and string(umbracoNaviHide) != '1']) &gt; 0">
              <xsl:for-each select="$currentPage/self::* [@isDoc and string(umbracoNaviHide) != '1']">
                <h3>
                  <a href="{umbraco.library:NiceUrl(@id)}">
                    <xsl:value-of select="@nodeName"/>
                  </a>
                </h3>
              </xsl:for-each>
            </xsl:when>
            <xsl:otherwise>
              <xsl:for-each select="$currentPage/parent::* [@isDoc and string(umbracoNaviHide) != '1']">
                <h3>
                  <a href="{umbraco.library:NiceUrl(@id)}">
                    <xsl:value-of select="@nodeName"/>
                  </a>
                </h3>
              </xsl:for-each>
            </xsl:otherwise>
          </xsl:choose>
  • Tom Fulton 2030 posts 4998 karma points c-trib
    Mar 11, 2011 @ 17:54
    Tom Fulton
    0

    Hi Connie,

    One way would be to store the for-each xpath in a variable, not tested but something like this should work:

          
    <xsl:variable name="theItems">
    <xsl:choose>
            <xsl:when test="count(current()/child::* [@isDoc and string(umbracoNaviHide) != '1']) &gt; 0">
    <xsl:copy-of select="
    $currentPage/self::* [@isDoc and string(umbracoNaviHide) != '1']"/>
            </xsl:when>
            <xsl:otherwise>
    <xsl:copy-of select="
    $currentPage/parent::* [@isDoc and string(umbracoNaviHide) != '1']"/>
            </xsl:otherwise>
          </xsl:choose>
    </xsl:variable>

              <xsl:for-each select="$theItems">
                <h3>
                  <a href="{umbraco.library:NiceUrl(@id)}">
                    <xsl:value-of select="@nodeName"/>
                  </a>
                </h3>
              </xsl:for-each>

    And hopefully Chriztian will pop in and tell us the right way to do it with templates :)

    -Tom

  • Connie DeCinko 931 posts 1160 karma points
    Mar 11, 2011 @ 18:14
    Connie DeCinko
    0

    That's the same way I originally tried to do it, it makes sense when you look at it.  However, it saves but throws a parsing error when you run it.  My fear with templates is that again, I'll have to duplicate several dozen lines of code when only one line varies between them.

     

  • Tom Fulton 2030 posts 4998 karma points c-trib
    Mar 11, 2011 @ 18:26
    Tom Fulton
    0

    Just tried it, you might need to add this to the for-each (wouldn't save until I did)

      <xsl:for-each select="msxml:node-set($theItems)/*">

    Also is this block inside another for-each loop?  I assume it is since you reference current() in the first condition

    -Tom

  • Connie DeCinko 931 posts 1160 karma points
    Mar 11, 2011 @ 18:52
    Connie DeCinko
    0

    Yeah, that saves but still throws a parsing error.

    I found this reference which actually works, although a bit ugly.

        <xsl:variable name="startNode" select="($currentPage/self::* [@isDoc and string(umbracoNaviHide) != '1'])
          [count($currentPage/child::* [@isDoc and string(umbracoNaviHide) != '1']) &gt; 0] |
          ($currentPage/parent::* [@isDoc and string(umbracoNaviHide) != '1'])" />

    Problem now is I want to limit it to one level.  Gotta restrict my results / replace my for-each.

  • Connie DeCinko 931 posts 1160 karma points
    Mar 11, 2011 @ 22:44
    Connie DeCinko
    0

    Ok, I decided to try the template approach as it allows for passing in a paramater (learned something new).  I've almost got it, but still have two issues.  First, I can't seem to get a reference to a specific node (currently shown as //root).  Second, my test for child nodes appears hit and miss with the various methods I've tried.  Right now, if there are no children the check is not finding that.

    <?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"
      exclude-result-prefixes="msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets ">

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

    <xsl:param name="currentPage"/>

    <xsl:template match="/">
      
      <xsl:if test="count($currentPage/ancestor-or-self::* [@template=1165 and string(umbracoNaviHide) != '1']) &gt; 0">

        <xsl:choose>
          <xsl:when test="$currentPage [name() = 'NewsRelease']">
            <xsl:call-template name="showMenu">
              <xsl:with-param name="startNode" select="//root"/>
            </xsl:call-template>
          </xsl:when>
          <!-- if node is a second level page, use self -->
          <xsl:when test="$currentPage [@isDoc and @level = 2 and string(umbracoNaviHide) != '1']">
            <xsl:call-template name="showMenu">
              <xsl:with-param name="startNode" select="$currentPage/self::*"/>
            </xsl:call-template>
          </xsl:when>
          <!-- check for children, only use self if node has children -->
          <xsl:when test="$currentPage/child::* [not(data[@alias = 'umbracoNaviHide'] = 1)]">
            <xsl:call-template name="showMenu">
              <xsl:with-param name="startNode" select="$currentPage/self::*"/>
            </xsl:call-template>
          </xsl:when>
          <!-- if no children, use parent -->
          <xsl:otherwise>
            <xsl:call-template name="showMenu">
              <xsl:with-param name="startNode" select="$currentPage/parent::*"/>
            </xsl:call-template>
          </xsl:otherwise>
        </xsl:choose>

      </xsl:if>

    </xsl:template>
        
    <xsl:template name="showMenu">
      <xsl:param name="startNode"/>

      <div class="block">

        <xsl:for-each select="$startNode [@isDoc and string(umbracoNaviHide) != '1']">
          <h3>
            <a href="{umbraco.library:NiceUrl(@id)}">
              <xsl:value-of select="@nodeName"/>
            </a>
          </h3>
        </xsl:for-each>
          
          <ul class="products">
            <xsl:for-each select="$startNode/* [@isDoc and string(umbracoNaviHide) != '1']">
              <xsl:variable name="subItems" select="umbraco.library:GetXmlNodeById(@id)/child::* [@isDoc and string(umbracoNaviHide) != '1']"/>
              <li>
                <xsl:if test="count($subItems)">
                  <xsl:attribute name="class">open</xsl:attribute>
                </xsl:if>
                <a href="{umbraco.library:NiceUrl(@id)}">
                  <xsl:value-of select="@nodeName"/>
                </a>
                <xsl:if test="count($subItems)">
                  <ul>
                    <xsl:for-each select="$subItems">
                      <xsl:variable name="subSubItems" select="umbraco.library:GetXmlNodeById(@id)/child::* [@isDoc and string(umbracoNaviHide) != '1']"/>
                      <li>
                        <a href="{umbraco.library:NiceUrl(@id)}">
                          <xsl:value-of  select="@nodeName"/>
                        </a>
                        <xsl:if test="count($subSubItems)">
                          <ul>
                            <xsl:for-each select="$subSubItems">
                              <li>
                                <a href="{umbraco.library:NiceUrl(@id)}">
                                  <xsl:value-of  select="@nodeName"/>
                                </a>
                              </li>
                            </xsl:for-each>
                          </ul>
                        </xsl:if>
                      </li>
                    </xsl:for-each>
                  </ul>
                </xsl:if>
              </li>
            </xsl:for-each>
          </ul>
        </div>
          </xsl:template>

    </xsl:stylesheet>
  • Chriztian Steinmeier 2800 posts 8790 karma points MVP 8x admin c-trib
    Mar 11, 2011 @ 22:52
    Chriztian Steinmeier
    0

    Hi Connie,

    The reason your "//root" doesn't work is because you're selecting it within the root ("/") template - in there, the / refers to a small <macro> XML document - you need to build the XPath off of $currentPage to do it - I usually do this right after the currentPage param:

    <xsl:param name="currentPage" />
    <xsl:variable name="root" select="$currentPage/ancestor-or-self::root" />

    I'll take a look at the rest and give you some hints to reduce it even further... 

    /Chriztian

  • Connie DeCinko 931 posts 1160 karma points
    Mar 11, 2011 @ 23:31
    Connie DeCinko
    0

    Ok, a bit closer.  Almost there...

    Got this to work, finally, for the child nodes:

    <xsl:when test="count($currentPage/descendant::* [@isDoc]) > 0">

    Now, I am using this temporarily, but need a correct solution to reference a specific node:

    <xsl:with-param name="startNode" select="$currentPage/../../../.."/>

     

Please Sign in or register to post replies

Write your reply to:

Draft