Unable to properly add a namespace using XSLT - xslt

I am having one problem.
Below XML is getting generated using a Oracle BPEL Process
<gdspCreateVpnNumberList xmlns:ws="http://ws.abc.com/" xmlns="http://ws.abc.com/">
<ws:numberListName>SampleList105</ws:numberListName>
<ws:numberListDesc>Desc</ws:numberListDesc>
<ws:selectedCustomerId>200</ws:selectedCustomerId>
<ws:numbersList>
<ws:number>21</ws:number>
</ws:numbersList>
</gdspCreateVpnNumberList>
I have applied below xslt to reach above desired input:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ws="http://ws.abc.com/">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="*">
<xsl:element name="ws:{local-name(.)}"
namespace="http://ws.abc.com/">
<xsl:apply-templates />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
But, I am unable to generate the actual request which I require:
<ws:gdspCreateVpnNumberList xmlns:ws="http://ws.abc.com/">
<numberListName>SampleList105</ws:numberListName>
<numberListDesc>Desc</ws:numberListDesc>
<selectedCustomerId>200</ws:selectedCustomerId>
<numbersList>
<number>21</ws:number>
</numbersList>
</ws:gdspCreateVpnNumberList>
Output:
<gdspCreateVpnNumberListResponse xmlns:msgns="http://ws.abc.com/" xmlns="http://ws.abc.com/">
<return xmlns="">
<returnCode>
<majorReturnCode>100</majorReturnCode>
<minorReturnCode>7042</minorReturnCode>
</returnCode>
</return>
</gdspCreateVpnNumberListResponse>
Really appreciate your help on this...
Regards,
Ankit

Your requested output seems very odd with all elements except the first being in no-namespace, but this generates:
result:
<ws:gdspCreateVpnNumberList xmlns:ws="http://ws.abc.com/">
<numberListName>SampleList105</numberListName>
<numberListDesc>Desc</numberListDesc>
<selectedCustomerId>200</selectedCustomerId>
<numbersList>
<number>21</number>
</numbersList>
</ws:gdspCreateVpnNumberList>
xsl:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ws="http://ws.abc.com/">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<xsl:element name="ws:{local-name(.)}"
namespace="http://ws.abc.com/">
<xsl:apply-templates />
</xsl:element>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{local-name(.)}">
<xsl:apply-templates />
</xsl:element>
</xsl:template>
</xsl:stylesheet>

Related

XSLT 1.0, copy all child nodes except some

I am trying to copy all child nodes to a specific node, except a few. Haven't been able to get this to work? Any pointers of what I am doing wrong?
Using this XML:
<ns0:Envelope xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/">
<ns0:Header>
<wsse:Sec xmlns:wsse="http://docs.x.org/wsse/">
<saml:Ass xmlns:saml="http://docs.x.org/saml/">
<ds:Sign xmlns:ds="http://docs.x.org/ds/">
<ds:SignVal>SignatureValue</ds:SignVal>
</ds:Sign>
<saml:subj>SubjectValue</saml:subj>
</saml:Ass>
</wsse:Sec>
<To>http://localhost:8080/Test/</To>
<Action>SendTest</Action>
</ns0:Header>
<ns0:Body>...</ns0:Body>
</ns0:Envelope>
The wanted result is to just get the Sec tag and all children:
<wsse:Sec xmlns:wsse="http://docs.x.org/wsse/">
<saml:Ass xmlns:saml="http://docs.x.org/saml/">
<ds:Sign xmlns:ds="http://docs.x.org/ds/">
<ds:SignVal>SignatureValue</ds:SignVal>
</ds:Sign>
<saml:subj>SubjectValue</saml:subj>
</saml:Ass>
</wsse:Sec>
I have tried numerous XSL including this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:template match="Header">
<xsl:copy-of select="*"/>
</xsl:template>
<!-- Exclude these -->
<xsl:template match="To" />
<xsl:template match="Action" />
</xsl:stylesheet>
The result is I get values but no tags...
You have not accounted for namespaces in your XSLT. In your XML, Header is in namespace http://schemas.xmlsoap.org/soap/envelope/, but your XSLT is trying to match a Header in no namespace.
You need to declare the namespaces in your XSLT, and use them in the template matches
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:wsse="http://docs.x.org/wsse/">
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:template match="ns0:Header">
<xsl:copy-of select="wsse:Sec"/>
</xsl:template>
<xsl:template match="ns0:Body" />
</xsl:stylesheet>
Note this XSLT doesn't need templates matching "To" and "Action" because of the explicit copy of wsse:Sec using this approach. However, you do need to template to ensure any test within ns0:Body isn't picked up.
Another approach is to use the identity template, and then you would have the templates to exclude To and Action (and Body)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:wsse="http://docs.x.org/wsse/">
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ns0:Envelope|ns0:Header">
<xsl:apply-templates />
</xsl:template>
<!-- Exclude these -->
<xsl:template match="ns0:Body|To|Action" />
</xsl:stylesheet>
Note there is a template matching ns0:Envelope and ns0:Header as although you don't want these elements themselves, you do need to process the child nodes.
You would need to use XSLT 2 or 3 with
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:wsse="http://docs.x.org/wsse/"
exclude-result-prefixes="#all"
version="3.0">
<xsl:template match="/">
<xsl:copy-of select="//wsse:Sec" copy-namespaces="no"/>
</xsl:template>
</xsl:stylesheet>
to get the posted result with a simple copy instruction: https://xsltfiddle.liberty-development.net/bnnZVw
In XSLT 1 the copy will always copy the in-scope namespace xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/" so to remove it from the result you would need to run your code through some kind of transformation stripping in-scope namespaces (other than the one of the element itself):
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:wsse="http://docs.x.org/wsse/"
exclude-result-prefixes="wsse"
version="1.0">
<xsl:template match="#*">
<xsl:attribute name="{name()}" namespace="{namespace-uri()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:apply-templates select="#* | node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="//wsse:Sec"/>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/bnnZVw/1

Convert string to binary base64

Is there any way on how to convert a string to binary base64? I've seen many references but it didn't work in my end. For example I have this input file:
<RootElement xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Data>
<Binary>
<RawData>This element should convert string to binary base64.</RawData>
</Binary>
</Data>
</RootElement>
I need to generate:
<RootElement xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Data>
<Binary>
<RawData>VGhpcyBlbGVtZW50IHNob3VsZCBjb252ZXJ0IHN0cmluZyB0byBiaW5hcnkgYmFzZTY0Lg==</RawData>
</Binary>
</Data>
I created an xslt and used the namespace I've seen online:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dp="http://www.datapower.com/extensions">
<xsl:output method="xml" version="1.0" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="RawData">
<xsl:element name="RawData">
<xsl:value-of select="dp:encode(., 'base-64')"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Thank you.
There is a pure XSLT 1.0 solution that works for any XSLT processor: JAXP, Saxon, Xalan, Xsltproc, Microsoft:
Download base64.xsl
Download base64_binarydatamap.xml
Use XSLT 1.0:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:b64="https://github.com/ilyakharlamov/xslt_base64">
<xsl:output method="xml"/>
<xsl:include href="base64.xsl"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="/RootElement/Data/Binary/RawData">
<xsl:call-template name="b64:encode">
<xsl:with-param name="asciiString" select="text()"/>
</xsl:call-template>
</xsl:template>
</xsl:stylesheet>

Using xslt to change an attribute value using arithmetic operations

I'm trying to bound the value of an xml attribute using xslt/xpath 1.0. In this example, it would be the id attribute on the m_m element.
<blart>
<m_data>
<m_m name="arggg" id="99999999" subs="asas"/>
</m_data>
<m_data>
<m_m name="arggg" id="99" subs="asas"/>
</m_data>
</blart>
If the id is greater then 20000 it gets set to 20000. I have the following xslt. I know it selects the correct node and attribute. It obviously is just outputing 20000. I realize I should have some sort of xpath logic in there but I'm having a hard time developing it. I have some big holes in my knowledge of xpath and xslt. If you can point me in the right direction in helping me understand on what I should be doing I would really appreciate it.
<?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" indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match ="m_data/m_m/#id[.> 20000]">20000 </xsl:template>
</xsl:stylesheet>
The expected output would be
<blart>
<m_data>
<m_m name="arggg" id="20000" subs="asas"/>
</m_data>
<m_data>
<m_m name="arggg" id="99" subs="asas"/>
</m_data>
</blart>
You can use the following XSLT that gives flexibility to the attribute you want to change, and keeps everything else as it is:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match ="m_data/m_m/#id[. > 20000]">
<xsl:attribute name="id">20000</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
Why don't you 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:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match ="m_m/#id[. > 20000]">
<xsl:attribute name="id">20000</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
NOTE: Since I posted this, much better answers were contributed (see here and here). SO won't let me delete this one because it was accepted, but in all fairness and for the sake of quality, I should encourage you to upvote the two aforementioned answers, so that they stand out over this one.
How about this:
<?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" indent="yes"/>
<xsl:template match="m_m">
<m_m>
<xsl:copy-of select="#*" />
<xsl:if test="#id > 20000">
<xsl:attribute name="id">20000</xsl:attribute>
</xsl:if>
</m_m>
</xsl:template>
<xsl:template match="m_data">
<m_data>
<xsl:apply-templates select="m_m" />
</m_data>
</xsl:template>
<xsl:template match="/blart">
<blart>
<xsl:apply-templates select="m_data" />
</blart>
</xsl:template>
</xsl:stylesheet>

how to remove a part of attribut to a node in xml file using xslt

I have the following xml code:
<OML>
<bg-def xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="EX1"/>
</OML>
I want to remove the attribute xmlns:xsi and its value using XSLT, so that the result will look like this:
<OML>
<bg-def name="EX1"/>
</OML>
I tryied to do this with the following XSLT code:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:ex="http://exslt.org/dates-and-times" extension-element-prefixes="ex">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="no" xml:space="preserve"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="bg-def|# xmlns:xsi"/>
</xsl:transform>
Before I finished to write my code, my editor warned me that:
"W Namespace prefix xmlns has not been declared".
When I remove the expression :xsi and just write xmlns, there is no warning more. But when I compile and execute my program, nothing happens and I don't get the expected output.
I try also to change the last line of my xslt file with this:
<xsl:template match="bg-def|# name"/>
then the result is looking like this:
<OML>
<bg-def xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
</OML>
That means, the attribute name has been removed very well. But I want to do this with the attribute xmlns:xsi.
Can someone help me to do this please?
Thanks for any help.
Franky
Use following template for bd-def node:
<xsl:template match="bg-def">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
Instead of
<xsl:template match="bg-def|# name"/>
This template will create node bg-def and copy all it context nodes and attributes, but not namespaces
Check similar question:
remove namespace for a perticular element
Update:
Source file:
<OML>
<bg-def xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="EX1"/>
</OML>
Stylesheet:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:ex="http://exslt.org/dates-and-times" extension-element-prefixes="ex">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="no" xml:space="preserve"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="bg-def">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
</xsl:transform>
Transformation result (Saxon 6.5.5 - Xslt 1.0):
<?xml version="1.0" encoding="UTF-8"?><OML>
<bg-def name="EX1"/>
</OML>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"/>
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="#*"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="#*">
<xsl:attribute name="{local-name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>

Remove xsi:type using xslt

I have following XML. I was able to remove all namespaces but not able to remove xsi:type using XSL.
XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<StudentResult xmlns='http://ns.xyz.org/2004-08-02' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:ns1='http://ns.xyz.org/2004-08-02' xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:type='ns1:StudentResult'>
<StudentId idOwner='xyz'><IdValue name='ClientId'>9103-XML</IdValue></StudentId>
<ClientOrderId idOwner='Cloud'><IdValue name='OrderNumber'>272454</IdValue></ClientOrderId>
<Results>false</Results>
</StudentResult>
Desired Output:
<?xml version="1.0" encoding="utf-8"?>
<StudentResult>
<StudentId idOwner="xyz"><IdValue name="ClientId">9103-XML</IdValue></StudentId>
<ClientOrderId idOwner="Cloud"><IdValue name="OrderNumber">272454</IdValue></ClientOrderId>
<Results>false</Results>
</StudentResult>
This is the xslt I used but it did not help.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" method="xml" encoding="utf-8" />
<xsl:template match="/|comment()|processing-instruction()">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="#*">
<xsl:attribute name="{local-name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="#*|node()|processing-instruction()"/>
</xsl:template>
</xsl:stylesheet>
Add a template
<xsl:template match="#xsi:type"/>
plus
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
exclude-result-prefixes="xsi">
on the stylesheet's root element.
This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()[not(self::*)]">
<xsl:copy/>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="#*[not(name()='xsi:type')]|node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="#*">
<xsl:attribute name="{local-name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<StudentResult
xmlns='http://ns.xyz.org/2004-08-02'
xmlns:xsd='http://www.w3.org/2001/XMLSchema'
xmlns:ns1='http://ns.xyz.org/2004-08-02'
xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xsi:type='ns1:StudentResult'>
<StudentId idOwner='xyz'>
<IdValue name='ClientId'>9103-XML</IdValue>
</StudentId>
<ClientOrderId idOwner='Cloud'>
<IdValue name='OrderNumber'>272454</IdValue>
</ClientOrderId>
<Results>false</Results>
</StudentResult>
produces the wanted, correct result:
<StudentResult>
<StudentId idOwner="xyz">
<IdValue name="ClientId">9103-XML</IdValue>
</StudentId>
<ClientOrderId idOwner="Cloud">
<IdValue name="OrderNumber">272454</IdValue>
</ClientOrderId>
<Results>false</Results>
</StudentResult>