Get Line Item value from XML using XSLT - 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>

Related

How to pass variable name inside for-each loop in xslt

I'm new to Xslt I'm reading xml data using xslt. for example
<head>
<root>
<data>
<Name>xxx</Name>
<age>10</age>
</data>
<data>
<Name>yyy</Name>
<age>20</age>
</data>
<data>
<Name>zzz</Name>
<age>15</age>
</data>
</root>
</head>
When I tried use below xslt
<xsl:template match="head">
<xsl:element name="Root1">
<xsl:for-each select="//head/root/data">
<xsl:element name="name">
<xsl:value-of select="$select_Name"/>
</xsl:element>
<xsl:element name="age">
<xsl:value-of select="$select_age"/>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:template>
My c# code is
XslTransform xsl=new XslTransform();
xsl.Load("xsltfile");
xsl.Transform("inputxml.xml","outputxml.xml");
I'm not getting proper output when i use the above xslt file. whereas when I give the xpath of the element to a variable in another xslt file and include the xslt into this xslt and pass variable name instead of hardcoded value <xsl:value-of select="$select_Name"/> like this whereas $name is declared as <xsl:variable name="select_Name" select="//head/root/data/Name"/> im getting the value of name for the field of Age. Anyone faced this kind of issue? or can you share how to pass the variable name instead of element name for the value inside for-each loop?

Iterating through collections returned from java call using for-each

I'm rewriting some XSLT 2.0 templates to make them XSLT 1.0 compatible (Xalan processor). We are using iterations through collections got from java call. But if I try to iterate these collections using for-each and Xalan I am getting
Can not convert #UNKNOWN (java.util.LinkedHashMap) to NodeList!
Is there any way how to do this or is this XSLT 2.0 only? In other words: do I need to convert all collections to NodeSets on my own? Seems that nodeset extension is not the case because it converts the collection to one item nodeset containing all items of original collection.
EDIT:
Formerly we're using Saxon, please see template fragment
<xsl:variable name="profilesTable" select="javaEagle:getAllProfileInfo()"/>
<xsl:variable name="profilesList" select="javaEagle:getProfileList()"/>
<xsl:variable name="loopInc" select="0"/>
<xsl:variable name="profileSize" select="set:size($profilesList)"/>
<xsl:if test="map:size($profilesTable) > 0">
<table>
<tgroup cols="{$profileSize}">
<colspec colnum="propertyName" colname="propertyName" colwidth="1*"/>
<xsl:for-each select="$profilesList">
<xsl:variable name="loopInc" select="$loopInc + 1" />
<colspec colnum="{$loopInc}" colname="col{$loopInc}" colwidth="1*"/>
</xsl:for-each>
<thead>
<row>
<entry valign="top">Module Property Name</entry>
<xsl:for-each select="$profilesList">
<entry valign="top"><xsl:value-of select="."/></entry>
</xsl:for-each>
</row>
</thead>
<tbody>
<xsl:for-each select="common:node-set(map:keySet($profilesTable))">
<xsl:variable name="key" select="."/>
<row>
<entry id="{$key}" namest="col1" nameend="col{$profileSize}" align="left"><b><xsl:value-of select="$key"/></b></entry>
<xsl:variable name="properties" select="map:get($profilesTable, string($key))"/>
Problematic part of code is this:
<xsl:for-each select="common:node-set(map:keySet($profilesTable))">
<xsl:variable name="key" select="."/>
... do somenthing with keys
$profilesTable is HashMap returned from java call.
Without common:nodeset extension I am getting error
Can not convert #UNKNOWN (java.util.LinkedHashMap) to NodeList!
With common:nodeset it seems loop goes over the whole nodeset as one item.
So the question is how to iterate through keys of returned hashmap using xalan processor.
EDIT2:
Reduced example:
<xsl:template match='/'>
<xsl:variable name="profilesTable" select="CustomFunctionsEagle:getAllProfileInfo()"/>
<xsl:if test="map:size($profilesTable) > 0">
<table>
<tbody>
<xsl:variable name="keys" select="common:node-set(map:keySet($profilesTable))"/>
<AllKeys><xsl:value-of select="$keys"/></AllKeys>
<xsl:for-each select="$keys/*">
<xsl:for-each select="/">
<GlobalVariable><xsl:value-of select="."/></GlobalVariable>
</xsl:for-each>
</xsl:for-each>
</tbody>
</table>
</xsl:if>
</xsl:template>
Output:
<?xml version="1.0" encoding="utf-8"?>
<table>
<tbody>
<AllKeys>[/AccountState/BW.HOST.NAME, .... another keys]</AllKeys>
</tbody>
</table>
Expected:
<table>
<tbody>
<AllKeys>[/AccountState/BW.HOST.NAME, .... another keys]</AllKeys>
<GlobalVariable>/AccountState/BW.HOST.NAME</GlobalVariable>
<GlobalVariable>... another keys</GlobalVariable>
</tbody>
</table>

Find preceding-sibling of the parent element in xslt

<p>
<p1>c</p1>
<a languageCode="en">a1</a>
<a languageCode="de">a2</a>
<ca>
<cc>056</cc>
<cs>BE-VAN</cs>
<cs>BG-VLI</cs>
<cs>BG-VLI</cs>
</ca>
<ca>
<cc>056</cc>
<cs>BE-VAN</cs>
<cs>BG-VLI</cs>
<cs>BG-VLI</cs>
</ca>
</p>
i tried this does not work:
<xsl:for-each select="p/ca/*">
<xsl:if test="not(preceding-sibling::*[1]/name() = local-name())">
<precedingParent n="{preceding-sibling::*[1]/parent::*/name()}"></precedingParent>
</xsl:if>
</xsl:for-each>
but expected
output should be:
<precedingParent n="a"></precedingParent>
I am looping in ca and for instance in first occurence of cs
If a want to find the preceding sibling of the parent for parent ca for element cs ? how do i do it?
The expression you are looking for is ../preceding-sibling::*[1]/name(). For example,
<xsl:for-each select="p/ca/*">
<xsl:if test="not(preceding-sibling::*[1]/name() = local-name())">
<precedingParent n="{../preceding-sibling::*[1]/name()}"></precedingParent>
</xsl:if>
</xsl:for-each>
Note that name(../preceding-sibling::*[1]) would also work (in XSLT 1.0 and XSLT 2.0).
On the other hand, you could be slightly more efficient by having a nested loop, and getting the preceding value before selecting the child elements, to save it having to be recalculated each time:
<xsl:for-each select="p/ca">
<xsl:variable name="precedingParent" select="name(preceding-sibling::*[1])" />
<xsl:for-each select="*">
<xsl:if test="not(preceding-sibling::*[1]/name() = local-name())">
<precedingParent n="{$precedingParent}"></precedingParent>
</xsl:if>
</xsl:for-each>
</xsl:for-each>

Extracting node values using 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

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.