Extracting node values using XSLT - xslt

I have an xml like below
<Envelope>
<Body>
<response>
<timestamp>
<status>
<Objectstatus>
<class>stats</class>
<Adminstate>disabled</Adminstate>
<name>abc</name>
</objectstatus>
<objectstatus>
<class>Policy</class>
<adminstate>enabled</adminstate>
<names>xyz</name>
</Objectstatus>
The response expected is stats,disabled,abc
Policy,enabled,xyz
Could you please tell me how i can do it using a stylesheet.

First thing first, make sure your child nodes have all the same name (Adminstate or adminstate, etc...), remember that it is case sensitive.
I'm also assuming you would like a HTML output, here's what you could try:
<xsl:for-each select="//Objectstatus">
<p>
<xsl:value-of select="./class"/>
<xsl:text>,</xsl:text>
<xsl:value-of select="./Adminstate"/>
<xsl:text>,</xsl:text>
<xsl:value-of select="./name"/>
</p>
</xsl:for-each>
Here's the output:
stats,disabled,abc Policy,enabled,xyz

Related

Get Line Item value from XML using XSLT

Need to get Line Item value from below XML using xslt.
Input Xml :
<Root>
<Table>
<Row1 ColumnA_1="1A" ColumnB_1="1B" ColumnC_1="1B"/>
<Row2 ColumnA_2="2A" ColumnB_2="2B" ColumnC_2="2C"/>
<Row3 ColumnA_3="3A" ColumnB_3="3B" ColumnC_3="3C"/>
<Row4 .......
<Rown>
</Table>
</Root>
we can get Tag value without loop using below code:
<xsl:value-of select="/Root/Table/Row1/#ColumnA_1"/>
<xsl:value-of select="/Root/Table/Row2/#ColumnA_2"/>
How we can get Line Item value using below loop ?
<xsl:for-each select="Root/Table">
<xsl:for-each select="./*">
<Row><xsl:value-of select="/Root/Table/*/#ColumnA_ + position()"/</Row>
</xsl:for-each>
</xsl:for-each>

Get parent node from child and rename it

I have the input bellow and I wrote some xslt that gives me an office with a specific ID but since I get the parent node I also get the tag <e>. My problem is that I don't want to have that <e> tag.
<response>
<offices>
<e>
<id>33701</id>
<name>aa</name>
</e>
.....<e></e>
</offices>
</response>
<xsl:template match="*:response/offices">
<econ:GetOfficesResponse>
<Office>
<xsl:for-each select="e/id">
<xsl:if test="text() = $office_id">
<xsl:copy-of select="parent::node()"/>
</xsl:if>
</xsl:for-each>
</Office>
</econ:GetOfficesResponse>
</xsl:template>
</xsl:stylesheet>
The response that I get:
<econ:GetOfficesResponse>
<Office>
<e>
<id>33701</id>
<name>...</name>
</e>
</Office>
The response that I want:
<econ:GetOfficesResponse>
<Office>
<id>33701</id>
<name>...</name>
</Office>
Can someone please help me with this? I/m using xslt 2.0
It seems like instead of your xsl:for-each you simply want a single <xsl:copy-of select="e[id = $office_id]/*"/>
try this code:
<xsl:template match="*:response/offices">
<econ:GetOfficesResponse>
<Office>
<xsl:for-each select="e/id">
<xsl:if test="text() = $office_id">
<xsl:copy-of select="parent::node()/child::node()"/>
</xsl:if>
</xsl:for-each>
</Office>
</econ:GetOfficesResponse>
</xsl:template>

Using XSL Choose to Substitute Empty String

I'm trying to substitute an empty value in a csv file with a number.
Here's an example:
1111111,,11222
So I tried this:
<xsl:template match="/">
<xsl:apply-templates select="//tr" />
</xsl:template>
<xsl:template match="tr">
<document>
<content name="title">
<xsl:value-of select="td[1]/text()" />
</content>
<content name="loanID">
<xsl:value-of select="td[1]/text()" />
</content>
<content name="cNumber">
<xsl:variable name="score" select="td[2]/text()" />
<xsl:choose>
<xsl:when test="$score=''">
<xsl:value-of select="550" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="td[18]/text()" />
</xsl:otherwise>
</xsl:choose>
</content>
</document>
</xsl:template>
I constantly get a null value for the cNumber node when the value is empty in the row, and I'm expecting my code to substitute the empty value for '550'. What am I doing wrong? I checked this question here: and it seems like this should work. I'm using a special application for this but my guess is the fault lies with me.
Thanks
If the td element is empty, then td/text() returns an empty sequence/node-set, and when you compare an empty sequence to '', the result is false. This is one of the reasons that many people advise against using text(). You're not interested here in the text node, you are interested in the string value of the td element, and to get that you should use
<xsl:variable name="score" select="string(td[2])" />
Your other uses of text() are also incorrect, though you're only likely to see a problem if your XML input contains comments or processing instructions. But you should get out of this coding habit, and replace
<xsl:value-of select="td[1]/text()" />
by
<xsl:value-of select="td[1]" />
As a general rule, when you see /text() in an XPath expression it's usually wrong.

Get Parent Attribute in the Current Position with XSLT

I have the following data:
<books>
<entry id="8">
<author name="tony-blair">Tony Blair</author>
</entry>
<entry id="9">
<author name="william-campbell">William Campbell</author>
</entry>
</books>
And use the following template
<xsl:template match="books/entry">
<xsl:value-of select="author"/>
<xsl:value-of select="ancestor::books/entry/#id"/>
</xsl:template>
I try to use ancestor::books/entry/#id but it results only the first id.
How to get the parent entry id while we are in the current position entry?
<xsl:template match="books/entry">
<xsl:value-of select="author"/>
<xsl:value-of select="#id"/>
</xsl:template>
Within a
<xsl:template match="books/entry">
the current context node is the entry element, so you can just use
<xsl:value-of select="#id" />
You don't need to go up to the books element and back down again.
<xsl:template match="entry">
<xsl:value-of select="author"/>
<xsl:value-of select="#id"/>
</xsl:template>
As others have said, you don't need to go up and down the tree.
books/entry is a tiny performance optimisation but it seems you're not there yet, so keep things simple and you're probably not processing massive documents anyway.

How do I get an XML node with xpath in a loop, based on an attribute with the same name as the attribute in the tree I'm searching?

I cant really formulate that better, so I'll go with an example instead:
XML:
<root>
<foo>
<bar id="1">sdf</bar>
<bar id="2">sdooo</bar
</foo>
<feng>
<heppa id="4">hihi</heppa>
<heppa id="2">sseeapeea</heppa>
<heppa id="1">....</heppa>
</feng>
</root>
XSLT:
<xsl:for-each select="/root/foo/bar">
<p>
<xsl:value-of select="." />: <xsl:value-of select="/root/feng/heppa[#id = #id]" />
</p>
</xsl:for-each>
Desired output:
<p>sdf: ....</p>
<p>sdooo: sseeapeea</p>
Actual output:
<p>sdf: hihi</p>
<p>sdooo: hihi</p>
For selecting nodes with XPath 1.0 only, you need to do a node set comparison:
/root/feng/heppa[#id=/root/foo/bar/#id]
Of course, this has NxM complexity (as the others XSLT solutions)
With XSLT 1.0 you should use keys because there are cross references:
<xsl:key name="kBarById" select="bar" use="#id"/>
<xsl:template match="/root/feng/heppa[key('kBarById',#id)]">
<p>
<xsl:value-of select="concat(key('kBarById',#id),': ',.)"/>
</p>
</xsl:template>
I assume you mean /root/foo/bar since /root/foo elements don't have id.
You're comparing the #id with itself, so of course it's true for the first node examined. You can use current() to reference the current node in an expression:
<xsl:for-each select="/root/foo/bar">
<p>
<xsl:value-of select="." />: <xsl:value-of select="/root/feng/heppa[#id = current()/#id]" />
</p>
</xsl:for-each>
Another solution is to read the id attribute into a variable.
<xsl:for-each select="/root/foo/bar">
<xsl:variable name="id" select="#id"/>
<p>
<xsl:value-of select="." />: <xsl:value-of select="/root/feng/heppa[#id = $id]" />
</p>
</xsl:for-each>
This might be handier, if your real use case is more complicated and you need to use the value of the id multiple times in this for-each section.