5
votes

Is there a way of restricting a section of XSLT to a single node, so that the entire path of the node is not necessary each time?

For example...

Name: <xsl:value-of select="/root/item[@attrib=1]/name"/>
Age: <xsl:value-of select="/root/item[@attrib=1]/age"/>

This could be done via a for-each command, but I am led to believe that these should be avoided if at all possible...

<xsl:for-each select="/root/item[@attrib=1]"/>
  Name: <xsl:value-of select="name"/>
  Age: <xsl:value-of select="age"/>
</xsl:for-each>

I guess I'm asking if there is an XSLT equivalent of the VB.NET With command?

I would prefer to avoid xsl:template for readability, as the XSLT file in question is large, but happy to accept if that is the only way to do it. And if so, what is the syntax to call a particular template based on specific node?

Update

In follow up to the answer by @javram, it is possible to match separate templates based on particular attributes / nodes.

<xsl:apply-templates select="/root/item[@attrib=1]"/>
<xsl:apply-templates select="/root/item[@attrib=2]"/>

<xsl:template match="/root/item[@attrib=1]">
  Name: <xsl:value-of select="name"/>
  Age: <xsl:value-of select="age"/>
</xsl:template>

<xsl:template match="/root/item[@attrib=2]">
  Foo: <xsl:value-of select="foo"/>
</xsl:template>
4
There's nothing wrong per se with using xsl:for-each as you are doing here. In this case, it functions fine in a "with" sort of way. People counsel against using xsl:for-each to explicitly loop over something when XSLT provides better ways to do the equivalent, such as letting templates apply and match. - user663031
Downvoter... can I ask why, and after so long? - freefaller
Downvoter... no I didn't think so... you just hide behind the anonymity of SO, rather than be constructive. Thanks, thanks a lot! - freefaller

4 Answers

2
votes

The correct way would be to use a template:

<xsl:apply-templates select="/root/item[@attrib=1]"/>

.
.
.

<xsl:template match="/root/item">
     Name: <xsl:value-of select="name"/>
     Age: <xsl:value-of select="age"/>
</xsl:template>
2
votes

You may use variables:

<xsl:variable name="foo" select="/root/item[@attrib=1]" />

<xsl:value-of select="$foo/name" />
<xsl:value-of select="$foo/age" />
0
votes

In XSLT 2.0 another possible style is:

<xsl:value-of select='/root/item[@attrib=1]/
                       concat("Name: ", name, " Age: ", age)'/>
0
votes

This:

<xsl:for-each select="/root/item[@attrib=1]"/>
  Name: <xsl:value-of select="name"/>
  Age: <xsl:value-of select="age"/>
</xsl:for-each>

descends into all nodes (each matching node, one by one).

This:

<xsl:for-each select="(/root/item[@attrib=1])[1]"/>
  Name: <xsl:value-of select="name"/>
  Age: <xsl:value-of select="age"/>
</xsl:for-each>

descents into first (possibly only) matching node and is equivalent of VB.NET With statement as you wished.