I am struggling with what should be a simple XSL: Copy the updateResponse from the message below (note: I need XPATH 1.0 syntax for my integration system compatibility):
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns="urn:enterprise.soap.sforce.com" xmlns:n="urn:enterprise.soap.sforce.com">
<soapenv:Body>
<updateResponse>
<result>
<id>001S000000J1Bu0IAF</id>
<success>true</success>
</result>
</updateResponse>
</soapenv:Body>
</soapenv:Envelope>
I simply want the result structure to be:
<updateResponse xmlns="urn:enterprise.soap.sforce.com">
<result>
<id>001S000000J1Bu0IAF</id>
<success>true</success>
</result>
</updateResponse>
I am able to copy the soap objects, but am unsuccessful in copying the children of the soapenv:Body element. The first copy-of works for Body, but the second does not resolve the XPATH. My XMLSPY tool xpath query editor says the xpath is valid, but the XSL does not resolve.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:urn="enterprise.soap.sforce.com" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<xsl:namespace-alias stylesheet-prefix="soapenv" result-prefix="foo"/>
<xsl:template match="/">
<xsl:apply-templates select="/soapenv:Envelope/soapenv:Body/urn:updateResponse"/>
</xsl:template>
<xsl:template match="/soapenv:Envelope/soapenv:Body/urn:updateResponse">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
Your namespaces are mismatched between your data and your stylesheet, that seems to be the only problem.
In your stylesheet document, change this:
xmlns:urn="enterprise.soap.sforce.com"
to this:
xmlns:urn="urn:enterprise.soap.sforce.com"
Then it will match the declared namespaces in your original input file.
This stylesheet:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<xsl:template match="/soapenv:Envelope/soapenv:Body//*">
<xsl:element name="{local-name()}"
namespace="urn:enterprise.soap.sforce.com">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Output:
<updateResponse xmlns="urn:enterprise.soap.sforce.com">
<result>
<id>001S000000J1Bu0IAF</id>
<success>true</success>
</result>
</updateResponse>
Note: First, the namespace declaration in your stylesheet is wrong. It should be xmlns:urn="urn:enterprise.soap.sforce.com". Second, for an exact result you need to strip in scope namespaces (there are three: xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/", xmlns="urn:enterprise.soap.sforce.com" (default), and xmlns:n="urn:enterprise.soap.sforce.com)
The namespaces in this document are weird; you have xmlns and xmlns:n both assigned to the same namespace. It looks like //soapenv:updateResponse should work. Have you tried that?
Related
I have requirement where I have to add Namespace and xsi to the
element from the source xml with No Namespace.
In Source XML I am just getting the Nodes and there is No namespace
and another program needs BizTalk to add Namespace and XSI to the XML for its processing.
I tried:
Used add namespace pipeline component. (It just added
namespace and not the xsi bits)
Used Map for putting up the desired format and yes no luck as got
just the namespace.
Need your help around this.
My source XML is like
<?xml version="1.0" encoding="UTF-16"?>
<Document>
<CstmrPmtStsRpt>
<GrpHdr>
<MsgId></MsgId>
<CreDtTm></CreDtTm>
<InitgPty>
<Id>
<OrgId>
<BICOrBEI></BICOrBEI>
</OrgId>
</Id>
</InitgPty>
</GrpHdr>
<OrgnlGrpInfAndSts>
<OrgnlMsgId></OrgnlMsgId>
<OrgnlMsgNmId></OrgnlMsgNmId>
<OrgnlNbOfTxs></OrgnlNbOfTxs>
<OrgnlCtrlSum></OrgnlCtrlSum>
<GrpSts>ACCP</GrpSts>
</OrgnlGrpInfAndSts>
</CstmrPmtStsRpt>
</Document>
My Required format is as below:
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="MyNamespace">
<CstmrPmtStsRpt>
<GrpHdr>
<MsgId></MsgId>
<CreDtTm></CreDtTm>
<InitgPty>
<Id>
<OrgId>
<BICOrBEI></BICOrBEI>
</OrgId>
</Id>
</InitgPty>
</GrpHdr>
<OrgnlGrpInfAndSts>
<OrgnlMsgId></OrgnlMsgId>
<OrgnlMsgNmId></OrgnlMsgNmId>
<OrgnlNbOfTxs></OrgnlNbOfTxs>
<OrgnlCtrlSum></OrgnlCtrlSum>
<GrpSts>ACCP</GrpSts>
</OrgnlGrpInfAndSts>
</CstmrPmtStsRpt>
</Document>
Use the namespace attribute of xsl:element like this:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="*">
<xsl:element name="{local-name()}" namespace="MyNamespace">
<xsl:namespace name="xsi" select="'http://www.w3.org/2001/XMLSchema-instance'"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Edit: Since you need to work with XSLT-1.0. Use following stylesheet:
<?xml version="1.0" encoding="UTF-16"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/Document">
<Document xmlns="MyNamespace"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:apply-templates/>
</Document>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{local-name()}" namespace="MyNamespace">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Note, that you need to know your rootnode's name for this (in this case Document).
BizTalk Answer:
First, it's a good thing the incoming document has no namespace. Xml Namespaces are far, far, far more trouble than they're worth and should be avoided/removed whenever possible.
Second the output format is not valid Xml. "MyNamespace" is not a valid URI and can't be used for a Namespace. If this is what they are asking for, they need to fix that first.
But, if you must, your process should not be "add a namespace". What you're really doing is Transforming from SysA's Document to SysB's Document. For that, use a Map. You will use to practially identical Schemas, one with and one without the Target Namespace.
The Mapper will handle xsi for you as well, if it's needed.
I have a incoming SOAP message like below:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns3:GetImageResponse xmlns="urn:webservice/server/mobile/shoebox/types/v1/CustomImage" xmlns:ns2="urn:webservice/server/mobile/shoebox/types/v1/common/ShoeboxCommonArtifacts" xmlns:ns3="urn:webservice/server/mobile/shoebox/types/v1/Image" xmlns:ns4="urn:webservice/server/mobile/shoebox/types/v1/common/exceptions" xmlns:ns5="urn:webservice/server/mobile/shoebox/types/v1/GetThumbnailImage">
<ns3:returnCode>105</ns3:returnCode>
<ns3:errorText>Invalid Participant code/id.</ns3:errorText>
<ns3:shoeboxImage xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
</ns3:GetImageResponse>
</soap:Body>
</soap:Envelope>
Need to transform into another simple XML like Below: (Constraint - The root element under BODY of SOAP envelope (ex- if "GetImageResponse" coming we need construct "GetImage" element in output XML) and it is not constant it can be any element So need to construct XML based on the root element under BODY , Ex shown below)
<?xml version="1.0" encoding="UTF-8"?>
<tns:GetImage xmlns:bons1="http://highmark.com/rbssvc/messages/common" xmlns:tns="http://www.example.org/GetImageResponseMessage/" xmlns:tns1="http://www.example.org/GetImageResponse/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.org/GetImageResponseMessage/ ../xsd/GetImageResponseMessage.xsd ">
<payload>
<returnCode>returnCode</returnCode>
<errorText>errorText</errorText>
<imageData>MA==</imageData>
</payload>
I am using this below XSLT to transform:
<xsl:stylesheet extension-element-prefixes="dp" exclude-result-prefixes="dp regex" version="1.0" xmlns:dp="http://www.datapower.com/extensions" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:regex="http://exslt.org/regular-expressions">
<xsl:template match="/">
<GetImage>
<xsl:element name="{'Payload'}">
<xsl:copy-of select="/*/*[local-name()='Body']/*[local-name()='GetImageResponse']/*"/>
</xsl:element>
</GetImage>
</xsl:template>
</xsl:stylesheet>
But i am not getting the desired XML output shown above
The out put which i am getting is :
<GetImageResponse>
<Payload>
<ns3:returnCode xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns5="urn:webservice/server/mobile/shoebox/types/v1/GetThumbnailImage" xmlns:ns4="urn:webservice/server/mobile/shoebox/types/v1/common/exceptions" xmlns:ns3="urn:webservice/server/mobile/shoebox/types/v1/Image" xmlns:ns2="urn:webservice/server/mobile/shoebox/types/v1/common/ShoeboxCommonArtifacts" xmlns="urn:webservice/server/mobile/shoebox/types/v1/CustomImage">105</ns3:returnCode>
<ns3:errorText xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns5="urn:webservice/server/mobile/shoebox/types/v1/GetThumbnailImage" xmlns:ns4="urn:webservice/server/mobile/shoebox/types/v1/common/exceptions" xmlns:ns3="urn:webservice/server/mobile/shoebox/types/v1/Image" xmlns:ns2="urn:webservice/server/mobile/shoebox/types/v1/common/ShoeboxCommonArtifacts" xmlns="urn:webservice/server/mobile/shoebox/types/v1/CustomImage">Invalid Participant code/id.</ns3:errorText>
<ns3:shoeboxImage xsi:nil="true" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns5="urn:webservice/server/mobile/shoebox/types/v1/GetThumbnailImage" xmlns:ns4="urn:webservice/server/mobile/shoebox/types/v1/common/exceptions" xmlns:ns3="urn:webservice/server/mobile/shoebox/types/v1/Image" xmlns:ns2="urn:webservice/server/mobile/shoebox/types/v1/common/ShoeboxCommonArtifacts" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:webservice/server/mobile/shoebox/types/v1/CustomImage"/>
</Payload>
</GetImageResponse>
The issue is here like i am not able to copy the name space of incoming soap message Like element "GetImageResponse" and some extra namespace are also coming for element "payload" .enter code here
Any idea how i can transform from SOAP message to the desired XML output.
Quick reply appreciated.
Regards
Rj
Well the redundant xmlns declarations are visual noise, but functionally not a problem. However you can fix this by making sure you set the necessary xmlns declarations on the root element of the result that you generate. In your case this is: <GetImage>.
You'll note that in your stylesheet the GetImage element is in the default namespace of the document which contains the XSLT stylesheet, which is also not specified.
Example:
<!--
namespace GetImage and
set up additional namespace mapping for ns5 prefix
for any copied elements which may be injected
-->
<tns:GetImage xmlns:tns="tns-uri" xmlns:ns5="ns5-uri">
<!-- more stuff here -->
</tns:GetImage>
Next up your <xsl:element name="{'Payload'}"> call also does not inject a namespace. You can either use the namespace attribute of xsl:element to associate the generated element with the desired namespace (URI), or you can use the syntax {prefix}:{local-name} in the name attribute and add the appropriate xmlns:prefix declarations.
Examples:
<xsl:element name="foo" namespace="bar"/>
<!-- needs xmlns:ns declaration -->
<xsl:element name="ns:foo"/>
<!-- substantially the same, using 'expressions' instead of 'literals' -->
<xsl:element name="{$nsPrefix}:{local-name()}">
Your question is not entirely clear. I think you want to do something like this:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns3="urn:webservice/server/mobile/shoebox/types/v1/Image"
xmlns:my="http://www.example.com/my"
exclude-result-prefixes="soap ns3 my">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<my:ns-holder xmlns:bons1="http://highmark.com/rbssvc/messages/common" xmlns:tns1="http://www.example.org/GetImageResponse/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.org/GetImageResponseMessage/ ../xsd/GetImageResponseMessage.xsd "/>
<xsl:template match="/soap:Envelope/soap:Body/*">
<xsl:element name="tns:{local-name()}" xmlns:tns="http://www.example.org/GetImageResponseMessage/">
<xsl:copy-of select="document('')/xsl:stylesheet/my:ns-holder/namespace::*"/>
<payload>
<returnCode>
<xsl:value-of select="ns3:returnCode" />
</returnCode>
<errorText>
<xsl:value-of select="ns3:errorText" />
</errorText>
<imageData>MA==</imageData>
</payload>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
What this does is:
Create a root element whose local name is the same as the name of
the child of soap:Body, assign it a tns: prefix and bind the
prefix to the "http://www.example.org/GetImageResponseMessage/'
namespace. Note that this assumes there will be only one such child.
Add a bunch of namespaces to the above root element. Note that these
namespaces are not actually used in the result - and as such are
entirely redundant.
Create the payload and its value nodes. Note that you cannot use
xsl:copy here, because that would also copy the original node's
namespace (ns3 in this example).
Applied to your input example, the result here will be:
<?xml version="1.0" encoding="UTF-8"?>
<tns:GetImageResponse xmlns:tns="http://www.example.org/GetImageResponseMessage/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns3="urn:webservice/server/mobile/shoebox/types/v1/Image" xmlns:my="http://www.example.com/my" xmlns:bons1="http://highmark.com/rbssvc/messages/common" xmlns:tns1="http://www.example.org/GetImageResponse/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<payload>
<returnCode>105</returnCode>
<errorText>Invalid Participant code/id.</errorText>
<imageData>MA==</imageData>
</payload>
</tns:GetImageResponse>
I did not understand:
How exactly should GetImageResponse be tranformed into GetImage;
Where is the imageData value ("MA==") supposed to come from.
this is my xml
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:end="http://endpoint.ggg.com/">
<soapenv:Header/>
<soapenv:Body>
<end:onlineExpressRemit>
<channelCode>NBPS</channelCode>
</end:onlineExpressRemit>
</soapenv:Body>
</soapenv:Envelope>
and this is my xslt
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:end="http://endpoint.ggg.com/" >
<xsl:template match="/">
<xsl:value-of name="ggg2" select="/soapenv:Envelope/soapenv:Body/*[namespace-uri()]"/>
</xsl:template>
</xsl:stylesheet>
my expected output is display only
onlineExpressRemit
i am very new for xslt, i try name(), local-name() alot others method, however no luck, i cant retrieve only node-name, any help will do, thank you!
You can try using local-name(soapenv:Envelope/soapenv:Body/*), for example, the following XSL transformation :
<xsl:stylesheet version="1.0" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:end="http://endpoint.ggg.com/" >
<xsl:output method="text" omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:element name="root">
<xsl:value-of select="local-name(soapenv:Envelope/soapenv:Body/*)"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
when applied to your XML sample, yield the following output :
<root>onlineExpressRemit</root>
Note: I added <root> element just because in online XSLT processor I used for testing, there was error when root element is absent. Usually, setting <xsl:output> is enough to be able to output a non-XML result : XSLT: Transforming into non-xml content?
Consider the following XSL transformation:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
xmlns:dyn="http://exslt.org/dynamic"
extension-element-prefixes="dyn">
<xsl:variable name="_raw">
<test>1</test>
<test>2</test>
</xsl:variable>
<xsl:variable name="list" select="exsl:node-set($_raw)"/>
<xsl:template match="/">
<result>
<xsl:for-each select="$list/test">
<loop>
<xsl:value-of select="dyn:evaluate('exsl:node-set($list)/test')"/>
</loop>
</xsl:for-each>
</result>
</xsl:template>
</xsl:transform>
Executing this on any input gives:
<?xml version="1.0" encoding="UTF-8"?>
<result xmlns:exsl="http://exslt.org/common">
<loop>1</loop>
<loop/>
</result>
What I don't understand is:
The esxl:note-set() inside dyn:evaluate() is necessary if I want to reference $list in the XPath string. Otherwise, the first <loop> is also empty. Why? $list is already a node set.
It's exactly the same code executed twice. Why does it yield no result the second time?
This works if I don't take the values from $list, but from the XML input instead. Where's the difference?
If I remove the <xsl:for-each>, dyn:evaluate() works without the exsl:node-set() in it. Why? There's no reference to the context in the expression that is evaluated, it shouldn't make a difference.
My XSLT processor is Xalan 2.7.2.
I believe what you want to do is:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
xmlns:dyn="http://exslt.org/dynamic"
extension-element-prefixes="exsl dyn">
<xsl:variable name="_raw">
<test>1</test>
<test>2</test>
</xsl:variable>
<xsl:variable name="list" select="exsl:node-set($_raw)"/>
<xsl:template match="/">
<result>
<xsl:for-each select="$list/test">
<loop>
<xsl:value-of select="dyn:evaluate(.)"/>
</loop>
</xsl:for-each>
</result>
</xsl:template>
</xsl:transform>
Which will result in:
<?xml version="1.0" encoding="UTF-8"?>
<result><loop>1</loop><loop>2</loop></result>
Edit:
I am still not sure what you are after here, but let me point out a few details:
It's exactly the same code executed twice. Why does it yield no result
the second time?
That may be a bug in Xalan. If you run your code with libxslt, the result will be:
<?xml version="1.0"?>
<result xmlns:exsl="http://exslt.org/common"><loop>1</loop><loop>1</loop></result>
The esxl:note-set() inside dyn:evaluate() is necessary if I want to
reference $list in the XPath string. Otherwise, the first is
also empty. Why? $list is already a node set.
I don't think it's necessary. Or perhaps I don't understand what it's necessary for. In any case, changing this:
<loop>
<xsl:value-of select="dyn:evaluate('exsl:node-set($list)/test')"/>
</loop>
to:
<loop>
<xsl:value-of select="dyn:evaluate('$list/test')"/>
</loop>
will result in:
<?xml version="1.0" encoding="UTF-8"?>
<result xmlns:exsl="http://exslt.org/common"><loop>1</loop><loop>1</loop></result>
and this time the result is same for both Xalan and libxslt.
I have a specific problem getting values for width and height out of some XML that has namespace prefixes defined. I can get other values such as SomeText from RelatedMaterial quite easily using normal xpath with namespace "n:" but unable to get values for width and height.
Sample XML:
<Description>
<Information>
<GroupInformation xml:lang="en">
<BasicDescription>
<RelatedMaterial>
<SomeText>Hello</SomeText>
<t:ContentProperties>
<t:ContentAttributes>
<t:Width>555</t:Width>
<t:Height>444</t:Height>
</t:ContentAttributes>
</t:ContentProperties>
</RelatedMaterial>
</BasicDescription>
</GroupInformation>
</Information>
</Description>
Here is an extract from the XSLT:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:n="urn:t:myfoo:2010" xmlns:tva2="urn:t:myfoo:extended:2008"
<xsl:apply-templates select="n:Description/n:Information/n:GroupInformation"/>
<xsl:template match="n:GroupInformation">
<width>
<xsl:value-of select="n:BasicDescription/n:RelatedMaterial/t:ContentProperties/t:ContentAttributes/t:Width"/>
</width>
</xsl:template>
The above XSLT does not work for getting the width. Any ideas?
I'm not sure you have realised that both your input and XSLT is invalid, it's always better to provide working examples.
Anyway, if we look at the XPath expression n:BasicDescription/n:RelatedMaterial/t:ContentProperties/t:ContentAttributes/t:Width you're using a prefix n which is mapped to urn:t:myfoo:2010 but when the data infact is in the default namespace. The same goes for the t prefix which isn't defined at all in neither the input data nor XSLT.
You need to define the namespaces on "both sides", in the XML data and the XSLT transformation and they need to be the same, not the prefixes, but the URI.
Somebody else could probably explain this better than me.
I've corrected your example and added a few things to make this work.
Input:
<?xml version="1.0" encoding="UTF-8"?>
<Description
xmlns="urn:t:myfoo:2010"
xmlns:t="something...">
<Information>
<GroupInformation xml:lang="en">
<BasicDescription>
<RelatedMaterial>
<SomeText>Hello</SomeText>
<t:ContentProperties>
<t:ContentAttributes>
<t:Width>555</t:Width>
<t:Height>444</t:Height>
</t:ContentAttributes>
</t:ContentProperties>
</RelatedMaterial>
</BasicDescription>
</GroupInformation>
</Information>
</Description>
XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
xmlns:n="urn:t:myfoo:2010"
xmlns:t="something...">
<xsl:template match="/">
<xsl:apply-templates select="n:Description/n:Information/n:GroupInformation"/>
</xsl:template>
<xsl:template match="n:GroupInformation">
<xsl:element name="width">
<xsl:value-of select="n:BasicDescription/n:RelatedMaterial/t:ContentProperties/t:ContentAttributes/t:Width"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Output:
<?xml version="1.0" encoding="UTF-8"?>
<width>555</width>