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="开发者_如何学Cproducts/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>
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.
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:
- Since it looks to me as though the HTML your transform is emitting for
topicFocus
andtopicLeft
elements is identical except for how thedisplay
style is set, I've created a single template for them. - I've used whitespace and indenting in the template so that the structure of the HTML is apparent; this will make maintaining it a zillion times easier, and will have no effect on how the transform produces its output.
- I've removed the redundant
./
that you had in front of all of your attributes.
精彩评论