How to split a node value which has xml as string in xslt - xslt

We have a requirement where we are getting an XML payload in form of String for one node and we need to expand this XML and pass the XML node values to destination XSD columns.
For example Input XSD :
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Transaction xmlns="http://xmlns.oracle.com/2012/SCEM">
<TRXKEY>0x0000013</TRXKEY>
<EVENTNAME>SalesOrder</EVENTNAME>
<ACCEPTEDQUANTITY>0</ACCEPTEDQUANTITY>
<ORDEREDQUANTITY>0</ORDEREDQUANTITY>
<SOLORGID>0</SOLORGID>
<LHORDERHOLDIDRELEASED>0</LHORDERHOLDIDRELEASED>
<ORDEREDQUANTITYUOM>0</ORDEREDQUANTITYUOM>
<UNITSELLINGPRICE>0</UNITSELLINGPRICE>
<ORDERTYPE><Val lang='AR'>OrderTypeARARARAR</Val>
<Val lang='KO'>OrderTypeKOKOKOKO</Val>
<Val lang='US'>OrderTypeUSUSUUS</Val>
</ORDERTYPE>
</Transaction>
Output XML
<Transaction1 xmlns="http://xmlns.oracle.com/2012/SCEM">
<TRXKEY>0x0000013</TRXKEY>
<EVENTNAME>SalesOrder</EVENTNAME>
<ACCEPTEDQUANTITY>0</ACCEPTEDQUANTITY>
<ORDEREDQUANTITY>0</ORDEREDQUANTITY>
<SOLORGID>0</SOLORGID>
<LHORDERHOLDIDRELEASED>0</LHORDERHOLDIDRELEASED>
<ORDEREDQUANTITYUOM>0</ORDEREDQUANTITYUOM>
<UNITSELLINGPRICE>0</UNITSELLINGPRICE>
<ORDERTYPE_AR>OrderTypeARARARAR</ORDERTYPE_AR>
<ORDERTYPE_US>OrderTypeUSUSUUS</ORDERTYPE_US>
<ORDERTYPE_KO>OrderTypeKOKOKOKO</ORDERTYPE_KO>
</Transaction>
We need to loop through the ORDERTYPE node XML string. Depending on the 'Val lang=' value we need to pass this node value to output XSD ORDERTYPE_$lang value column.
How can I loop through this XML string for these 2 different values and pass it to the corresponding output XML column?
I was thinking of using split but it is not helping much.

Thanks Martin,
I have come up with below code which resolved my issue.
<xsl:stylesheet version="1.0"
xmlns:bpws="http://schemas.xmlsoap.org/ws/2003/03/business-process/"
xmlns:xp20="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.Xpath20"
xmlns:mhdr="http://www.oracle.com/XSL/Transform/java/oracle.tip.mediator.service.common.functions.MediatorExtnFunction"
xmlns:bpel="http://docs.oasis-open.org/wsbpel/2.0/process/executable"
xmlns:oraext="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.ExtFunc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dvm="http://www.oracle.com/XSL/Transform/java/oracle.tip.dvm.LookupValue"
xmlns:hwf="http://xmlns.oracle.com/bpel/workflow/xpath"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:med="http://schemas.oracle.com/mediator/xpath"
xmlns:ids="http://xmlns.oracle.com/bpel/services/IdentityService/xpath"
xmlns:bpm="http://xmlns.oracle.com/bpmn20/extensions"
xmlns:client="http://xmlns.oracle.com/KeyStore/emsProjXslt/BPELProcess1"
xmlns:xdk="http://schemas.oracle.com/bpel/extension/xpath/function/xdk"
xmlns:xref="http://www.oracle.com/XSL/Transform/java/oracle.tip.xref.xpath.XRefXPathFunctions"
xmlns:ns2="http://xmlns.oracle.com/2012/SCEM"
xmlns:plnk="http://schemas.xmlsoap.org/ws/2003/05/partner-link/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:ora="http://schemas.oracle.com/xpath/extension"
xmlns:socket="http://www.oracle.com/XSL/Transform/java/oracle.tip.adapter.socket.ProtocolTranslator"
xmlns:ldap="http://schemas.oracle.com/xpath/extension/ldap"
exclude-result-prefixes="xsi xsl client ns2 plnk xsd wsdl bpws xp20 mhdr bpel oraext dvm hwf med ids bpm xdk xref ora socket ldap">
<xsl:template match="/">
<ns2:Transaction>
<ns2:TRXKEY>
<xsl:value-of select="/ns2:Transaction/ns2:TRXKEY"/>
</ns2:TRXKEY>
<xsl:call-template name="for.loop.Parameters">
<xsl:with-param name="sourceNodes"
select='substring-after(/ns2:Transaction/ns2:ORDERTYPE,"Val lang=")'/>
</xsl:call-template>
</ns2:Transaction>
</xsl:template>
<xsl:template name="for.loop.Parameters">
<xsl:param name="sourceNodes"/>
<xsl:variable name="temp">
<xsl:choose>
<xsl:when test="string-length($sourceNodes) > '0'">
<xsl:value-of select="substring-before($sourceNodes,'</Val>')"/>
</xsl:when>
</xsl:choose>
</xsl:variable>
<xsl:variable name="Expression" select="substring-after($temp, '>')"/>
<xsl:variable name="Expression1" select="substring-before($temp, '>')"/>
<xsl:if test="contains($Expression1,'AR')">
<ns2:ORDERTYPE_AR>
<xsl:value-of select="$Expression"/>
</ns2:ORDERTYPE_AR>
</xsl:if>
<xsl:if test="contains($Expression,'US')">
<ns2:ORDERTYPE_US>
<xsl:value-of select="$Expression"/>
</ns2:ORDERTYPE_US>
</xsl:if>
<xsl:if test="contains($Expression,'KO')">
<ns2:ORDERTYPE_KO>
<xsl:value-of select="$Expression"/>
</ns2:ORDERTYPE_KO>
</xsl:if>
<xsl:variable name="test">
<xsl:value-of select="substring-after($sourceNodes,'/Val>')"/>
</xsl:variable>
<xsl:if test="string-length($test) > 1 ">
<xsl:call-template name="for.loop.Parameters">
<xsl:with-param name="sourceNodes">
<xsl:value-of select='substring-after($test,"Val lang=")'/>
</xsl:with-param>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

Related

Which is the correct approach out of the two?

I'm having an XML and likes to retrieve and concatenate values
Below is the Sample XML from which we need to retrieve the values:
<?xml version="1.0" encoding="UTF-8"?>
<Document>
<docBody>
<employee>
<employeeNumber>595</employeeNumber>
</employee>
<employeeAddress>
<empAddress>1</empAddress>
<empAddress2>1</empAddress2>
</employeeAddress>
</docBody>
<Messages />
</Document>
Method1:
<xsl:template match="employee">
<xsl:variable name="empNbr">
<xsl:value-of select="employeeNumber"/>
</xsl:variable>
<xsl:variable name="empAddress">
<xsl:value-of select="../employeeDetails/employeeAddress"/>
</xsl:variable>
<xsl:variable name="empAddress2">
<xsl:value-of select="../employeeDetails/empAddress2"/>
</xsl:variable>
<xsl:value-of select="concat($empNbr,$empAddress,$empAddress2)"/>
</xsl:template>
Method2:
<xsl:template match="employee">
<xsl:value-of select="concat(<xsl:value-of select="employeeNumber"/>,
<xsl:value-of select="../employeeDetails/employeeAddress"/>,
<xsl:value-of select="../employeeDetails/empAddress2"/>)"/>
</xsl:template>
Thanks in advance.
It's usually better to write variable declarations like so
<xsl:variable name="empNbr" select="employeeNumber" />
This means empNbr now references the employeeNumber directly. By using xsl:value-of this effectively gets the text value of empNbr and assigns it to the variable.
Your second method is not valid XSLT. The expression you are looking for is this...
<xsl:value-of select="concat(employeeNumber, ../employeeDetails/employeeAddress, ../employeeDetails/empAddress2)" />
Or you could have three separate xsl:value-of statements.
<xsl:value-of select="employeeNumber"/>
<xsl:value-of select="../employeeDetails/employeeAddress"/>
<xsl:value-of select="../employeeDetails/empAddress2"/>

XSL Copy nodes without xmlns

I have a specific problem. I have to transform an XML structure to other, where the base XSD is same, different only the namespace definition. The first part is simple, because here I have to use field-mapping. The second part is the simple copy. And here is the problem. The copied "main" node contains the original xmlns attribute. I need to remove this "attribute".
The base xml:
<?xml version="1.0" encoding="UTF-8"?>
<S2SCTIcf:SCTIcfBlkCredTrf xmlns:S2SCTIcf="urn:S2SCTIcf:xsd:$SCTIcfBlkCredTrf"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:S2SCTIcf:xsd:$SCTIcfBlkCredTrf SCTIcfBlkCredTrf.xsd">
<S2SCTIcf:SndgInst>XXXXXXX0</S2SCTIcf:SndgInst>
<S2SCTIcf:RcvgInst>YYYYYYY0</S2SCTIcf:RcvgInst>
<S2SCTIcf:FileRef>2013111200800546</S2SCTIcf:FileRef>
<S2SCTIcf:SrvcId>SCT</S2SCTIcf:SrvcId>
<S2SCTIcf:TstCode>T</S2SCTIcf:TstCode>
<S2SCTIcf:FType>ICF</S2SCTIcf:FType>
<S2SCTIcf:FDtTm>2013-11-12T16:26:31</S2SCTIcf:FDtTm>
<S2SCTIcf:NumCTBlk>1</S2SCTIcf:NumCTBlk>
<S2SCTIcf:NumPCRBlk>0</S2SCTIcf:NumPCRBlk>
<S2SCTIcf:NumRFRBlk>0</S2SCTIcf:NumRFRBlk>
<S2SCTIcf:NumROIBlk>0</S2SCTIcf:NumROIBlk>
<S2SCTIcf:FIToFICstmrCdtTrf xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.008.001.02">
<GrpHdr>
<MsgId>xxddccxxaaa</MsgId>
<CreDtTm>2013-11-12T16:26:31</CreDtTm>
<NbOfTxs>1</NbOfTxs>
<TtlIntrBkSttlmAmt Ccy="EUR">469.12</TtlIntrBkSttlmAmt>
<IntrBkSttlmDt>2013-11-13</IntrBkSttlmDt>
<SttlmInf>
<SttlmMtd>CLRG</SttlmMtd>
<ClrSys>
<Prtry>ST2</Prtry>
</ClrSys>
</SttlmInf>
<InstgAgt>
<FinInstnId>
<BIC>XXXXXXX0</BIC>
</FinInstnId>
</InstgAgt>
</GrpHdr>
<CdtTrfTxInf>
<PmtId>
<EndToEndId>1114405599,1114382976</EndToEndId>
<TxId>F3232323232</TxId>
</PmtId>
<PmtTpInf>
<SvcLvl>
<Cd>SEPA</Cd>
</SvcLvl>
</PmtTpInf>
<IntrBkSttlmAmt Ccy="EUR">469.12</IntrBkSttlmAmt>
<ChrgBr>SLEV</ChrgBr>
<Dbtr>
<Nm>ddffrrddsaasas</Nm>
<PstlAdr>
<Ctry>HU</Ctry>
<AdrLine>dssdsdsdsdsdaas</AdrLine>
</PstlAdr>
</Dbtr>
<DbtrAcct>
<Id>
<IBAN>HU26XXXXXXXXXXXXXX</IBAN>
</Id>
</DbtrAcct>
<DbtrAgt>
<FinInstnId>
<BIC>CCCCHUH0</BIC>
</FinInstnId>
</DbtrAgt>
<CdtrAgt>
<FinInstnId>
<BIC>CVCVCVCVCVC</BIC>
</FinInstnId>
</CdtrAgt>
<Cdtr>
<Nm>XXXXX</Nm>
<PstlAdr>
<Ctry>DE</Ctry>
</PstlAdr>
</Cdtr>
<CdtrAcct>
<Id>
<IBAN>DE12vvvvvvvhghhg</IBAN>
</Id>
</CdtrAcct>
<RmtInf>
<Ustrd>0000000000,0000000000 </Ustrd>
</RmtInf>
</CdtTrfTxInf>
</S2SCTIcf:FIToFICstmrCdtTrf>
</S2SCTIcf:SCTIcfBlkCredTrf>
The xslt:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ns0="urn:S2SCTIcf:xsd:$SCTIcfBlkCredTrf"
xmlns:sw8="urn:iso:std:iso:20022:tech:xsd:pacs.008.001.02"
xmlns:S2SCTScf="urn:S2SCTScf:xsd:$SCTScfBlkCredTrf" exclude-result-prefixes="xs ns0 ">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="var1_SCTIcfBlkCredTrf" select="ns0:SCTIcfBlkCredTrf"/>
<S2SCTScf:SCTScfBlkCredTrf
xsi:schemaLocation="urn:S2SCTScf:xsd:$SCTScfBlkCredTrf SCTScfBlkCredTrf.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:S2SCTScf="urn:S2SCTScf:xsd:$SCTScfBlkCredTrf">
<xsl:for-each select="$var1_SCTIcfBlkCredTrf">
<S2SCTScf:SndgInst>
<xsl:value-of select="string(ns0:RcvgInst)"/>
</S2SCTScf:SndgInst>
</xsl:for-each>
<xsl:for-each select="$var1_SCTIcfBlkCredTrf">
<S2SCTScf:RcvgInst>
<xsl:value-of select="string(ns0:SndgInst)"/>
</S2SCTScf:RcvgInst>
</xsl:for-each>
<xsl:for-each select="$var1_SCTIcfBlkCredTrf">
<S2SCTScf:SrvcId>
<xsl:value-of select="string(ns0:SrvcId)"/>
</S2SCTScf:SrvcId>
</xsl:for-each>
<xsl:for-each select="$var1_SCTIcfBlkCredTrf">
<S2SCTScf:TstCode>
<xsl:value-of select="string(ns0:TstCode)"/>
</S2SCTScf:TstCode>
</xsl:for-each>
<S2SCTScf:FType>SCF</S2SCTScf:FType>
<xsl:for-each select="$var1_SCTIcfBlkCredTrf">
<S2SCTScf:FileRef>
<xsl:value-of select="string(ns0:FileRef)"/>
</S2SCTScf:FileRef>
</xsl:for-each>
<S2SCTScf:RoutingInd>DIR</S2SCTScf:RoutingInd>
<xsl:for-each select="$var1_SCTIcfBlkCredTrf">
<S2SCTScf:FileBusDt>
<xsl:value-of select="string(ns0:FDtTm)"/>
</S2SCTScf:FileBusDt>
</xsl:for-each>
<S2SCTScf:FIToFICstmrCdtTrf xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.008.001.02">
<xsl:for-each select="$var1_SCTIcfBlkCredTrf/ns0:FIToFICstmrCdtTrf">
<GrpHdr>
<xsl:for-each select="$var1_SCTIcfBlkCredTrf/ns0:FIToFICstmrCdtTrf">
<MsgId>
<xsl:value-of select="string(sw8:GrpHdr/sw8:MsgId)"/>
</MsgId>
</xsl:for-each>
<xsl:for-each select="$var1_SCTIcfBlkCredTrf/ns0:FIToFICstmrCdtTrf">
<CreDtTm>
<xsl:value-of select="string(sw8:GrpHdr/sw8:CreDtTm)"/>
</CreDtTm>
</xsl:for-each>
<xsl:for-each select="$var1_SCTIcfBlkCredTrf/ns0:FIToFICstmrCdtTrf">
<NbOfTxs>
<xsl:value-of select="string(sw8:GrpHdr/sw8:NbOfTxs)"/>
</NbOfTxs>
</xsl:for-each>
<xsl:for-each select="$var1_SCTIcfBlkCredTrf/ns0:FIToFICstmrCdtTrf">
<xsl:variable name="var2_TtlIntrBkSttlmAmt"
select="sw8:GrpHdr/sw8:TtlIntrBkSttlmAmt"/>
<TtlIntrBkSttlmAmt>
<xsl:attribute name="Ccy" namespace="">
<xsl:value-of select="string($var2_TtlIntrBkSttlmAmt/#Ccy)"/>
</xsl:attribute>
<xsl:value-of
select="string(number(string($var2_TtlIntrBkSttlmAmt)))"/>
</TtlIntrBkSttlmAmt>
</xsl:for-each>
<xsl:for-each select="$var1_SCTIcfBlkCredTrf/ns0:FIToFICstmrCdtTrf">
<IntrBkSttlmDt>
<xsl:value-of select="string(sw8:GrpHdr/sw8:IntrBkSttlmDt)"/>
</IntrBkSttlmDt>
</xsl:for-each>
<SttlmInf>
<xsl:for-each select="$var1_SCTIcfBlkCredTrf/ns0:FIToFICstmrCdtTrf">
<SttlmMtd>
<xsl:value-of
select="string(sw8:GrpHdr/sw8:SttlmInf/sw8:SttlmMtd)"/>
</SttlmMtd>
</xsl:for-each>
<ClrSys>
<xsl:for-each select="$var1_SCTIcfBlkCredTrf/ns0:FIToFICstmrCdtTrf">
<Prtry>
<xsl:value-of
select="string(sw8:GrpHdr/sw8:SttlmInf/sw8:ClrSys/sw8:Prtry)"
/>
</Prtry>
</xsl:for-each>
</ClrSys>
</SttlmInf>
<InstdAgt>
<FinInstnId>
<xsl:for-each
select="$var1_SCTIcfBlkCredTrf/ns0:FIToFICstmrCdtTrf/sw8:GrpHdr/sw8:InstgAgt">
<BIC>
<xsl:value-of select="string(sw8:FinInstnId/sw8:BIC)"/>
</BIC>
</xsl:for-each>
</FinInstnId>
</InstdAgt>
</GrpHdr>
<xsl:copy-of select="$var1_SCTIcfBlkCredTrf/ns0:FIToFICstmrCdtTrf/sw8:CdtTrfTxInf" />
</xsl:for-each>
</S2SCTScf:FIToFICstmrCdtTrf>
</S2SCTScf:SCTScfBlkCredTrf>
</xsl:template>
</xsl:stylesheet>
The wrong part of output:
...
</InstdAgt>
</GrpHdr>
<CdtTrfTxInf xmlns:S2SCTIcf="urn:S2SCTIcf:xsd:$SCTIcfBlkCredTrf">
<PmtId>
<EndToEndId>1114405599,1114382976</EndToEndId>
<TxId>F3232323232</TxId>
...
I don't want to get the xmlns:S2SCTIcf="urn:S2SCTIcf:xsd:$SCTIcfBlkCredTrf" attribute this line.
Have someone any idea?
Thank you!
Feri
Your issue is that
<xsl:copy-of select="$var1_SCTIcfBlkCredTrf/ns0:FIToFICstmrCdtTrf/sw8:CdtTrfTxInf" />
copies the node from the original tree including its "namespace nodes", i.e. the namespace declarations that were in scope at that point in the original document. When this node is serialized any of these namespace nodes that are not already in force at this point in the output document will be declared by the serializer.
If you were able to use XSLT 2.0 then you could try setting copy-namespaces="no" on the copy-of but that isn't an option in XSLT 1.0. So instead of using copy-of you need to use templates to copy that node (and all its descendants recursively) without including the namespace nodes. The simplest way I can think of to do this is to declare two additional templates
<xsl:template match="*" mode="copy">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:apply-templates select="#*|node()" mode="copy" />
</xsl:element>
</xsl:template>
<xsl:template match="#*|text()|comment()" mode="copy">
<xsl:copy/>
</xsl:template>
and then replace that copy-of with
<xsl:apply-templates mode="copy"
select="$var1_SCTIcfBlkCredTrf/ns0:FIToFICstmrCdtTrf/sw8:CdtTrfTxInf" />
The trick here is that xsl:element is creating a new element node that happens to have the same name and namespace as the original one, rather than copying the original node, so it doesn't copy the namespace nodes.
You can use a variant of the answer here to get what you want.
Basically, you would create a template to rebuild that element without any namespaces. So you would add the following two templates to your current XSLT:
<xsl:template match="*" mode="copy-no-namespaces">
<xsl:element name="{local-name()}">
<xsl:copy-of select="#*"/>
<xsl:apply-templates select="node()" mode="copy-no-namespaces"/>
</xsl:element>
</xsl:template>
<xsl:template match="comment()| processing-instruction()" mode="copy-no-namespaces">
<xsl:copy/>
</xsl:template>
And then update your copy-of to
<xsl:apply-templates select="$var1_SCTIcfBlkCredTrf/ns0:FIToFICstmrCdtTrf/sw8:CdtTrfTxInf" mode="copy-no-namespaces"/>

How to programmatically iterate in XSLT across multiple files with similar name

A have following xmls:
data_0.xml
data_1.xml
data_3.xml
and so on...
And in xslt file I want to iterate through all files, so I tried for-each function.
<xsl:for-each select="document('data.xml')/*">
How to iterate on all of them? Add mask somehow? This surely won't work:
<xsl:for-each select="document('data_*.xml')/*">
Here is your solution in xslt 1.0:
I have four files in my filesystem:
Doc1.xml:
<p>Doc1</p>
Doc2.xml:
<p>Doc2</p>
Doc3.xml:
<p>Doc3</p>
Doc4.xml:
<p>Doc4</p>
and my xslt to get their output is:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<Root>
<xsl:call-template name="getDocuments"/>
</Root>
</xsl:template>
<xsl:template name="getDocuments">
<xsl:param name="fileStartWith" select="'Doc'"/>
<xsl:param name="endCounter">4</xsl:param>
<xsl:param name="startCounter">1</xsl:param>
<xsl:choose>
<xsl:when test="$endCounter > 0">
<xsl:variable name="fileName"><xsl:value-of select="concat($fileStartWith,$startCounter,'.xml')"/></xsl:variable>
<xsl:for-each select="document($fileName)/*">
<xsl:copy-of select="."/><xsl:text>
</xsl:text>
</xsl:for-each>
<xsl:call-template name="getDocuments">
<xsl:with-param name="startCounter" select="$startCounter + 1"/>
<xsl:with-param name="fileStartWith" select="$fileStartWith"/>
<xsl:with-param name="endCounter" select="$endCounter - 1"/>
</xsl:call-template>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
generated output is:
<Root>
<p>Doc1</p>
<p>Doc2</p>
<p>Doc3</p>
<p>Doc4</p>
</Root>
Please make sure that xslt and xml is on the same path otherwise you need to change the content of document function.

Merge functionality of two xsl files into a single file (continued.....)

This is in continuation of my question:
Merge functionality of two xsl files into a single file (not a xsl import or include issue)
I have to merge the solution (xsl) of above question to below xsl:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:template match="/">
<Declaration>
<Message>
<Meduim>
<xsl:value-of select="/Declaration/Message/Meduim"/>
</Meduim>
<MessageIdentifier>
<xsl:value-of select="/Declaration/Message/MessageIdentifier"/>
</MessageIdentifier>
<ControlingAgencyCode>
<xsl:value-of select="/Declaration/Message/ControlingAgencyCode"/>
</ControlingAgencyCode>
<AssociationAssignedCode>
<xsl:value-of select="/Declaration/Message/AssociationAssignedCode"/>
</AssociationAssignedCode>
<CommonAccessReference>
<xsl:value-of select="/Declaration/Message/CommonAccessReference"/>
</CommonAccessReference>
</Message>
<BeginingOfMessage>
<MessageCode>
<xsl:value-of select="/Declaration/BeginingOfMessage/MessageCode"/>
</MessageCode>
<DeclarationCurrency>
<xsl:value-of select="/Declaration/BeginingOfMessage/DeclarationCurrency"/>
</DeclarationCurrency>
<MessageFunction>
<xsl:value-of select="/Declaration/BeginingOfMessage/MessageFunction"/>
</MessageFunction>
</BeginingOfMessage>
<Header>
<ProcessingInformation>
<xsl:for-each select="/Declaration/Header/ProcessingInformation/ProcessingInstructions">
<ProcessingInstructions>
<xsl:value-of select="."/>
</ProcessingInstructions>
</xsl:for-each>
</ProcessingInformation>
<xsl:for-each select="/Declaration/Header/Seal">
<Seal>
<SealID>
<xsl:value-of select="SealID"/>
</SealID>
<SealLanguage>
<xsl:value-of select="SealLanguage"/>
</SealLanguage>
</Seal>
</xsl:for-each>
<xsl:choose>
<xsl:when test='/Declaration/Header/DeclarantsReference = ""'>
<DeclarantsReference>
<xsl:text disable-output-escaping="no">A</xsl:text>
</DeclarantsReference>
</xsl:when>
<xsl:otherwise>
<DeclarantsReference>
<xsl:value-of select="/Declaration/Header/DeclarantsReference"/>
</DeclarantsReference>
</xsl:otherwise>
</xsl:choose>
<xsl:for-each select="/Declaration/Header/Items">
<Items>
<CustomsStatusOfGoods>
<CPC>
<xsl:value-of select="CustomsStatusOfGoods/CPC"/>
</CPC>
<CommodityCode>
<xsl:value-of select="CustomsStatusOfGoods/CommodityCode"/>
</CommodityCode>
<ECSuplementaryMeasureCode1>
<xsl:value-of select="CustomsStatusOfGoods/ECSuplementaryMeasureCode1"/>
</ECSuplementaryMeasureCode1>
<ECSuplementaryMeasureCode2>
<xsl:value-of select="CustomsStatusOfGoods/ECSuplementaryMeasureCode2"/>
</ECSuplementaryMeasureCode2>
<PreferenceCode>
<xsl:value-of select="CustomsStatusOfGoods/PreferenceCode"/>
</PreferenceCode>
</CustomsStatusOfGoods>
<xsl:for-each select="ItemAI">
<ItemAI>
<AICode>
<xsl:value-of select="AICode"/>
</AICode>
<AIStatement>
<xsl:value-of select="AIStatement"/>
</AIStatement>
<AILanguage>
<xsl:value-of select="AILanguage"/>
</AILanguage>
</ItemAI>
</xsl:for-each>
<Locations>
<CountryOfOriginCode>
<xsl:value-of select="Locations/CountryOfOriginCode"/>
</CountryOfOriginCode>
<xsl:for-each select="Locations/ItemCountryonRouteCode">
<ItemCountryonRouteCode>
<xsl:value-of select="."/>
</ItemCountryonRouteCode>
</xsl:for-each>
<ItemDispatchCountry>
<xsl:value-of select="Locations/ItemDispatchCountry"/>
</ItemDispatchCountry>
<ItemDestinationCountry>
<xsl:value-of select="Locations/ItemDestinationCountry"/>
</ItemDestinationCountry>
</Locations>
<Measurements>
<GrossMass>
<xsl:value-of select="Measurements/GrossMass"/>
</GrossMass>
<NetMass>
<xsl:value-of select="Measurements/NetMass"/>
</NetMass>
<SupplementaryUnits>
<xsl:value-of select="Measurements/SupplementaryUnits"/>
</SupplementaryUnits>
<ThirdQuantity>
<xsl:value-of select="Measurements/ThirdQuantity"/>
</ThirdQuantity>
</Measurements>
<xsl:for-each select="Package">
<Package>
<PackageNumber>
<xsl:value-of select="PackageNumber"/>
</PackageNumber>
<PackageKind>
<xsl:value-of select="PackageKind"/>
</PackageKind>
<PackageMarks>
<xsl:value-of select="PackageMarks"/>
</PackageMarks>
<PackageLanguage>
<xsl:value-of select="PackageLanguage"/>
</PackageLanguage>
</Package>
</xsl:for-each>
<PriceValue>
<ItemStatisticalValue>
<xsl:value-of select="PriceValue/ItemStatisticalValue"/>
</ItemStatisticalValue>
<ItemPrice>
<xsl:value-of select="PriceValue/ItemPrice"/>
</ItemPrice>
</PriceValue>
<ItemReferences>
<xsl:for-each select="ItemReferences/ContainerID">
<ContainerID>
<xsl:value-of select="."/>
</ContainerID>
</xsl:for-each>
<QuotaNo>
<xsl:value-of select="ItemReferences/QuotaNo"/>
</QuotaNo>
<UNDangerousGoodsCode>
<xsl:value-of select="ItemReferences/UNDangerousGoodsCode"/>
</UNDangerousGoodsCode>
</ItemReferences>
<GoodsDescription>
<GoodsDescription>
<xsl:value-of select="GoodsDescription/GoodsDescription"/>
</GoodsDescription>
<GoodsDescriptionLanguage>
<xsl:value-of select="GoodsDescription/GoodsDescriptionLanguage"/>
</GoodsDescriptionLanguage>
</GoodsDescription>
<Documents>
<xsl:for-each select="Documents/PreviousDocument">
<PreviousDocument>
<PreviousDocumentKind>
<xsl:value-of select="PreviousDocumentKind"/>
</PreviousDocumentKind>
<PreviousDocumentIdentifier>
<xsl:value-of select="PreviousDocumentIdentifier"/>
</PreviousDocumentIdentifier>
<PreviousDocumentType>
<xsl:value-of select="PreviousDocumentType"/>
</PreviousDocumentType>
<PreviousDocumentLanguage>
<xsl:value-of select="PreviousDocumentLanguage"/>
</PreviousDocumentLanguage>
</PreviousDocument>
</xsl:for-each>
<xsl:for-each select="Documents/ItemDocument">
<ItemDocument>
<DocumentCode>
<xsl:value-of select="DocumentCode"/>
</DocumentCode>
<DocumentPart>
<xsl:value-of select="DocumentPart"/>
</DocumentPart>
<DocumentQuantity>
<xsl:value-of select="DocumentQuantity"/>
</DocumentQuantity>
<DocumentReason>
<xsl:value-of select="DocumentReason"/>
</DocumentReason>
<DocumentReference>
<xsl:value-of select="DocumentReference"/>
</DocumentReference>
<DocumentStatus>
<xsl:value-of select="DocumentStatus"/>
</DocumentStatus>
<DocumentLanguage>
<xsl:value-of select="DocumentLanguage"/>
</DocumentLanguage>
</ItemDocument>
</xsl:for-each>
</Documents>
<Valuation>
<ValuationMethodCode>
<xsl:value-of select="Valuation/ValuationMethodCode"/>
</ValuationMethodCode>
<ItemValuationAdjustmentCode>
<xsl:value-of select="Valuation/ItemValuationAdjustmentCode"/>
</ItemValuationAdjustmentCode>
<ItemValuationAdjustmentPercentage>
<xsl:value-of select="Valuation/ItemValuationAdjustmentPercentage"/>
</ItemValuationAdjustmentPercentage>
</Valuation>
<ItemTransportChargeMOP>
<xsl:value-of select="ItemTransportChargeMOP"/>
</ItemTransportChargeMOP>
<xsl:for-each select="ItemProcessingInstructions">
<ItemProcessingInstructions>
<xsl:value-of select="."/>
</ItemProcessingInstructions>
</xsl:for-each>
</Items>
</xsl:for-each>
<NumberOfPackages>
<xsl:value-of select="/Declaration/Header/NumberOfPackages"/>
</NumberOfPackages>
</Header>
</Declaration>
</xsl:template>
</xsl:stylesheet>
so for source xml
<Declaration>
<Message>
<Meduim>#+#</Meduim>
<MessageIdentifier>AA</MessageIdentifier>
<CommonAccessReference></CommonAccessReference>
</Message>
<BeginingOfMessage>
<MessageCode>ISD</MessageCode>
<DeclarationCurrency></DeclarationCurrency>
<MessageFunction>5</MessageFunction>
</BeginingOfMessage>
</Declaration>
the final output is
<Declaration>
<Message>
<Meduim></Meduim>
<MessageIdentifier>AA</MessageIdentifier>
</Message>
<BeginingOfMessage>
<MessageCode>ISD</MessageCode>
<MessageFunction>5</MessageFunction>
</BeginingOfMessage>
</Declaration>
I. Performing a chain of transformations is used quite often in XSLT applications, though doing this entirely in XSLT 1.0 requires the use of the vendor-specific xxx:node-set() function. In XSLT 2.0 no such extension is needed as the infamous RTF datatype is eliminated there.
Here is an example (too-simple to be meaningful, but illustrating completely how this is done):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="vrtfPass1">
<xsl:apply-templates select="/*/*"/>
</xsl:variable>
<xsl:variable name="vPass1"
select="ext:node-set($vrtfPass1)"/>
<xsl:apply-templates mode="pass2"
select="$vPass1/*"/>
</xsl:template>
<xsl:template match="num[. mod 2 = 1]">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="num" mode="pass2">
<xsl:copy>
<xsl:value-of select=". *2"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
when this transformation is applied on the following XML document:
<nums>
<num>01</num>
<num>02</num>
<num>03</num>
<num>04</num>
<num>05</num>
<num>06</num>
<num>07</num>
<num>08</num>
<num>09</num>
<num>10</num>
</nums>
the wanted, correct result is produced:
<num>2</num>
<num>6</num>
<num>10</num>
<num>14</num>
<num>18</num>
Explanation:
In the first step the XML document is transformed and the result is defined as the value of the variable $vrtfPass1. This copies only the num elements that have odd value (not even).
The $vrtfPass1 variable, being of type RTF, is not directly usable for XPath expressions so we convert it to a normal tree, using the EXSLT (implemented by most XSLT 1.0 processors) function ext:node-set and defining another variable -- $vPass1 whose value is this tree.
We now perform the second transformation in our chain of transformations -- on the result of the first transformation, that is kept as the value of the variable $vPass1. Not to mess with the first-pass template, we specify that the new processing should be in a named mode, called "pass2". In this mode the value of any num element is multiplied by two.
See also the answer of Michael Kay to your first question, which also explained this general technique.
II. XSLT 2.0 solution (no RTFs):
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="vPass1" >
<xsl:apply-templates select="/*/*"/>
</xsl:variable>
<xsl:apply-templates mode="pass2"
select="$vPass1/*"/>
</xsl:template>
<xsl:template match="num[. mod 2 = 1]">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="num" mode="pass2">
<xsl:copy>
<xsl:value-of select=". *2"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
III. Using the compose() and compose-flist() functions/templates of FXSL
The FXSL library provides two convenient functions/template that support easy chaining of transformations. The former composes two functions/transformations while the latter composes all functions/transformations that are provided in a sequence.
Here is a simple, complete code example:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:f="http://fxsl.sf.net/"
xmlns:myFun1="f:myFun1"
xmlns:myFun2="f:myFun2"
xmlns:ext="http://exslt.org/common"
exclude-result-prefixes="xsl f ext myFun1 myFun2"
>
<xsl:import href="compose.xsl"/>
<xsl:import href="compose-flist.xsl"/>
<!-- to be applied on any xml source -->
<xsl:output method="text"/>
<myFun1:myFun1/>
<myFun2:myFun2/>
<xsl:template match="/">
<xsl:variable name="vFun1" select="document('')/*/myFun1:*[1]"/>
<xsl:variable name="vFun2" select="document('')/*/myFun2:*[1]"/>
Compose:
(*3).(*2) 3 =
<xsl:call-template name="compose">
<xsl:with-param name="pFun1" select="$vFun1"/>
<xsl:with-param name="pFun2" select="$vFun2"/>
<xsl:with-param name="pArg1" select="3"/>
</xsl:call-template>
<xsl:variable name="vrtfParam">
<xsl:copy-of select="$vFun1"/>
<xsl:copy-of select="$vFun2"/>
<xsl:copy-of select="$vFun1"/>
</xsl:variable>
Multi Compose:
(*3).(*2).(*3) 2 =
<xsl:call-template name="compose-flist">
<xsl:with-param name="pFunList" select="ext:node-set($vrtfParam)/*"/>
<xsl:with-param name="pArg1" select="2"/>
</xsl:call-template>
</xsl:template>
<xsl:template match="myFun1:*" mode="f:FXSL">
<xsl:param name="pArg1"/>
<xsl:value-of select="3 * $pArg1"/>
</xsl:template>
<xsl:template match="myFun2:*" mode="f:FXSL">
<xsl:param name="pArg1"/>
<xsl:value-of select="2 * $pArg1"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on any XML document (not used), the wanted, correct results are produced:
Compose:
(*3).(*2) 3 =
18
Multi Compose:
(*3).(*2).(*3) 2 =
36
Pure XSLT 1.0 does not support chaining templates (nor stylesheets as a whole). You can either solve this program outside of XSLT by calling the second xslt template and passing it the output of the first manually, or you can use the fairly pervasive extension function node-set(). MSXML, .NET, EXSL and many other implementations support such a function. The namespace prefix for node-set varies depending on XSLT implementation, but the EXSL prefix is a good bet (and .NET, though undocumented, supports this).
To use node-set store the result of a template in an xsl:variable or xsl:param and do something like <xsl:apply-templates select="exsl:node-set($myvarname)"/>.
Finally, you can of course rewrite your two templates to provide the functionality of both in one pass - but in general, this isn't a trivial thing to do.
I don't understand the problem.
The solution I posted in your last question already works.
For this input:
<?xml version="1.0" encoding="UTF-8"?>
<Declaration>
<Message>
<Meduim>#+#</Meduim>
<MessageIdentifier>AA</MessageIdentifier>
<CommonAccessReference></CommonAccessReference>
</Message>
<BeginingOfMessage>
<MessageCode>ISD</MessageCode>
<DeclarationCurrency></DeclarationCurrency>
<MessageFunction>5</MessageFunction>
</BeginingOfMessage>
</Declaration>
Output will be:
<?xml version="1.0" encoding="UTF-8"?>
<Declaration>
<Message>
<Meduim/>
<MessageIdentifier>AA</MessageIdentifier>
</Message>
<BeginingOfMessage>
<MessageCode>ISD</MessageCode>
<MessageFunction>5</MessageFunction>
</BeginingOfMessage>
</Declaration>
You, in fact, don't need your original stylesheet, because basically you just copy the tree.

replacing text in xml using xslt

I have an XML file which has some values in child Element aswell in attributes.
If i want to replace some text when specific value is matched how can i achieve it?
I tried using xlst:translate() function. But i cant use this function for each element or attribute in xml.
So is there anyway to replace/translate value at one shot?
<?xml version="1.0" encoding="UTF-8"?>
<Employee>
<Name>Emp1</Name>
<Age>40</Age>
<sex>M</sex>
<Address>Canada</Address>
<PersonalInformation>
<Country>Canada</country>
<Street1>KO 92</Street1>
</PersonalInformation>
</Employee>
Output :
<?xml version="1.0" encoding="UTF-8"?>
<Employee>
<Name>Emp1</Name>
<Age>40</Age>
<sex>M</sex>
<Address>UnitedStates</Address>
<PersonalInformation>
<Country>UnitedStates</country>
<Street1>KO 92</Street1>
</PersonalInformation>
</Employee>
in the output, replaced text from Canada to UnitedStates.
so, without using xslt:transform() functions on any element , i should be able to replace text Canada to UnitedStates irrespective of level nodes.
Where ever i find 'Canada' i should be able to replace to 'UnitedStates' in entire xml.
So how can i achieve this.?
I. XSLT 1.0 solution:
This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my:my" >
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<my:Reps>
<rep>
<old>replace this</old>
<new>replaced</new>
</rep>
<rep>
<old>cat</old>
<new>tiger</new>
</rep>
</my:Reps>
<xsl:variable name="vReps" select=
"document('')/*/my:Reps/*"/>
<xsl:template match="node()|#*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="#*">
<xsl:attribute name="{name()}">
<xsl:call-template name="replace">
<xsl:with-param name="pText" select="."/>
</xsl:call-template>
</xsl:attribute>
</xsl:template>
<xsl:template match="text()" name="replace">
<xsl:param name="pText" select="."/>
<xsl:if test="string-length($pText)">
<xsl:choose>
<xsl:when test=
"not($vReps/old[contains($pText, .)])">
<xsl:copy-of select="$pText"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="vthisRep" select=
"$vReps/old[contains($pText, .)][1]
"/>
<xsl:variable name="vNewText">
<xsl:value-of
select="substring-before($pText, $vthisRep)"/>
<xsl:value-of select="$vthisRep/../new"/>
<xsl:value-of select=
"substring-after($pText, $vthisRep)"/>
</xsl:variable>
<xsl:call-template name="replace">
<xsl:with-param name="pText"
select="$vNewText"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
when applied on this XML document:
<t>
<a attr1="X replace this Y">
<b>cat mouse replace this cat dog</b>
</a>
<c/>
</t>
produces the wanted, correct result:
<t>
<a attr1="X replaced Y">
<b>tiger mouse replaced tiger dog</b>
</a>
<c/>
</t>
Explanation:
The identity rule is used to copy "as-is" some nodes.
We perform multiple replacements, parameterized in my:Reps
If a text node or an attribute doesn't contain any rep-target, it is copied as-is.
If a text node or an attribute contains text to be replaced (rep target), then the replacements are done in the order specified in my:Reps
If the string contains more than one string target, then all targets are replaced: first all occurences of the first rep target, then all occurences of the second rep target, ..., last all occurences of the last rep target.
II. XSLT 2.0 solution:
In XSLT 2.0 one can simply use the standard XPath 2.0 function replace(). However, for multiple replacements the solution would be still very similar to the XSLT 1.0 solution specified above.