Question for XSLT gurus - Test in foreach

Discussion in 'XML' started by Dirk McCormick, Apr 28, 2005.

  1. I need to transform something that looks like this

    <!-- %%%%%%%%%%%%%%%%%%%%%%% -->
    <MyStructure>

    <Packages>
    <Package>
    <PkgBenefitCode>1</PkgBenefitCode>
    <PkgBenefitCode>2</PkgBenefitCode>
    <PkgBenefitCode>3</PkgBenefitCode>
    </Package>
    ...
    </Packages>

    <Benefits>
    <Benefit code="1">
    <Content>The content 1</Content>
    </Benefit>
    <Benefit code="2">
    <Link>http://www.example.com</Link>
    </Benefit>
    <Benefit code="3">
    <Content>The content 3</Content>
    </Benefit>
    ...
    </Benefits>

    </MyStructure>
    <!-- %%%%%%%%%%%%%%%%%%%%%%% -->

    Into an HTML table with rows having alternating background colours,
    and containing only Content, ie ignoring the Benefits with a Link
    element.

    I do a for-each on the PkgBenefitCode elements and then I do an if
    within the for-each to determine whether the Content element exists.
    This means that I can't use test="position() mod 2" to determine the
    background colour of the table row, because the if filters some
    elements out and results in the background colours not always
    alternating properly. See sample code below.

    Can anyone suggest a way of solving this that's not too much of a
    hack?
    (eg using recursive method call with alternating parameter is a hack!)

    Ideally what I need is to pass a filtered list to the foreach, or in
    the foreach have a test for whether the Benefit element contains a
    Link element but I can't see how to do this.

    Sample code is below:
    <table>
    <xsl:for-each select="/MyStructure/Packages/Package/PkgBenefitCode">
    <xsl:if test="count(/MyStructure/Benefits/Benefit[@code=string(.)]/Content)
    = 1">
    <tr><td bgColor="<!--position() mod 2-->">
    <xsl:value-of select="/MyStructure/Benefits/Benefit[@code=string(.)]/Content"/>
    </td></tr>
    </xsl:if>
    </xsl:for-each>
    </table>

    Any help appreciated.
    Please post replies to newsgroup only.
    Cheers,
    Dirk
     
    Dirk McCormick, Apr 28, 2005
    #1
    1. Advertising

  2. As youindicated to get position() right you need to do
    <xsl:for-each select="/MyStructure/Packages/Package/PkgBenefitCode
    [some predicate]">

    The predicate there might be a bit involved, but if in fact you just want
    to iterate over the content elemnst in the other branch, why not do

    <xsl:for-each select=/MyStructure/Benefits/Benefit/Content

    however I'll assume that in your real example that isn't workable.

    Another alternative to using position() since you are not sorting is to
    use
    count(preceding-sibling::Benefit[Content]) mod 2
    as the test

    But to use position I'd probably use a key which simplifies things a lot
    in this case:

    <xsl:key name="c" match="Benefit[Content]" use="@code"/>

    then you can do
    <xsl:for-each
    select="/MyStructure/Packages/Package/PkgBenefitCode[key('c',.)]">
    to iterate over those codes that have Content and
    <xsl:value-of select="key('c',.)/Content"/>
    to access that content directly without having to keep searching with a
    long xpath.

    David
     
    David Carlisle, Apr 28, 2005
    #2
    1. Advertising

  3. Dirk McCormick

    Guest

    Hi David,

    Thanks for your response. The solution using xsl:key seems to be the
    most elegant, however the xml data I am working with comes from two
    external xml files, one containing

    <Packages>
    <Package>
    <PkgBenefitCode>1</PkgBenefitCode>
    <PkgBenefitCode>2</PkgBenefitCode>
    <PkgBenefitCode>3</PkgBenefitCode>
    </Package>
    ...
    </Packages>

    and the other containing

    <Benefits>
    <Benefit code="1">
    <Content>The content 1</Content>
    </Benefit>
    <Benefit code="2">
    <Link>http://www.example.com</Link>
    </Benefit>
    <Benefit code="3">
    <Content>The content 3</Content>
    </Benefit>
    ...
    </Benefits>

    It is not possible to reference an external document with a key, except
    when the context is changed (See http://www.w3.org/TR/xslt#key). I
    could change the context to the document containing the key but this
    wouldn't solve my problem of needing to reference the other document.

    I will try one of the other solutions but I wonder if there is any way
    of using a key or similar across documents in this fashion?

    Thanks again for your help.
    Dirk
     
    , May 5, 2005
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Alex
    Replies:
    6
    Views:
    2,210
    John Saunders
    Aug 26, 2003
  2. George Copeland

    Question for Java Gurus

    George Copeland, May 17, 2004, in forum: Java
    Replies:
    44
    Views:
    1,229
    P.Hill
    May 25, 2004
  3. Skybuck Flying

    Call oddities: &Test() vs &Test vs Test

    Skybuck Flying, Oct 4, 2009, in forum: C Programming
    Replies:
    1
    Views:
    726
    Skybuck Flying
    Oct 4, 2009
  4. Robin

    foreach loop test

    Robin, Apr 13, 2004, in forum: Perl Misc
    Replies:
    11
    Views:
    202
    Robin
    Apr 27, 2004
  5. dhtml
    Replies:
    2
    Views:
    767
Loading...

Share This Page