Transformation using XSLT - xslt-1.0

Need help to convert SOAP message to XML:
The element "externalID"can occur multiple time so based on "externalID" this element need to generate "Detail" tag in output XML.
Need some code sample to convert this SOAP message to desired output XML
Input SOAP Message:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:mem="http://example.com/vc/types/attachments">
<soapenv:Header/>
<soapenv:Body>
<mem:payRequest>
<payload>
<uuid>?</uuid>
<umi>?</umi>
<externalID>
<externalLineID></externalLineID>
<groupNo>?</groupNo>
<payeeCd>dfsdfsfd</payeeCd>
<paymntAmt>?</paymntAmt>
<acctCd>dfafa</acctCd>
<transID>fasf</transID>
<errCD>?</errCD>
<errMessage>?</errMessage>
</externalID>
<externalID>
<externalLineID>?</externalLineID>
<groupNo>?</groupNo>
<payeeCd>dfsdfsfd</payeeCd>
<paymntAmt>?</paymntAmt>
<acctCd>dfafa</acctCd>
<transID>fasf</transID>
<errCD>?</errCD>
<errMessage>?</errMessage>
</externalID>
<errCD>?</errCD>
<errMessage>?</errMe`enter code here`ssage>
</payload>
</mem:payRequest>
</soapenv:Body>
</soapenv:Envelope>
==============
Desired Output XML:
<payRequest>
<Detail>
<uuid>?</uuid>
<umd>?</umd>
<claimNumber></claimNumber>
<claimLineNumber>?</claimLineNumber>
<dd>1</dd>
<claimStatus></claimStatus>
<clientNumber></clientNumber>
<payMode>Other</payMode>
<paymentAmount></paymentAmount>
<accountCode></accountCode>
<transactionId></transactionId>
<errorCode></errorCode>
<returnCode></returnCode>
</Detail>
<Detail>
<uuid>?</uuid>
<umd>?</umd>
<claimNumber></claimNumber>
<claimLineNumber>?</claimLineNumber>
<dd>1</dd>
<claimStatus></claimStatus>
<clientNumber></clientNumber>
<payMode>Other</payMode>
<paymentAmount></paymentAmount>
<accountCode></accountCode>
<transactionId></transactionId>
<errorCode></errorCode>
<returnCode></returnCode>
</Detail>
</payRequest>

I'd suggest you try it along these lines:
<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:strip-space elements="*"/>
<xsl:template match="/">
<payRequest>
<xsl:for-each select="//externalID">
<Detail>
<uuid>
<xsl:value-of select="../uuid"/>
</uuid>
<umd>
<xsl:value-of select="../umi"/>
</umd>
<claimNumber>
<xsl:value-of select="XYZ"/>
</claimNumber>
<claimLineNumber>
<xsl:value-of select="externalLineID"/>
</claimLineNumber>
<dd>
<xsl:value-of select="XYZ"/>
</dd>
<claimStatus>
<xsl:value-of select="XYZ"/>
</claimStatus>
<clientNumber>
<xsl:value-of select="XYZ"/>
</clientNumber>
<payMode>
<xsl:value-of select="XYZ"/>
</payMode>
<paymentAmount>
<xsl:value-of select="paymntAmt"/>
</paymentAmount>
<accountCode>
<xsl:value-of select="XYZ"/>
</accountCode>
<transactionId>
<xsl:value-of select="transID"/>
</transactionId>
<errorCode>
<xsl:value-of select="errCD"/>
</errorCode>
<returnCode>
<xsl:value-of select="XYZ"/>
</returnCode>
</Detail>
</xsl:for-each>
</payRequest>
</xsl:template>
</xsl:stylesheet>
You did not provide any information regarding which source nodes are supposed to provide the data for the result. I have tried to guess a few and used XYZ as a placeholder for the others.
Note: you should never have to use a hack like *[local-name()='externalID'].

Related

XSLT 1.0: How to determine the position of a node based on the value

thanks for taking the time!
I am trying to get the position of a node based on its value, so that I can then get corresponding entries. Please let me show you with an example, it will be easier to explain.
Here is the source XML:
<?xml version="1.0" encoding="UTF-8"?>
<sampleSourceXML>
<Table>
<Header>
<Column>Name</Column>
<Column>Surname</Column>
<Column>Title</Column>
</Header>
<Body>
<Row>
<Entry>James</Entry>
<Entry>Bond</Entry>
<Entry>Mr</Entry>
</Row>
<Row>
<Entry>Harry</Entry>
<Entry>Potter</Entry>
<Entry>Mr</Entry>
</Row>
</Body>
</Table>
</sampleSourceXML>
This is the resulting XML that I would like to achieve:
<?xml version="1.0" encoding="UTF-8"?>
<sampleResultXML>
<Person>
<FirstName>James</FirstName>
<LastName>Bond</LastName>
<Title>Mr</Title>
</Person>
<Person>
<FirstName>Harry</FirstName>
<LastName>Potter</LastName>
<Title>Mr</Title>
</Person>
</sampleResultXML>
I tried it with this XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:element name="sampleResultXML">
<xsl:for-each select="sampleSourceXML/Table/Rows/Row">
<xsl:element name="Person">
<xsl:element name="FirstName">
<xsl:value-of select="./Entry[1]/text()"></xsl:value-of>
</xsl:element>
<xsl:element name="LastName">
<xsl:value-of select="./Entry[2]/text()"></xsl:value-of>
</xsl:element>
<xsl:element name="Title">
<xsl:value-of select="./Entry[3]/text()"></xsl:value-of>
</xsl:element>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
This works.
But! The source XML can have a different order. For example the Title element can be above the Name element. So the hardcoded position in my XSLT (e.g. Entry[3]) will not work any more.
The header order and the entry order are always corresponding. So if the Column Title is in position 3, so will be the corresponding row.
So I need a way to get the position of, let's say, the Title element dynamically. So I have to go through the Column elements until I reach the one with value "Title". This position I thought I'd save in a variable (e.g. Position_Title) so that I can fill the value later like so:
<xsl:element name="Title">
<xsl:value-of select="./Entry[$Position_Title]/text()"></xsl:value-of>
</xsl:element>
However I haven't been able to find a way to do this...
Do you have any ideas how I can achieve this?
Thanks!
Nick
EDIT: Thanks to Michael for the help! Here is the final XSLT I'm using:
<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="/sampleSourceXML">
<xsl:variable name="cols" select="Table/Header/Column"/>
<sampleResultXML>
<xsl:for-each select="Table/Body/Row">
<Person>
<xsl:for-each select="Entry">
<xsl:variable name="i" select="position()"/>
<xsl:variable name="elementName">
<xsl:choose>
<xsl:when test="$cols[$i]='Name'">
<xsl:value-of select="'FirstName'"/>
</xsl:when>
<xsl:when test="$cols[$i]='Surname'">
<xsl:value-of select="'LastName'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$cols[$i]"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:element name="{$elementName}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
</Person>
</xsl:for-each>
</sampleResultXML>
</xsl:template>
</xsl:stylesheet>
So I need a way to get the position of, let's say, the Title element dynamically. So I have to go through the Column elements until I reach the one with value "Title". This position I thought I'd save in a variable (e.g. Position_Title) so that I can fill the value later like so:
I think it could be much simpler if you do it from the opposite direction. Try:
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="/sampleSourceXML">
<xsl:variable name="cols" select="Table/Header/Column" />
<sampleResultXML>
<xsl:for-each select="Table/Body/Row">
<Person>
<xsl:for-each select="Entry">
<xsl:variable name="i" select="position()" />
<xsl:element name="{$cols[$i]}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
</Person>
</xsl:for-each>
</sampleResultXML>
</xsl:template>
</xsl:stylesheet>

xslt 3.0 xsl:evaluate example

For the following xml document:
<company>
<employee>
<name>John Andrews</name>
<age>23</age>
<salary>4000</salary>
<division>Accounting</division>
</employee>
</company>
I have the xsl like
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:value-of select="company/employee/name"/>
<xsl:variable name="test">
<xsl:text>company/employee/name</xsl:text>
</xsl:variable>
<xsl:evaluate xpath="$test"/>
</xsl:template>
</xsl:stylesheet>
How can I use $test variable in xsl:evaluate in order to get the same result as in the:
<xsl:value-of select="company/employee/name"/>
Is it possible?
You need to set the context item with e.g.
<xsl:evaluate xpath="$test" context-item="."/>

xslt nested transformation : unable to transnform

I am learning XSLT and trying to transform below xml. But couldn't achieve the task
<sample id="7">
<land1 id="8">
<owner>TOMMY</owner>
<type>INDIVIDUAL</type>
<hint>TOM_INDIVIDUAL</hint>
<date>12.02.2014</date>
<text>land details</text>
<number>1</number>
<cost>WIDERRUFLICH</cost>
</land1>
</sample>
and trying to convert above into
<table name="sample">
<tablename="land1">
<rel name="owner" value="TOMMY"/>
<rel name="type" value="INDIVIDUAL"/>
<rel name="<hint" value="TOM_INDIVIDUAL"/>
<rel name="date" value="12.02.2014"/>
<rel name="details" value="land details"/>
<rel name="number" value="1"/>
<rel name="cost" value="25%"/>
</table>
</table>
I tried below to generate the same, but it's not working.
<?xml version="1.0" encoding="UTF-8"?>
<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="*">
<xsl:if test="current().count(*)>0">
<xsl:element name="table">
<xsl:attribute name="name">
<xsl:value-of select="name(.)"/>
</xsl:attribute>
<xsl:apply-templates select="/"
</xsl:element>
</xsl:if>
<xsl:if test="current().count(*)=0">
<xsl:element name="rel">
<xsl:attribute name="name">
<xsl:value-of select="name(.)"/>
</xsl:attribute>
<xsl:attribute name="value">
<xsl:value-of select="current()"/>
</xsl:attribute>
</xsl:element>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Can someone please let me know where I am doing wrong?
Can someone please let me know where I am doing wrong?
Well, for one thing, current().count(*)>0 is not a valid expression.
And you have <xsl:apply-templates select="/" without closing the tag. Which may be a good thing - because if it worked, it would have created an infinite loop.
I also don't understand the overall logic of your approach. Couldn't you do simply:
<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:strip-space elements="*"/>
<xsl:template match="*[*]">
<table name="{name()}">
<xsl:apply-templates/>
</table>
</xsl:template>
<xsl:template match="*">
<rel name="{name()}" value="{.}"/>
</xsl:template>
</xsl:stylesheet>
Added:
every element with an attribute should also be a table. For example,
in the above xml, <land1 id="8"> has children and your logic works
fine. But my inout can also contain <land1 id="8"/>. Now even though
it doesn't have any child elements, still element name has to be
considered as Table
Then use:
<xsl:template match="*[#*]">
instead of:
<xsl:template match="*[*]">

getting namespace uri by giving prefix in xslt

I am using xsl 1.0. I need to get the namespace uri from prefix.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:a1="http://example.com/arthemetic/integers/a1">
<soapenv:Header>
</soapenv:Header>
<soapenv:Body>
<a1:add>
</a1:add>
</soapenv:Body>
</soapenv:Envelope>
I want to get the namespace uri for prefix a1 is http://example.com/arthemetic/integers/v1
Here is the code that i am trying out,
<xsl:template match="/">
<xsl:variable name="operationName">
<xsl:value-of
select="name(/*[local-name()='Envelope']/*[local-name()='Body']/*[1])"></xsl:value-of>
</xsl:variable>
<xsl:variable name="prefix">
<xsl:value-of select="substring-before($operationName, ':')"></xsl:value-of>
</xsl:variable>
<xsl:variable name="ns-node"
select="namespace::node()[.= $prefix]" />
dfadsfdfadsf
<xsl:value-of select="$ns-node" />
</xsl:template>
</xsl:stylesheet>
But I am not receiving the namespace.
Use:
<xsl:value-of select="/*/namespace::a1"/>
Here is a complete transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:value-of select="/*/namespace::a1"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the provided XML document:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:a1="http://abc.com/arthemetic/integers/a1">
<soapenv:Header></soapenv:Header>
<soapenv:Body>
<a1:add></a1:add>
</soapenv:Body>
</soapenv:Envelope>
the wanted, correct result is produced:
http://abc.com/arthemetic/integers/a1

XSL 1.0 - Hiding Child nodes when child element is Null

I have been trying to make child elements of my structure hide based upon them being empty.
From reading other posts I found this Remove parent node if a child node is empty but I don't understand it enough to implement it in my XSL. I have had a try at applying the linked post to my XSL but it does not make the desired changes to my output.
So my XML is like this:
<?xml version="1.0" encoding="UTF-8" ?>
<exchange>
<sce>
<sce.srs>
<sce_scjc.sce.srs>140008305/1</sce_scjc.sce.srs>
<sce_seq2.sce.srs>01</sce_seq2.sce.srs>
<sce_stuc.sce.srs>140008305</sce_stuc.sce.srs>
<spr>
<spr.cams>
<spr_code.spr.cams>140008305/1</spr_code.spr.cams>
<prs_code.spr.cams>77711925</prs_code.spr.cams>
<prs>
<prs.mensys>
<prs_code.prs.mensys>77711925</prs_code.prs.mensys>
<prs_name.prs.mensys>Johan</prs_name.prs.mensys>
</prs.mensys>
</prs>
</spr.cams>
</spr>
</sce.srs>
<sce.srs>
<sce_scjc.sce.srs>151516736/1</sce_scjc.sce.srs>
<sce_seq2.sce.srs>01</sce_seq2.sce.srs>
<sce_stuc.sce.srs>151516736</sce_stuc.sce.srs>
<spr>
<spr.cams>
<spr_code.spr.cams>151516736/1</spr_code.spr.cams>
<prs_code.spr.cams>77709062</prs_code.spr.cams>
<prs>
<prs.mensys>
<prs_code.prs.mensys>77709062</prs_code.prs.mensys>
<prs_name.prs.mensys>Evangelia</prs_name.prs.mensys>
</prs.mensys>
</prs>
</spr.cams>
</spr>
</sce.srs>
<sce.srs>
<sce_scjc.sce.srs>150052468/1</sce_scjc.sce.srs>
<sce_seq2.sce.srs>01</sce_seq2.sce.srs>
<sce_stuc.sce.srs>150052468</sce_stuc.sce.srs>
<spr>
<spr.cams>
<spr_code.spr.cams>150052468/1</spr_code.spr.cams>
<prs_code.spr.cams/>
</spr.cams>
</spr>
</sce.srs>
</sce>
</exchange>
And my XSL looks like the passaage below. I have a nil element template that I added in as I thought looking for a value was easier than looking for a nulll so happy for it to come out if not needed.
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" exclude-result-prefixes="xd" version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/exchange/sce">
<ImportTask>
<EntityRelationshipEntities>
<xsl:apply-templates select="node()|#*"/>
</EntityRelationshipEntities>
</ImportTask>
</xsl:template>
<xsl:template name="nilElement">
<xsl:param name="value"/>
<xsl:choose>
<xsl:when test="string($value)">
<xsl:value-of select="$value"/>
</xsl:when>
<xsl:otherwise>
<xsl:attribute name="xsi:nil" namespace="http://www.w3.org/2001/XMLSchema-instance">True</xsl:attribute>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="sce.srs[not(*/AttributeValue[not(#AttributeValue='True')])]">
<xsl:for-each select="spr/spr.cams">
<EntityRelationshipEntity>
<ErRef>ERREF_21</ErRef>
<EntityCode><xsl:value-of select="../../sce_stuc.sce.srs"/></EntityCode>
<AttributeValue>
<xsl:call-template name="nilElement">
<xsl:with-param name="value" select="prs/prs.mensys/prs_name.prs.mensys"/>
</xsl:call-template>
</AttributeValue>
<Action>VALUEONLY</Action>
</EntityRelationshipEntity>
</xsl:for-each>
</xsl:template>
<xsl:template match="AttributeValue[#AttributeValue = 'True']"/>
</xsl:stylesheet>
So this currently gives me:
<ImportTask xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<EntityRelationshipEntities>
<EntityRelationshipEntity>
<ErRef>ERREF_21</ErRef>
<EntityCode>151514490</EntityCode>
<AttributeValue xsi:nil="True"/>
<Action>VALUEONLY</Action>
</EntityRelationshipEntity>
<EntityRelationshipEntity>
<ErRef>ERREF_21</ErRef>
<EntityCode>140008305</EntityCode>
<AttributeValue>Johan</AttributeValue>
<Action>VALUEONLY</Action>
</EntityRelationshipEntity>
<EntityRelationshipEntity>
<EntityCode>151516736</EntityCode>
<AttributeValue>Evangelia</AttributeValue>
<Action>VALUEONLY</Action>
</EntityRelationshipEntity>
</EntityRelationshipEntities>
</ImportTask>
What I would like to produce is out those where is not null. This would mean that the child below is not output:
<EntityRelationshipEntity>
<ErRef>ERREF_21</ErRef>
<EntityCode>151514490</EntityCode>
<AttributeValue xsi:nil="True"/>
<Action>VALUEONLY</Action>
</EntityRelationshipEntity>
But the others would be output something like this:
<ImportTask xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<EntityRelationshipEntities>
<EntityRelationshipEntity>
<ErRef>ERREF_21</ErRef>
<EntityCode>140008305</EntityCode>
<AttributeValue>Johan</AttributeValue>
<Action>VALUEONLY</Action>
</EntityRelationshipEntity>
<EntityRelationshipEntity>
<EntityCode>151516736</EntityCode>
<AttributeValue>Evangelia</AttributeValue>
<Action>VALUEONLY</Action>
</EntityRelationshipEntity>
</EntityRelationshipEntities>
</ImportTask>
Can someone help me apply this correctly?
Many thanks
Jonah
Perhaps I am missing something, but couldn't this be simply:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/exchange/sce">
<ImportTask xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<EntityRelationshipEntities>
<xsl:apply-templates select="sce.srs/spr/spr.cams[string(prs/prs.mensys/prs_name.prs.mensys)]"/>
</EntityRelationshipEntities>
</ImportTask>
</xsl:template>
<xsl:template match="spr.cams">
<EntityRelationshipEntity>
<ErRef>ERREF_21</ErRef>
<EntityCode>
<xsl:value-of select="../../sce_stuc.sce.srs"/>
</EntityCode>
<AttributeValue>
<xsl:value-of select="prs/prs.mensys/prs_name.prs.mensys"/>
</AttributeValue>
<Action>VALUEONLY</Action>
</EntityRelationshipEntity>
</xsl:template>
</xsl:stylesheet>