Compare data of 2 xmls in xslt - xslt

I am new to XSL. Hence please help me with the below.
I have 2 xmls. I have to do the following in XSL transformation.
if Employee/EmployeeInfo/FirstName = EmployeeSegment/EmployeeSummary/GivenName and Employee/EmployeeInfo/LastName = EmployeeSegment/EmployeeSummary/Surname
employeeId = EmployeeSegment/EmployeeSummary/EmpId
XML1
<Employee>
<EmployeeInfo>
<FirstName>ABC</FirstName>
<LastName>DEF</LastName>
</EmployeeInfo>
</Employee>
XML2
<EmployeeSegment>
<EmployeeSummary>
<EmpId>1234</EmpId>
<GivenName>ABC</GivenName>
<Surname>DEF</Surname>
</EmployeeSummary>
</EmployeeSegment>
I have tried the following. It is not working.
<xsl:param name="cjEmployeeSegment" select="document('CJ_Response.xml')"/>
<xsl:for-each select="/ns3:Employee/ns3:EmployeeInfo">
<xsl:variable name="empFirstName">
<xsl:value-of select="ns1:FirstName"/>
</xsl:variable>
<xsl:variable name="empLastName">
<xsl:value-of select="ns1:LastName"/>
</xsl:variable>
<xsl:for-each select="$cjEmployeeSegment/v32:EmployeeSegment/v31:EmployeeSummary">
<xsl:if test="$empFirstName=v31:GivenName and $empLastName=v31:Surname">
<ns12:EmployeeIdentifier>
<ns12:EmployeeID>
<xsl:value-of select="v31:EmpId"/>
</ns12:EmployeeID>
</ns12:EmployeeIdentifier>
</xsl:if>
</xsl:for-each>
</xsl:for-each>

Assuming you are processing the following input:
XML
<Employee>
<EmployeeInfo>
<FirstName>ABC</FirstName>
<LastName>DEF</LastName>
</EmployeeInfo>
</Employee>
and there is another XML document named CJ_Response.xml:
<EmployeeSegment>
<EmployeeSummary>
<EmpId>1234</EmpId>
<GivenName>ABC</GivenName>
<Surname>DEF</Surname>
</EmployeeSummary>
</EmployeeSegment>
you can use the following stylesheet:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="cj_Response" select="document('CJ_Response.xml')"/>
<xsl:template match="/Employee">
<root>
<xsl:for-each select="EmployeeInfo">
<xsl:variable name="lookup" select="$cj_Response/EmployeeSegment/EmployeeSummary[GivenName = current()/FirstName and Surname = current()/LastName]" />
<xsl:if test="$lookup">
<EmployeeIdentifier>
<EmployeeID>
<xsl:value-of select="$lookup/EmpId"/>
</EmployeeID>
</EmployeeIdentifier>
</xsl:if>
</xsl:for-each>
</root>
</xsl:template>
</xsl:stylesheet>
to return:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<EmployeeIdentifier>
<EmployeeID>1234</EmployeeID>
</EmployeeIdentifier>
</root>
Of course, this will fail miserably if there are two or more employees with the same name.

Related

In XSLT replace value

I have this XML document :Now I want to replace LineNo so that the output will be line no will 1 ,2 . I have tried some thing like this.
<xsl:value-of select="replace( '000010',1)"/>
<Rder>
<Order>
<OrderNo>458</OrderNo>
<LineNo>000010</LineNo>
<SerialNO>96</SerialNO>
<VNo>543</VNo>
</Order>
<Order>
<OrderNo>458</OrderNo>
<LineNo>000020</LineNo>
<SerialNO>32</SerialNO>
<VNo>543</VNo>
</Order>
</Rder>
I want to replace the value of LineNo= 000010 ,000020 by 1,2 in XSLT below one i have tried.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:key name="orders" match="Order" use="OrderNo" />
<xsl:template match="/*">
<SalesOrders>
<xsl:for-each select="Rder/Order[generate-id() = generate-id(key('orders', OrderNo)[1])]">
<Order VNo="{VNo}" OrderNo="{OrderNo}">
<OrderLines>
<xsl:apply-templates select="key('orders', OrderNo)" />
</OrderLines>
</Order>
</xsl:for-each>
</SalesOrders>
</xsl:template>
<xsl:template match="Order">
<OrderLine LineNo="{LineNo}" SerialNO="{SerialNO}"/>
</xsl:template>
</xsl:stylesheet>
Actually I getting those lineno details in same format i have tried couple cases its doesn't giving that expected format.
Any help would be appreciated.
Why don't you do simply:
<xsl:template match="Order">
<OrderLine LineNo="{position()}" SerialNO="{SerialNO}"/>
</xsl:template>
or:
<xsl:template match="Order">
<OrderLine LineNo="{number(LineNo) div 10}" SerialNO="{SerialNO}"/>
</xsl:template>

Sort the info based on given sequence order

Please suggest how to sort the info, based on given sort sequence (Seq.xml).
Here fetching info from folder where files' name should have 'Sort##.xml' formats. Output should be sort based on DOI number as sequnce given in external file 'D:\Sort\Seq.xml'.
Input XMLs:
D:\Sort\Sort01.xml
<article>
<fm>
<title>The solar system</title>
<aug><au>Rudramuni TP</au></aug>
<doi>10.11/MPS.0.10.11</doi>
</fm>
<body><text>The text</text></body>
</article>
D:\Sort\Sort02.xml
<article>
<fm>
<title>The Galaxy</title>
<aug><au>Kishan TR</au></aug>
<doi>10.11/MPS.0.10.2</doi>
</fm>
<body><text>The text</text></body>
</article>
D:\Sort\Sort03.xml
<article>
<fm>
<title>The Pluto</title>
<aug><au>Kowshik MD</au></aug>
<doi>10.11/MPS.0.10.10</doi>
</fm>
<body><text>The text</text></body>
</article>
Sequence info in D:\Sort\Seq.xml
<root>
<toc>
<seq seq="1"><art-id>10.11/MPS.0.10.2</art-id></seq>
<seq seq="2"><art-id>10.11/MPS.0.10.11</art-id></seq>
<seq seq="3"><art-id>10.11/MPS.0.10.10</art-id></seq>
</toc>
</root>
XSLT:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes"/>
<xsl:variable name="varCollection">
<xsl:copy-of select="
collection('file:///D:/Sort/?select=Sort*.xml; recurse=yes')
[matches(document-uri(.),'Sort/Sort[0-9][0-9].xml')]"/>
</xsl:variable><!-- to fetch info from folder 'Sort*.xml' s -->
<xsl:variable name="docSeq" select="document('D:/Sort/Seq.xml')"/><!--In this file, sequnce info is there -->
<!--xsl:key name="kSeq" match="$docSeq/root/toc/seq/#seq" use="art-id"/--><!-- I tried with key, but unable to get the required sequence -->
<xsl:template match="root">
<xsl:for-each select="$varCollection/article">
<!--xsl:sort select="key('kSeq', fm/doi)"/-->
<art>
<title><xsl:value-of select="fm/title"/></title>
<Name><xsl:value-of select="fm/aug/au"/></Name>
<DOI><xsl:value-of select="fm/doi"/></DOI>
</art><xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Required Sequence
<art><title>The Galaxy</title><Name>Kishan TR</Name><DOI>10.11/MPS.0.10.2</DOI></art>
<art><title>The solar system</title><Name>Rudramuni TP</Name><DOI>10.11/MPS.0.10.11</DOI></art>
<art><title>The Pluto</title><Name>Kowshik MD</Name><DOI>10.11/MPS.0.10.10</DOI></art>
I think you want
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="varCollection" select="
collection('file:///D:/Sort/?select=Sort*.xml; recurse=yes')
[matches(document-uri(.),'Sort/Sort[0-9][0-9].xml')]"/>
<xsl:variable name="docSeq" select="document('file:///D:/Sort/Seq.xml')"/><!--In this file, sequnce info is there -->
<xsl:key name="kSeq" match="root/toc/seq" use="art-id"/>
<xsl:template match="root">
<xsl:for-each select="$varCollection/article">
<xsl:sort select="key('kSeq', fm/doi, $docSeq)/xs:integer(#seq)"/>
<art>
<title><xsl:value-of select="fm/title"/></title>
<Name><xsl:value-of select="fm/aug/au"/></Name>
<DOI><xsl:value-of select="fm/doi"/></DOI>
</art>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
You could also do this from the opposite direction:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes"/>
<xsl:variable name="varCollection">
<xsl:sequence select="collection('file:///D:/Sort/?select=Sort*.xml; recurse=yes')
[matches(document-uri(.),'Sort/Sort[0-9][0-9].xml')]"/>
</xsl:variable>
<xsl:variable name="docSeq" select="document('D:/Sort/Seq.xml')"/>
<xsl:key name="article" match="article" use="fm/doi" />
<xsl:template match="root">
<xsl:for-each select="$docSeq/root/toc/seq">
<xsl:sort select="#seq" data-type="number" order="ascending"/>
<xsl:apply-templates select="key('article', art-id, $varCollection)"/>
</xsl:for-each>
</xsl:template>
<xsl:template match="article">
<art>
<title><xsl:value-of select="fm/title"/></title>
<Name><xsl:value-of select="fm/aug/au"/></Name>
<DOI><xsl:value-of select="fm/doi"/></DOI>
</art>
</xsl:template>
</xsl:stylesheet>
Note that the output lacks a root element.

Text value of input xml element as final xslt output

I have a scenario where the input(source) xml is having an element which contains a valid well formed xml as string. I am trying to write an xslt that would give me the text value of that desired element which contains the payload xml. In essence, output should only be text of the element that contains it. Here is what I am trying, am I missing something obvious here. I am using xslt 1.0
Thanks.
Input xml:
<BatchOrders xmlns="http://Microsoft.ABCD.OracleDB/STMT">
<BatchOrdersRECORD>
<BatchOrdersRECORD>
<ActualPayload>
<PersonName>
<PersonGivenName>CaptainJack</PersonGivenName>
<PersonMiddleName>Walter</PersonMiddleName>
<PersonSurName>Sparrow</PersonSurName>
<PersonNameSuffixText>Sr.</PersonNameSuffixText>
</PersonName>
</ActualPayload>
</BatchOrdersRECORD>
</BatchOrdersRECORD>
</BatchOrders>
Xslt:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="text()|#*" name="sourcecopy" mode="xml-to-string">
<xsl:value-of select="*"/>
</xsl:template>
<xsl:template name="xml-to-string-called-template">
<xsl:param name ="param1">
<xsl:element name ="DestPayload">
<xsl:text disable-output-escaping ="yes"><![CDATA[</xsl:text>
<xsl:call-template name ="sourcecopy"/>
<xsl:text disable-output-escaping ="yes">]]></xsl:text>
</xsl:element>
</xsl:param>
</xsl:template>
</xsl:stylesheet>
Desired Output:
<PersonName>
<PersonGivenName>CaptainJack</PersonGivenName>
<PersonMiddleName>Walter</PersonMiddleName>
<PersonSurName>Sparrow</PersonSurName>
<PersonNameSuffixText>Sr.</PersonNameSuffixText>
</PersonName>
Do you really need the mode="xml-to-string"?
Change
<xsl:template match="text()|#*" name="sourcecopy" mode="xml-to-string">
<xsl:value-of select="*"/>
</xsl:template>
to
<xsl:template match="text()|#*" name="sourcecopy">
<xsl:value-of select="." disable-output-escaping ="yes"/>
</xsl:template>
Would this template suffice?

How to select element name, not value, using XSL/XSLT?

We are using XSL to convert a XML file into a pipe-delimited format.
<?xml version="1.0" encoding="UTF-8"?>
<ns:tradedata xmlns:ns="http://schemas.com/enterprise/util/extractservice/v1">
<tradedata_item>
<ORDER_ID>113632428</ORDER_ID>
<CUSIP>31393FHA7</CUSIP>
<TICKER>FHR</TICKER>
<SEC_NAME>FHR 2527 SG</SEC_NAME>
<ORDER_QTY>169249.6824</ORDER_QTY>
</tradedata_item>
<tradedata_item>
<ORDER_ID>113632434</ORDER_ID>
<CUSIP>31393G2C7</CUSIP>
<TICKER>FHR</TICKER>
<SEC_NAME>FHR 2531 ST</SEC_NAME>
<ORDER_QTY>214673.0105</ORDER_QTY>
</tradedata_item>
<tradedata_item>
<ORDER_ID>113632431</ORDER_ID>
<CUSIP>527069AH1</CUSIP>
<TICKER>LESL</TICKER>
<SEC_NAME>ZZZ_LESLIE S POOLMART INC</SEC_NAME>
<ORDER_QTY>365000.0000</ORDER_QTY>
</tradedata_item>
</ns:tradedata>
We need the first line in the output to be the column headers, and everything else would be data, like this...
ORDER_ID|CUSIP|TICKER|SEC_NAME|ORDER_QTY
1136324289|31393FHA7|FHR|FHR 2527 SG|169249.6824
1136324304|31393G2C7|FHR|FHR 2531 ST|214673.0105
We've got the XSL working to get the data, but we can't get the header to output correctly. We just select the first tradedata_item element, then iterate the element name and separate them using | characters. Here is the full XSL...
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="xsl"
version="1.0" xmlns="http://schemas.com/enterprise/util/extractservice/v1"
xmlns:o="http://schemas.com/enterprise/util/extractservice/v1" >
<!-- xsl:strip-space elements="*"/-->
<xsl:output method="text" indent="no"/>
<xsl:template match="/tradedata/tradedata_item[1]">
<xsl:for-each select="*">
<xsl:value-of select="local-name()"/>|
</xsl:for-each>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="/">
<xsl:for-each select="tradedata/tradedata_item">
<xsl:value-of select="ORDER_ID"/>|<xsl:value-of select="CUSIP"/>|<xsl:value-of select="TICKER"/>|<xsl:value-of select="SEC_NAME"/>|<xsl:value-of select="ORDER_QTY"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
The output we're seeing is just data, no header...
113632428|31393FHA7|FHR|FHR 2527 SG|169249.6824
113632430|31393G2C7|FHR|FHR 2531 ST|214673.0105
113632431|527069AH1|LESL|ZZZ_LESLIE S POOLMART INC|365000.0000
113632434|38470RAD3|GRAHAM|ZZZ_GRAHAM PACKAGING CO|595000.0000
Please disregard any namespace inconsistencies; I had to obfuscate the xml and xsl for legal reasons.
Try this :
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" indent="no"/>
<xsl:template match="/">
<xsl:for-each select="tradedata/tradedata_item[1]/*">
<xsl:value-of select="concat(name(), '|')"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Output :
ORDER_ID|CUSIP|TICKER|SEC_NAME|ORDER_QTY|
It seems pretty simple to me. Maybe your error lies elsewhere.
I tried your code.. I only changed the first template to match:
<xsl:template match="//tradedata_item[1]">
and it worked for me, i.e. got the header names.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="xsl ofi"
version="1.0" xmlns="http://schemas.com/enterprise/util/extractservice/v1"
xmlns:ofi="http://schemas.oppen.com/enterprise/util/extractservice/v1">
<xsl:output method="text" indent="no"/>
<xsl:template match="tradedata_item[position()='1']">
<xsl:for-each select="self::*">
<xsl:for-each select="child::*[position()!='5']">
<xsl:value-of select="local-name(self::*)"/>|
</xsl:for-each>
<xsl:value-of select="local-name(child::*[position()='5'])"/>
<xsl:text>
</xsl:text>
<xsl:value-of select="ORDER_ID"/>|<xsl:value-of select="CUSIP"/>|<xsl:value-of select="TICKER"/>|<xsl:value-of select="SEC_NAME"/>|<xsl:value-of select="ORDER_QTY"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
<xsl:template match="tradedata_item[position()>1]">
<xsl:for-each select="self::*">
<xsl:value-of select="ORDER_ID"/>|<xsl:value-of select="CUSIP"/>|<xsl:value-of select="TICKER"/>|<xsl:value-of select="SEC_NAME"/>|<xsl:value-of select="ORDER_QTY"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

XSL: How to concatenate nodes with conditions?

I have the following code (eg):
<response>
<parameter>
<cottage>
<cot>
<res>
<hab desc="Lakeside">
<reg cod="OB" prr="600.84>
<lwz>TR#2#AB#200.26#0#QB#OK#20120829#20120830#EU#3-0#</lwz>
<lwz>TR#2#AB#200.26#0#QB#OK#20120830#20120831#EU#3-0#</lwz>
<lwz>TR#2#AB#200.26#0#QB#OK#20120831#20120901#EU#3-0#</lwz>
I need to create a concatenated string that includes the whole of the first 'lwz' line and then the price (200.26, but it can be different in each line) for each corresponding line.
So the output, separating each line with | would be:
TR#2#AB#200.26#0#QB#OK#20120829#20120830#EU#3-0#|200.26|200.26
Thanks
This XSLT 1.0 transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="lwz[1]">
<xsl:value-of select="."/>
</xsl:template>
<xsl:template match="lwz[position() >1]">
<xsl:value-of select=
"concat('
',
substring-before(substring-after(substring-after(substring-after(.,'#'),'#'),'#'),'#')
)
"/>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
when applied on the provided text (converted to a well-formed XML document !!!):
<response>
<parameter>
<cottage>
<cot>
<res>
<hab desc="Lakeside">
<reg cod="OB" prr="600.84">
<lwz>TR#2#AB#200.26#0#QB#OK#20120829#20120830#EU#3-0#</lwz>
<lwz>TR#2#AB#200.26#0#QB#OK#20120830#20120831#EU#3-0#</lwz>
<lwz>TR#2#AB#200.26#0#QB#OK#20120831#20120901#EU#3-0#</lwz>
</reg>
</hab>
</res>
</cot>
</cottage>
</parameter>
</response>
produces the wanted, correct result:
TR#2#AB#200.26#0#QB#OK#20120829#20120830#EU#3-0#
200.26
200.26
II XSLT 2.0 solution:
This transformation:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="lwz[1]">
<xsl:value-of select="."/>
</xsl:template>
<xsl:template match="lwz[position() >1]">
<xsl:value-of select=
"concat('
', tokenize(.,'#')[4])"/>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
when applied on the above XML document, again produces the wanted, correct result. Note the use of the standard XPath 2.0 function tokenize():
TR#2#AB#200.26#0#QB#OK#20120829#20120830#EU#3-0#
200.26
200.26
You can use the XPath substring function to select substrings from your lwz node data. You don't really give much more detail about your problem, if you want a more detailed answer, perhaps provide the full XML document and your best-guess XSLT