Reputation: 247
I am trying to pull a specific node from my xml document, but continue to get content from all nodes. I am testing for a specific jNumber by passing the number to the xslt in a variable set with the fragment call ($jNumber).
<xsl:if test="products/product/jNumber[. = $jNumber]">
<div class="floatLeft padTop10 margLeft10" style="width:185px;">
<xsl:for-each select="products/product/topicFocus">
<div id="tab{./@tab}focus" class="linksUnit padBtm3" style="display:block;"><xsl:text>» </xsl:text><a href="#" class="bold" target="_blank"><em><xsl:value-of select="./@name" /></em></a></div>
<div id="tab{./@tab}ready" class="linksUnit padBtm3" style="display:none;"><xsl:text>» </xsl:text><a href="#" target="_blank"><xsl:value-of select="./@name" /></a></div>
</xsl:for-each>
<xsl:for-each select="products/product/topicLeft">
<div id="tab{./@tab}focus" class="linksUnit padBtm3" style="display:none;"><xsl:text>» </xsl:text> <a href="#" class="bold" target="_blank"><em><xsl:value-of select="./@name" /></em></a></div>
<div id="tab{./@tab}ready" class="linksUnit padBtm3" style="display:block;"><xsl:text>» </xsl:text><a href="#" target="_blank"><xsl:value-of select="./@name" /></a></div>
</xsl:for-each>
</div>
</xsl:if>
It was my understanding that the if statement would cause only nodes that tested true to be displayed. Is that true?
<products>
<product>
<jNumber>1234</jNumber>
<name>Product #1</name>
<numberoftabs>12</numberoftabs>
<!-- Links at top of the page -->
<topicFocus tab="1" name="Accessories"></topicFocus>
<!--topicLeft tab="2" name="Configuration examples"></topicLeft-->
<topicLeft tab="2" name="Resources (white papers, datasheets, etc.)"></topicLeft>
<topicLeft tab="3" name="Download software"></topicLeft>
<topicLeft tab="4" name="FAQs"></topicLeft>
<topicLeft tab="5" name="Interoperability"></topicLeft>
<!--topicLeft tab="6" name="MIBs"></topicLeft-->
<topicRight tab="6" name="Technical documentation">
<subCategory tab="7">Management and Configuration</subCategory>
<subCategory tab="8">Archived</subCategory>
</topicRight>
<topicRight tab="9" name="Related links"></topicRight>
<topicRight tab="10" name="Support form"></topicRight>
</product>
</products>
Upvotes: 0
Views: 130
Reputation: 96920
Jason Aller's answer is certainly correct, but I think you have a lot more opportunities to improve that XSLT. Wherever you have XPath like:
select="products/product/topicFocus"
you are looking at all products
elements that are children of the context node (i.e. the element that your template is transforming, or that your for-each
loop is currently positioned at), and then their product
children, and then any topicFocus
children beneath that. That's either going to find a lot of nodes (if the context node is the parent of your products
element) or none at all (if the context node is a product
element, unless your product
element have products
children).
It's a lot easier to work with XSLT if you use templates as your primary tool. A template transforms a node into a result. In your case, you want to transform product
nodes into div
s. You also want to transform topicFocus
and topicLeft
elements into pairs of div
s.
If your templates' design reflects that, it looks like this:
<!--
this, somewhere in the main template, finds the specific product
element you're looking for and transforms it.
-->
<xsl:apply-templates select="products/product[jNumber = $jNumber]/>
<xsl:template match="product">
<div class="floatLeft padTop10 margLeft10" style="width:185px;">
<xsl:apply-templates select="topicFocus"/>
<xsl:apply-templates select="topicLeft"/>
</div>
</xsl:template>
<xsl:template match="topicFocus | topicLeft">
<xsl:variable name="display1">
<xsl:choose>
<xsl:when test="name() = 'topicFocus'>none</xsl:when>
<xsl:otherwise>block</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="display2">
<xsl:choose>
<xsl:when test="name() = 'topicFocus'>block</xsl:when>
<xsl:otherwise>none</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<div id="tab{@tab}focus" class="linksUnit padBtm3" style="display:{$display1};">
<xsl:text>» </xsl:text>
<a href="#" class="bold" target="_blank">
<em>
<xsl:value-of select="@name" />
</em>
</a>
</div>
<div id="tab{@tab}ready" class="linksUnit padBtm3" style="display:{$display2};">
<xsl:text>» </xsl:text>
<a href="#" target="_blank">
<xsl:value-of select="@name" />
</a>
</div>
</xsl:template>
I've simplified a couple of other things here, too:
topicFocus
and topicLeft
elements is identical except for how the display
style is set, I've created a single template for them../
that you had in front of all of your attributes.Upvotes: 1
Reputation: 3652
The xsl:for-each is nested in the xsl:if, but the for-each isn't limited by the if.
I don't see where jNumber is in the XML you provided, but you can make the for-each respect the same limit as your enclosing if which would choose to display the region or not.
<xsl:for-each select="products/product[jNumber = $jNumber]/topicFocus">
The line above says: starting with the current scope look for products - which have product - which has a jNumber equal to $jNumber - and then look at the topicFocus nodes.
Upvotes: 2