Reputation: 2024
I am relatively new to xslt, but I have had some luck styling a huge xml file. Now i am stuck in a place and not able to proceed. Lets say the structure of the xml file is somewhat like
<xxx>
.......
.......
.......
<Field id="123" type="fld" elem="3">
<td:value passed="true"> 25 </td:value>
</Field>
.......
.......
.......
</xxx>
I am currently in the Field node. If i do a <xsl:value of select="name()" />
it gives out "Field" and if i do a <xsl:value of select="@type" />
i get "fld". But if i do a <xsl:value of select="." />
i get the value inside <td:value>
that is 25.
My concern is that i need to get the value of the 'passed' attribute inside td:value. I am able to access the attribute if i use the following template from the current place.
<xsl:apply-templates select="*[@passed]" />
<xsl:template match="*[@passed]" >
<xsl:value-of select="@passed" />
</xsl:template>
But the problem is that the 'passed' attribute might not be there always, so i need to get to the <td:value>
node with just the nodes name.
I tried
<xsl:apply-templates select=".//td" />
<xsl:apply-templates select=".//td:value" />
<xsl:apply-templates select=".//*" />
<xsl:apply-templates select=".*" />
<xsl:apply-templates select="td" />
nothing seems to work. How do i get to that td:value node from the Field node ?
Upvotes: 0
Views: 721
Reputation: 8135
You need to declare the same namespace that is assigned to the td
prefix of td:value
in the input XML. For instance:
<foo xmlns:td="urn:td">
<Fieldid="123" type="fld" elem="3">
<td:value passed="true"> 25 </td:value>
</Field>
</foo>
The XSLT could be something like:
<xsl:template match="Field">
<xsl:if test="td:value@passed" xmlns:td="urn:td">
<xsl:value-of select="td:value"/>
</xsl:if>
</xsl:template>
The important part is that the namespace be the same as in the input document, it doesn't matter if the prefix in the XSLT document is named differently. If possible and if all XML is under your control, it should be, for clarity.
Upvotes: 2
Reputation: 70638
Just to clarify, you are currently positioned on the field element, and you are trying to select the child td:value to get its @passed attribute, but if this attribute is not there, you want to get the get the value of the element instead.
Well, what you could do is first do, is replace this
<xsl:apply-templates select="*[@passed]" />
With just this
<xsl:apply-templates select="*" />
Then, you need two matching templates; one for when the attribute is present, and one to capture other cases
<xsl:template match="Field/*[@passed]" >
<xsl:value-of select="@passed" />
</xsl:template>
<xsl:template match="Field/*" >
<xsl:value-of select="." />
</xsl:template>
When you have two templates like this, XSLT will match the more specific one first. So, if a @passed attribute is present, the first template will always be matched (even though the second template also matches it). When there is not one present, the second one will be used.
EDIT: If you don't want to specify the element name, you could replace your templates with just this...
<xsl:template match="*[@passed]" >
<xsl:value-of select="@passed" />
</xsl:template>
<xsl:template match="*" >
<xsl:value-of select="." />
</xsl:template>
However, these will start to match all elements which could affect other parts of your XSLT. So, you might have to make use of the mode parameter here
<xsl:apply-templates select="*" mode="Field" />
<xsl:template match="*[@passed]" mode="Field" >
<xsl:value-of select="@passed" />
</xsl:template>
<xsl:template match="*" mode="Field" >
<xsl:value-of select="." />
</xsl:template>
Upvotes: 1