Question for XSLT gurus - Test in foreach

D

Dirk McCormick

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
 
D

David Carlisle

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
 
D

dirk

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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,999
Messages
2,570,246
Members
46,841
Latest member
WilmerBelg

Latest Threads

Top