Copied to clipboard

Flag this post as spam?

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


  • Stefan 117 posts 215 karma points
    Feb 02, 2012 @ 23:29
    Stefan
    0

    Get child node from within for-each loop

    Hi.

    I'm working on a gallery which have the following structure:

    - GalleryList
    --- GalleryList
    ------ GalleryPage
    ------ GalleryPage
    --- GalleryList
    ------ GalleryPage
    ------ GalleryPage

    The GalleryList is a page that shows all child gallery folders. When on the first level (GalleryList) I loop through all childs with a for-each. If the childs also are of the type GalleryList, I need to select the first child of that.

    Simplified code:

    <xsl:for-each select="$currentPage/child::* [@isDoc]">
      <img>
     
        <xsl:attribute name="src">
          <xsl:choose>
         
            <xsl:when test="$img = '' "> <xsl:value-of select="child of the processed child..." />         </xsl:when>
           
            <xsl:otherwise>
              <xsl:value-of select="$img/galleryImage/crops/crop[@name='GalleryListSmall']/@url" />
            </xsl:otherwise>
           
          </xsl:choose>
        </xsl:attribute>

      </img>
    </xsl:for-each>

     

    If no image is found, the first child is a GalleryList - I need to select the first child of that.

    Sorry for this stupid question, but I can't seem to get my head around the syntax :/

    Thanks in advance!
    Stefan

  • Chriztian Steinmeier 2800 posts 8790 karma points MVP 8x admin c-trib
    Feb 03, 2012 @ 00:33
    Chriztian Steinmeier
    0

    Hi Stefan,

    Looks like you need yourself a dose of the "apply-templates" approach - see if this is close to what you want:

    <xsl:template match="/">
        <!-- Process the children of $currentPage -->
        <xsl:apply-templates select="$currentPage/*[@isDoc]" />
    </xsl:template>
    
    <!-- Template for a GalleryList -->
    <xsl:template match="GalleryList">
        <!-- Take the crop from the first GalleryPage childnode -->
        <xsl:apply-templates select="GalleryPage[1]" />
    </xsl:template>
    
    <!-- Template for a GalleryPage - take the cropped image -->
    <xsl:template match="GalleryPage">
        <img src="{galleryImage/crops/crop[@name = 'GalleryListSmall']/@url}" />
    </xsl:template>
    

    /Chriztian

  • Stefan 117 posts 215 karma points
    Feb 03, 2012 @ 13:06
    Stefan
    0

    Thank you for your reply!

    I have not had a chance to rewrite the code to use templates just yet, but I'm a little confused if your proposed code will work no matter what the currentPage is?

    If currentPage is the GalleryList on level 1, the template applied for GalleryList will work correctly, but if currentPage is GalleryList on level 2 the childs will be of the docType GalleryPage. Then the image should be taken directly from that page.

    Do I need an if statement to somehow determine what docType the child nodes are? Or is there a neat XSLT trick you can enlighten me with? :)
    Also, is it possible to call a template which holds the general markup, and from there apply all other templates to render the correct image?

  • Chriztian Steinmeier 2800 posts 8790 karma points MVP 8x admin c-trib
    Feb 03, 2012 @ 13:24
    Chriztian Steinmeier
    1

    Hi Stefan,

    It goes like this:

    When you use the apply-templates instruction, you tell the processor to collect all the nodes that match the XPath in the select attribute - in this case, all the child document nodes of whichever $currentPage is. They're collected in document order and the processor then looks at each of them in turn and checks if there's a template that "matches" the node, and subsequently use that template to render it with.

    If it has a list of GalleryPage nodes it will generate an image for each of their galleryImage properties (the paths inside a template are relative to that template's matching element). 

    Now, if it has a list of GalleryList nodes instead, it will use the match="GalleryList" template which in turn says "Hey, use the first of my GalleryPage child nodes instead", delegating the actual markup creation from within the GalleryPage template.

    So there you have it - as you can see you don't need an if statement to check the document type - instead you write a template for each of the types you need to support. Easily extensible.

    /Chriztian

     

  • Stefan 117 posts 215 karma points
    Feb 10, 2012 @ 16:57
    Stefan
    0

    Thank you very much for your thorough elaboration on how to use templates!

    I need to extend the solution to contain a wrapper for every 3 items rendered. It is somewhat working, but the renderings are very inconsistent.

    The current structure of the gallery on the site:

    Root
    - GalleryList (root)
    -- GalleryList (1)
    ---- GalleryPage (1)
    -- GalleryList (2)
    ---- GalleryPage (1)
    ---- GalleryPage (2)
    ---- GalleryPage (3)
    ---- GalleryPage (4)

    If currentPage is GalleryList (root) the GalleryList (1) page renders just fine, but as the only item inside the wrapper. Next, what should have been GalleryList (2) is instead all child pages of itself. When currentPage is GalleryList (2) every child pages renders. For GalleryPage (1) it is fine, but GalleryPage (2) shows up 2 times, GalleryPage (3) shows up 3 times together with GalleryPage (4) which also shows 3 times.

    Here's the code:

    <xsl:template match="/">
            <!-- Process the children of $currentPage -->
            <xsl:apply-templates select="$currentPage/*[@isDoc and @level = $currentPage/@level +1]" />
    </xsl:template>

    <!-- Template for a GalleryList -->
    <xsl:template match="GalleriList">
        <!-- Take the crop from the first GalleryPage childnode -->
        <xsl:apply-templates select="GalleryPage[1 and position() mod 3 = 1]" />
    </xsl:template>

    <!-- 3-item wrapper for a GalleryPage -->
    <xsl:template match="GalleryPage">
        <div style="height: 300px;">
            <xsl:apply-templates select=".|following-sibling::GalleryPage[position() &lt; 3]" mode="inner" />
        </div>
    </xsl:template>

    <!-- Template for a GalleryPage to be rendered -->
    <xsl:template match="GalleryPage" mode="inner">
        Contents here...
    </xsl:template>


    Any suggestions?

Please Sign in or register to post replies

Write your reply to:

Draft