Copied to clipboard

Flag this post as spam?

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


  • Garrett Fisher 341 posts 496 karma points
    Jul 25, 2012 @ 17:59
    Garrett Fisher
    0

    Nested Loop > Structure Problem

    Hi,

    I am looping through the children of the current node, and when I find a node which itself has children, I need to loop through those and show an image which is a property of that child page. Page structure is as follows:

    Category 1 (is $currentPage)
    -- Product 1 (has articlePhoto)
    -- Product 2
    ---- Slide 2-1 (has slideImage)
    ---- Slide 2-2 (has slideImage)
    ---- Slide 2-3 (has slideImage)

    XSLT is as follows:

    <xsl:for-each select="$currentPage/* [@isDoc and string(umbracoNaviHide) != '1']">
        <li>
            <div style="width:100%;height:100%;clear:both;padding-bottom:20px;">
              <xsl:if test="ucomponents.io:FileExists(ucomponents.io:GetServerMapPath(articlePhoto))">
              <img src="{articlePhoto}" style="float:left;width:150px;max-height:75px;margin:0px 10px 7px 0px;" />
              </xsl:if>
              <xsl:if test="./node()">
                <xsl:for-each select="./node()">
                  <xsl:if test="slideImage != ''">
                    <xsl:variable name="media" select="umbraco.library:GetMedia(slideImage, 0)" />
                    <img src="{$media/umbracoFile}" style="float:left;width:150px;max-height:75px;margin:0px 10px 7px 0px;" />
                  </xsl:if>
                </xsl:for-each>
              </xsl:if>
              <h1 style="font-size:2em;padding-bottom:10px;display:inline;">
                  <a style="width:100%;" href="{umbraco.library:NiceUrl(@id)}">
                  
                  <xsl:choose>
                    <xsl:when test="abstractTitle != ''">
                      <xsl:value-of select="abstractTitle"/>
                    </xsl:when>
                    <xsl:otherwise>
                      <xsl:value-of select="@nodeName"/>
                    </xsl:otherwise>
                  </xsl:choose>
                    
                  </a>
              </h1>
              <xsl:choose>
                <xsl:when test="abstractText != ''">
                  <xsl:value-of select="abstractText" disable-output-escaping="yes"/>
                </xsl:when>
                <xsl:otherwise>
                  <xsl:value-of select="bodyText" disable-output-escaping="yes"/>
                </xsl:otherwise>
              </xsl:choose>
              <a style="width:100%;display:block;" href="{umbraco.library:NiceUrl(@id)}">Learn More &#187;</a>
            </div>
        </li>
      </xsl:for-each>

    The field in question is slideImage.  The children of the current page might have just an articlePhoto, and when they do, this displays fine; however, some child pages might have a slideShow, which involves the currentPage having child nodes which themselves have a media picker property called a slideImage.

    The result I am getting here is all 3 slideImages for the first page in the nested loop, and none for the rest (??).  What I want here is to display the First slideImage of each of the children in the nested loop.  Haven't got to the first-only issue just because my loop structure seems to be wrong in the first place.  What am I missing?

     

    Thanks,

    Garrett

  • Chriztian Steinmeier 2800 posts 8790 karma points MVP 8x admin c-trib
    Jul 25, 2012 @ 22:56
    Chriztian Steinmeier
    0

    Hi Garrett,

    Here's how I'd use the benefit of "match templates" to achieve what (I think) you're after - feel free to ask about how it works:

    <xsl:template match="/">
        <!-- Only run if $currentPage is a Category -->
        <xsl:apply-templates select="$currentPage[self::Category]" />
    </xsl:template>
    
    <xsl:template match="Category">
        <!-- Process all non-hidden Product nodes -->
        <xsl:apply-templates select="Product[not(umbracoNaviHide = 1)]" />
    </xsl:template>
    
    <!-- Template for a single Product -->
    <xsl:template match="Product">
        <li>
            <div class="Product">
                <!-- Process articlePhoto if present -->
                <xsl:apply-templates select="articlePhoto[normalize-space()]" />
    
                <!-- Process the 1st Slide child that have a slideImage -->
                <xsl:apply-templates select="Slide[normalize-space(slideImage)][1]" />
    
                <h1>
                    <a href="{umbraco.library:NiceUrl(@id)}">
                        <!-- Take abstractTitle but fallback to @nodeName if empty -->
                        <xsl:value-of select="(@nodeName[not(normalize-space(../abstractTitle))] | abstractTitle)[1]" />
                    </a>
    
                </h1>
    
                <xsl:choose>
                    <xsl:when test="normalize-space(abstractText)">
                        <xsl:value-of select="abstractText" disable-output-escaping="yes" />
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="bodyText" disable-output-escaping="yes" />
                    </xsl:otherwise>
                </xsl:choose>
    
                <a href="{umbraco.library:NiceUrl(@id)}">Learn More &#187;</a>
            </div>
        </li>
    </xsl:template>
    
    <xsl:template match="Slide">
        <xsl:variable name="media" select="umbraco.library:GetMedia(slideImage, false())" />
        <img class="slideImage" src="{$media/umbracoFile}" />
    </xsl:template>
    
    <xsl:template match="articlePhoto">
        <img class="articlePhoto" src="{.}" />
    </xsl:template>
    
    

     

    /Chriztian

  • Garrett Fisher 341 posts 496 karma points
    Jul 25, 2012 @ 23:45
    Garrett Fisher
    0

    Thanks Chiztian -- this code is great and will save a lot of time elsewhere!!  One thing, though -- under Category, there are Document Types other than Product (I'm trying to use the same template on multiple pages) -- so I copied theProduct one:

    <!-- Template for a single Product -->
    <xsl:template match="Industry">

            <div style="width:100%;height:100%;clear:both;padding:20px 0px 20px 0px;">
              
              <!-- Process articlePhoto if present -->
              <xsl:apply-templates select="articlePhoto[normalize-space()]" />
              
              <!-- Process the 1st Slide child that have a slideImage -->
              <xsl:apply-templates select="Slide[normalize-space(slideImage)][1]" />
              
              <h1 style="font-size:2em;padding-bottom:10px;display:inline;">

                  <a href="{umbraco.library:NiceUrl(@id)}">
                    <!-- Take abstractTitle but fallback to @nodeName if empty -->
                    <xsl:value-of select="(@nodeName[not(normalize-space(../abstractTitle))] | abstractTitle)[1]" />
                  </a>
                      
              </h1>
              
              <xsl:choose>
                <xsl:when test="normalize-space(abstractText)">
                  <xsl:value-of select="abstractText" disable-output-escaping="yes" />
                </xsl:when>
                <xsl:otherwise>
                  <xsl:value-of select="bodyText" disable-output-escaping="yes" />
                </xsl:otherwise>
              </xsl:choose>
              
              <a style="width:100%;display:block;" href="{umbraco.library:NiceUrl(@id)}">Learn More &#187;</a>
            </div>
          
    </xsl:template>

    But when I am on category where Industries are the subs, nothing shows up.  How can I use this XSLT on ALL pages which are "Category," regardless of Product or whatever is underneath it?

    Thanks again,

    Garrett

  • Chriztian Steinmeier 2800 posts 8790 karma points MVP 8x admin c-trib
    Jul 26, 2012 @ 00:07
    Chriztian Steinmeier
    0

    Hi Garrett,

    You probably just need to change the Category template to not target Product pages specifically, so from this:

    <xsl:template match="Category">
            <!-- Process all non-hidden Product nodes -->
            <xsl:apply-templates select="Product[not(umbracoNaviHide = 1)]" />
    </xsl:template>

    to this:

    <xsl:template match="Category">
            <!-- Process all non-hidden child nodes -->
            <xsl:apply-templates select="*[@isDoc][not(umbracoNaviHide = 1)]" />
    </xsl:template>

     

    And if your Product and Industry templates are exact copies - just tell the template to match both types, e.g.:

    <xsl:template match="Product | Industry">
    ...
    </xsl:template>

     

    /Chriztian

  • Garrett Fisher 341 posts 496 karma points
    Jul 26, 2012 @ 00:50
    Garrett Fisher
    0

    Thanks again for staying with me here -- I've made those exact changes (they make good sense):

    <xsl:template match="Category">
            <!-- Process all non-hidden child nodes -->
            <xsl:apply-templates select="*[@isDoc][not(umbracoNaviHide = 1)]" />
    </xsl:template>

    <!-- Template for a single Product -->
    <xsl:template match="Product | Industry">

    But I am getting a parse error on the front end.  It's the apply-templates line.  As soon as I remove the Product there I get the error:

    Error parsing XSLT file: \xslt\Category.xslt

    For some reason any other nodeset I select in that line gives me the error.

    ???

  • Garrett Fisher 341 posts 496 karma points
    Jul 26, 2012 @ 17:46
    Garrett Fisher
    0

    The above error I fixed by placing a null check on the articlePhoto field.  Thanks. 

    Bigger issue now-- the "first child slide" functionality is only working on the First child item.  The link below will help you understand the structure.  I think instead of picking the first Slide child of Each Product, we're picking the first Product only and showing Its first slide.

    http://31.222.157.191/products/desktop.aspx

    Here, the Desktop page represents the Category, and each item in the list below (Environment Manager, Application Manager, Performance Manager) represent the  Products, and these products have mutiple children which are of document type Slide (which has the property slideImage). 

    Make sense?  Can you help me adjust the code so that we get the first Slide child of EACH Product?

    Thanks again, Chriztian -- and sorry to be such a pain -- it's just that this XSLT structure/style is new to me with the multiple template matches.  I'll get the hang of it with your continued belief ;)

    Thanks,

    Garrett

  • Chriztian Steinmeier 2800 posts 8790 karma points MVP 8x admin c-trib
    Jul 26, 2012 @ 23:15
    Chriztian Steinmeier
    0

    Hi Garrett - no worries; we'll get there :-)

    If you need to put a null-check on articlePhoto there must be something else going on - 'cause that's what articlePhoto[normalize-space()] does; it makes sure to only apply the template if there's a value (other than whitespace) in the property.

    - Have you covered all possible child doctypes of Category (e.g.: match="Product | Industry | OtherTypeHere") ?

    If you have others and use the *[@isDoc] selector when applying, you'll need to have 'em covered (or maybe ignore them if they're not similar to Product).

     

    Regarding the 1st Slide problem - isn't that exactly what it's doing now? (Taking the 1st Slide child that has a slideImage and showing that image?)

    What's the intended output in HTML for e.g. the "Environment Manager"?

    /Chriztian

     

  • Garrett Fisher 341 posts 496 karma points
    Jul 31, 2012 @ 14:18
    Garrett Fisher
    0

    Intended output of Use Cases, which is a Category document type, whose children are of type UseCase, which is covered under the <xsl:template match="Product | Industry | CWS_Textpage | UseCase">,for now, is:

    <div style="width:100%;height:100%;clear:both;padding:20px 0px 20px 0px;">
    <img src="/media/4021/images.jpeg" style="float:left;width:150px;max-height:100px;margin:0px 10px 7px 0px;"/>
    <h1 style="font-size:2em;padding-bottom:10px;display:inline;">
    <a href="/solutions/use-cases/windows-7.aspx">Accelerate Windows 7 Migrations</a>
    </h1>
    <p>AppSense enables businesses to realize the benefits of Windows 7
    more quickly and at less cost. In managing the most complex and
    diverse component of the desktop, the user, 'User Virtualization'
    ensures a proven simple and seamless migration to any new desktop
    operating system.</p>
    <a style="width:100%;display:block;" href="/solutions/use-cases/windows-7.aspx">Learn More »</a>
    </div>

    This is the code that yields this currently:

    <xsl:if test="articlePhoto != ''">
    <img src="{articlePhoto}" style="float:left;width:150px;max-height:100px;margin:0px 10px 7px 0px;" />
    </xsl:if>

    Using the apply-templates code:

    <xsl:apply-templates select="articlePhoto[normalize-space(articlePhoto)]" />
    <xsl:template match="articlePhoto">
        <a href="{umbraco.library:NiceUrl(@id)}">
          <img class="articlePhoto" src="{.}" style="float:left;width:150px;max-height:75px;margin:0px 10px 7px 0px;" />
       </a>
    </xsl:template>

    I get this:

    <div style="width:100%;height:100%;clear:both;padding:20px 0px 20px 0px;">
    <h1 style="font-size:2em;padding-bottom:10px;display:inline;">
    <a href="/solutions/use-cases/windows-7.aspx">Accelerate Windows 7 Migrations</a>
    </h1>
    <p>AppSense enables businesses to realize the benefits of Windows 7
    more quickly and at less cost. In managing the most complex and
    diverse component of the desktop, the user, 'User Virtualization'
    ensures a proven simple and seamless migration to any new desktop
    operating system.</p>
    <a style="width:100%;display:block;" href="/solutions/use-cases/windows-7.aspx">Learn More »</a>
    </div>

    In other words everything but the image renders.  There is no error, I was mistaken on that part.

    //Garrett

  • Chriztian Steinmeier 2800 posts 8790 karma points MVP 8x admin c-trib
    Jul 31, 2012 @ 14:38
    Chriztian Steinmeier
    0

    Hi Garrett,

    That makes sense - your apply-templates selection says: "Apply templates to any articlePhoto element that has a non-empty articlePhoto element in it"

    It needs to be empty to perform the check on itself:

    <xsl:apply-templates select="articlePhoto[normalize-space()]" />

    Aternatively, you can use the dot to signal the context node (but that's the default if omitted):

    <xsl:aply-templates select="articlePhoto[normalize-space(.)]" />

    /Chriztian

Please Sign in or register to post replies

Write your reply to:

Draft