XSLT: Populate field alternatively in loop - xslt

I am beginner to XSLT and stuck with below conversion.
Input:
<?xml version="1.0">
<Header>
<Data>
<field1>ABC</field1>
<field2>123</field2>
</Data>
<Data>
<field1>XYZ</field1>
<field2>456</field2>
</Data>
</Header>
Output:
<?xml version="1.0">
<Header>
<Data>
<field1>ABC</field1>
<field2>123</field2>
<field1>XYZ</field1>
<field2>456</field2>
</Data>
</Header>
The main issue I am facing is populating field1 in alternative manner. I shall really appreciate any help here.
Thanks

There may be something missing from your explanation, because as presented the task is utterly trivial and requires no populating of any fields, alternatively or otherwise:
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:template match="/Header">
<Header>
<Data>
<xsl:copy-of select="Data/*"/>
</Data>
</Header>
</xsl:template>
</xsl:stylesheet>

Related

XSLT keep namespace on output

I need help preserving the namespace on XSLT transformation. I see other threads have solutions, but I don't understand them. When I use the XSLT transformation below, all the namespace disappears. Below is what I'm trying to accomplish. Any help is much appreciated! Thank you!
Before transform XML:
<?xml version='1.0' encoding='UTF-8'?>
<Worker
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:this="this.file/eib"
xmlns:is="java:com.workday.esb.intsys.xpath.ParsedIntegrationSystemFunctions"
xmlns:tv="java:com.workday.esb.intsys.TypedValue">
<Detail>
<EmployeeID>123456</EmployeeID>
<PayCode>Earning</PayCode>
<Amount>4243.20</Amount>
</Detail>
<Detail>
<EmployeeID>123456</EmployeeID>
<PayCode>Deduction</PayCode>
<Amount>2265.60</Amount>
</Detail>
</Worker>
My XSLT transformation:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" exclude-result-prefixes="xsl wd is xsd this env"
xmlns:wd="urn:com.workday/bsvc"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:is="java:com.workday.esb.intsys.xpath.ParsedIntegrationSystemFunctions"
xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:this="urn:this-stylesheet">
<xsl:output indent="yes" method="xml"/>
<xsl:template match="/">
<xsl:copy>
<Worker>
<xsl:for-each select="Worker" >
<Detail>
<EmployeeID><xsl:value-of select="Detail[(PayCode ='Earning')]/EmployeeID"/></EmployeeID>
<PayCode><xsl:value-of select="Detail[(PayCode ='Earning')]/PayCode"/></PayCode>
<Amount><xsl:value-of select="Detail[(PayCode ='Earning') and (string-length(Amount) > 0)]/Amount"/></Amount>
</Detail>
</xsl:for-each>
</Worker>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Desired output:
<?xml version="1.0" encoding="UTF-8"?>
<Worker
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:this="this.file/eib"
xmlns:is="java:com.workday.esb.intsys.xpath.ParsedIntegrationSystemFunctions"
xmlns:tv="java:com.workday.esb.intsys.TypedValue">
<Detail>
<EmployeeID>123456</EmployeeID>
<PayCode>Earning</PayCode>
<Amount>4243.20</Amount>
</Detail>
</Worker>
At least in XSLT 2.0 (the version you used), namespaces disappear because you used exclude-result-prefixes attribute.
Just remove it and all namespaces included in your XSLT sheet, except for xsl, will be presented in the output, in the order of appearance.
But if you decided to omit all namespaces, it is easier to write exclude-result-prefixes="#all", instead of writing them again.
I can see no good reason to keep namespace declarations that are not used in your output. But if you really want to have them, why don't you simply copy them (as part of their parent element) - for example:
XSLT
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/Worker">
<xsl:copy>
<xsl:copy-of select="Detail[PayCode ='Earning']"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
When this is applied to your input example, the result will be:
<?xml version="1.0" encoding="UTF-8"?>
<Worker xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:this="this.file/eib"
xmlns:is="java:com.workday.esb.intsys.xpath.ParsedIntegrationSystemFunctions"
xmlns:tv="java:com.workday.esb.intsys.TypedValue">
<Detail>
<EmployeeID>123456</EmployeeID>
<PayCode>Earning</PayCode>
<Amount>4243.20</Amount>
</Detail>
</Worker>
Demo: http://xsltransform.net/gVhD8Qt

xslt remove string and special character from number in xml

During xslt transformation, I have tried to clean string and special from customer number, but it doesnt work. I need to remove c: or s: from the number. Thanks :)
Xml File 1
<Data>
<Request>
<CustNo>c:222</CustNo>
</Request>
</Data>
Xml File 2
<Data>
<Request>
<CustNo>s:333</CustNo>
</Request>
</Data>
XSLT
<?xml version="1.0" encoding="iso-8859-1" ?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xdt="http://www.w3.org/2005/xpath-datatypes" >
<xsl:output method="xml" version="1.0" indent="yes"/>
<xsl:template match="Request" >
<TestPayment>
<Transactions>
<Transaction custno="{CustNo}" >
</Transaction>
</Transactions>
</TestPayment>
</xsl:template>
<xsl:template match="Request/CustNo">
<xsl:value-of select="regex=(^c:[a-zA-Z0-9]*$,^s:[a-zA-Z0-9]*$ )"/>
</xsl:template>
</xsl:template>
</xsl:stylesheet>
Result of Xml File 1:
<?xml version="1.0" encoding="utf-8"?>
<TestPayment>
<Transactions>
<Transaction custno="222">
</Transaction>
</Transactions>
</TestPayment>
Result of Xml File 2:
<?xml version="1.0" encoding="utf-8"?>
<TestPayment>
<Transactions>
<Transaction custno="333">
</Transaction>
</Transactions>
</TestPayment>
In XSLT 2.0, you could do simply:
replace(CustNo, '\D', '')
to remove any non-digit characters.
Even in XSLT 1.0, you could use:
substring-after(CustNo, ':')
to accommodate both your examples.
why don't you try a double-translate function?
<Transaction custno="{translate(CustNo, translate(CustNo, '0123456789', ''), '')}" >

XSLT for picking the first detail corresponding to one field

I am writing xslt for filtering the data based on one of the fields.
Here is my input xml:
<?xml version="1.0" encoding="UTF-8"?>
<Consumer>
<header>
<msfnm>MSFNM</msfnm>
<mslnm>MSLNM</mslnm>
<msmnm>MSMNM</msmnm>
<msssn>MSSSN</msssn>
<csscstno>CSSCSTNO</csscstno>
<msact>MSACT</msact>
</header>
<data>
<msfnm>Nitin</msfnm>
<mslnm>Jain</mslnm>
<msmnm/>
<msssn>123</msssn>
<csscstno>111</csscstno>
<msact>1234</msact>
</data>
<data>
<msfnm>Nitin1</msfnm>
<mslnm>Jain1</mslnm>
<msmnm>L1</msmnm>
<msssn>1233</msssn>
<csscstno>111</csscstno>
<msact>1233556</msact>
</data>
<data>
<msfnm>Nitin2</msfnm>
<mslnm>Jain2</mslnm>
<msmnm>L1</msmnm>
<msssn>1234</msssn>
<csscstno>123</csscstno>
<msact>12334256</msact>
</data>
<data>
<msfnm>Nitin</msfnm>
<mslnm>Jain</mslnm>
<msmnm/>
<msssn>123</msssn>
<csscstno>111</csscstno>
<msact>1234</msact>
</data>
and I want my output xml should be like
<?xml version="1.0" encoding="UTF-8"?>
<Consumer>
<data>
<msfnm>Nitin</msfnm>
<mslnm>Jain</mslnm>
<msmnm/>
<msssn>123</msssn>
<csscstno>111</csscstno>
<msact>1234</msact>
</data>
<data>
<msfnm>Nitin2</msfnm>
<mslnm>Jain2</mslnm>
<msmnm>L1</msmnm>
<msssn>1234</msssn>
<csscstno>123</csscstno>
<msact>12334256</msact>
</data>
</Consumer>
Condition: basically what I want, to take first occurrence of csscstno only. If in next occurrence, csscstno is same, then the whole set should be rejected.
My xslt:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xml>
<xsl:for-each select="/Consumer/data">
<Consumer>
<msfnm><xsl:value-of select="msfnm"/></msfnm>
<mslnm><xsl:value-of select="mslnm"/></mslnm>
<msmnm><xsl:value-of select="msmnm"/></msmnm>
<msssn><xsl:value-of select="msssn"/></msssn>
<xsl:if test="position()=1">
<csscstno><xsl:value-of select="csscstno"/></csscstno>
</xsl:if>
<msact><xsl:value-of select="msact"/></msact>
</Consumer>
</xsl:for-each>
</xml>
</xsl:template>
</xsl:stylesheet>
This is not working. Let me know, what I am doing wrong here.
You can use keys. Just like the stylesheet below:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes" />
<!-- create a key for your target node -->
<xsl:key name="Customer_No" match="csscstno" use="."/>
<!-- copy only the 1st matched keys in the output -->
<xsl:template match="/">
<Consumer>
<xsl:copy-of select="Consumer/data[count(csscstno | key('Customer_No', csscstno)[1]) = 1]"/>
<!-- or you can use the following line instead
<xsl:copy-of select="Consumer/data[generate-id(csscstno) = generate-id(key('Customer_No', csscstno)[1])]"/>
-->
</Consumer>
</xsl:template>
</xsl:transform>
when this is applied to your input XML, the result is:
<?xml version="1.0" encoding="utf-8"?>
<Consumer>
<data>
<msfnm>Nitin</msfnm>
<mslnm>Jain</mslnm>
<msmnm/>
<msssn>123</msssn>
<csscstno>111</csscstno>
<msact>1234</msact>
</data>
<data>
<msfnm>Nitin2</msfnm>
<mslnm>Jain2</mslnm>
<msmnm>L1</msmnm>
<msssn>1234</msssn>
<csscstno>123</csscstno>
<msact>12334256</msact>
</data>
</Consumer>
Or, you can use keys for grouping data by csscstno to get the first occurence. Also, You can use a copy-of to select "data":
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="dataByCsscstno" match = "data" use = "csscstno"/>
<xsl:template match="/">
<Consumer>
<xsl:copy-of select="/Consumer/data[generate-id() = generate-id(key('dataByCsscstno', csscstno)[1])]"/>
</Consumer>
</xsl:template>
</xsl:stylesheet>
Eventually I have found another way, which is working as expected.
Here is my xslt:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xml>
<xsl:for-each-group select="/Consumer/data" group-by="csscstno">
<xsl:copy-of select="current-group()[1]"/>
</xsl:for-each-group>
</xml>
</xsl:template>
</xsl:stylesheet>

XSLT: why the XSLT is not generating output when there are only outer XSL tags

My real code is not this, but the problem that i am stating here applies to my real code.
XML:
<?xml version="1.0" encoding="UTF-8"?>
<books>
<book.child.1>
<title>charithram</title>
<author>sarika</author>
</book.child.1>
<book.child.2>
<title>doublebell</title>
<author>psudarsanan</author>
</book.child.2>
</books>
XSLT 1:
<?xml version="1.0" encoding="ISO-8859-1"?>
<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:template match="/">
<xsl:for-each select="books/*">
<newbook>
<title>
<xsl:value-of select="title" />
</title>
</newbook>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
There in no output generated for this XSLT. I am trying using online tool: http://www.freeformatter.com/xsl-transformer.html
I could not understand what was wrong, Finally when I modified the XSLT like as written below,
XSLT 2:
<?xml version="1.0" encoding="ISO-8859-1"?>
<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:template match="/">
<mytag>
<xsl:for-each select="books/*">
<newbook>
<title>
<xsl:value-of select="title" />
</title>
</newbook>
</xsl:for-each>
</mytag>
</xsl:template>
</xsl:stylesheet>
The output is generated in this case:
outputXML:
<?xml version="1.0" encoding="UTF-8"?>
<mytag>
<newbook>
<title>charithram</title>
</newbook>
<newbook>
<title>doublebell</title>
</newbook>
</mytag>
Can you please explain why is this behavior?
Also I don't know how exactly to ask this question, so please edit or let me know if i need to change the question title.
Your first XSLT will theoretically produce the output
<?xml version="1.0" encoding="UTF-8"?>
<newbook>
<title>charithram</title>
</newbook>
<newbook>
<title>doublebell</title>
</newbook>
But that output is not valid XML, because it has 2 root tags, which is not well-formed XML.
In this situation, you have probably the following choices
specify a root element like you did in XSLT 2
change the output from XML to TEXT, but be aware that any XML program will not be able to read the output

xslt transform xml to xml how to get attibutes of an entity?

I want to transform an xml to naother xml, with xstl
I have an entity <AAA id="e1" ts=" bb">
How can i get this entity with the attributes in my new xml file?
The <xsl:copy-of> element can be used to accomplish what you're getting after.
When this XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output omit-xml-declaration="no" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<xsl:copy-of select="AAA" />
</xsl:template>
</xsl:stylesheet>
...is run against the following sample XML:
<t>
<AAA id="e1" ts=" bb" />
</t>
...the wanted result is produced:
<?xml version="1.0" encoding="UTF-8"?>
<AAA id="e1" ts=" bb" />