Adding Namespace Attributes to the XML - xslt

We are trying to add two additional namespace/attributes in our XML file. The structure is an external definition (XSD) and we'd like to know if it would be possible if we can add two new attribute/namespaces via XSLT or this should be included in the external defintion? (Of course, updating the external defintion is the easiest way out.)
I've already looked at several questions here like:
adding attribute to the node
Adding namespace to child elements using xslt
XSLT transforming is throwing error
But I'm still clueless as to how to make this work. I'm a virgin with regard to XSLT - no experience at all. Would like to know if this is possible via XSLT.
As-is
<ns2:ProcessCommunication xmlns:ns2="http://URL">
<ns2:communication>
<ns2:CommunicationTemplateAbbreviation>INV</ns2:CommunicationTemplateAbbreviation>
<ns2:CommunicationValues>
<ns2:CommunicationValue>
<ns2:FinancialValue>205029</ns2:FinancialValue>
<ns2:Title>Net</ns2:Title>
</ns2:CommunicationValue>
</ns2:CommunicationValues>
<ns2:CustomFields>
<ns2:CustomField>
<ns2:Name>SomeValue</ns2:Name>
<ns2:Answer>
<ns2:Value>1</ns2:Value>
</ns2:Answer>
</ns2:CustomField>
<ns2:CustomField>
<ns2:Name>Transaction Currency</ns2:Name>
<ns2:Answer>
<ns2:Value>EUR</ns2:Value>
</ns2:Answer>
</ns2:CustomField>
</ns2:CustomFields>
</ns2:communication>
</ns2:ProcessCommunication>
To-be:
<ns2:ProcessCommunication xmlns:ns2="http://URL">
<ns2:communication>
<ns2:CommunicationTemplateAbbreviation>INV</ns2:CommunicationTemplateAbbreviation>
<ns2:CommunicationValues>
<ns2:CommunicationValue>
<ns2:FinancialValue>205029</ns2:FinancialValue>
<ns2:Title>Net</ns2:Title>
</ns2:CommunicationValue>
</ns2:CommunicationValues>
<ns2:CustomFields>
<ns2:CustomField>
<ns2:Name>SomeValue</ns2:Name>
<ns2:Answer>
<ns2:Value i:type="a:string" xmlns:a="http://www.w3.org/2001/XMLSchema">1</ns2:Value>
</ns2:Answer>
</ns2:CustomField>
<ns2:CustomField>
<ns2:Name>Transaction Currency</ns2:Name>
<ns2:Answer>
<ns2:Value i:type="a:string" xmlns:a="http://www.w3.org/2001/XMLSchema">EUR</ns2:Value>
</ns2:Answer>
</ns2:CustomField>
</ns2:CustomFields>
</ns2:communication>
</ns2:ProcessCommunication>
There's an additional
i:type="a:string" xmlns:a="http://www.w3.org/2001/XMLSchema"
in the node, Value.
I am only able to go until here, which is pretty useless.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance" >
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="node()">
<xsl:copy>
<xsl:attribute name="i:type">a:string</xsl:attribute>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
I try and use <xsl:template match="Answer/Value"> and this doesn't work.

You were just missing the namespace declaration on the XSLT itself. This should work:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns2="http://URL">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ns2:Answer/ns2:Value">
<xsl:copy>
<xsl:attribute name="i:type">a:string</xsl:attribute>
<xsl:attribute name="xmlns:a">http://www.w3.org/2001/XMLSchema</xsl:attribute>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

Related

Need to remove the prefix namespace in the output using XSLT

Is there any way on how to avoid populating the namespace of common: prefix in the output? And, this namespace should replace as a default namespace. I have this sample file:
INPUT:
<IntraConsignment xmlns="http://www.minfin.fgov.be/IntraConsignment" xmlns:common="http://www.minfin.fgov.be/InputCommon" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.minfin.fgov.be/IntraConsignment NewICO-in_v0_7.xsd" IntraListingsNbr="1">
<Representative>
<common:RepresentativeID identificationType="NVAT" issuedBy="BE">9876941603</common:RepresentativeID>
</Representative>
<IntraListing SequenceNumber="1" ClientsNbr="1" AmountSum="1000.00">
<Declarant>
<common:VATNumber>9876941603</common:VATNumber>
</Declarant>
<Period>
<Month>07</Month>
</Period>
<IntraClient SequenceNumber="1">
<CompanyVATNumber issuedBy="DE">123456</CompanyVATNumber>
</IntraClient>
</IntraListing>
</IntraConsignment>
And, I need to remove the common: prefix in the XML and the elements that doesn't have a prefix should have a ns2: prefix.
I have this stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns2="http://www.minfin.fgov.be/IntraConsignment" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:common="http://www.minfin.fgov.be/InputCommon" xmlns="http://www.minfin.fgov.be/InputCommon" exclude-result-prefixes="xs xsi xsl common">
<xsl:output encoding="UTF-8" indent="yes" method="xml" version="1.0"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="common:*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="*">
<xsl:element name="ns2:{local-name()}">
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
My xslt is quite working but the namespace xmlns="http://www.minfin.fgov.be/InputCommon" did not appear in the output.
GENERATED OUTPUT:
<ns2:IntraConsignment xmlns:ns2="http://www.minfin.fgov.be/IntraConsignment" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.minfin.fgov.be/IntraConsignment NewICO-in_v0_7.xsd" IntraListingsNbr="1">
<ns2:Representative>
<RepresentativeID xmlns="http://www.minfin.fgov.be/InputCommon" identificationType="NVAT" issuedBy="BE">9876941603</RepresentativeID>
</ns2:Representative>
<ns2:IntraListing SequenceNumber="1" ClientsNbr="1" AmountSum="1000.00">
<ns2:Declarant>
<VATNumber xmlns="http://www.minfin.fgov.be/InputCommon">9876941603</VATNumber>
</ns2:Declarant>
<ns2:Period>
<ns2:Month>07</ns2:Month>
</ns2:Period>
<ns2:IntraClient SequenceNumber="1">
<ns2:CompanyVATNumber issuedBy="DE">123456</ns2:CompanyVATNumber>
<ns2:Amount>1000.00</ns2:Amount>
</ns2:IntraClient>
</ns2:IntraListing>
</ns2:IntraConsignment>
EXPECTED:
<ns2:IntraConsignment xmlns:ns2="http://www.minfin.fgov.be/InputCommon" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.minfin.fgov.be/IntraConsignment NewICO-in_v0_7.xsd" xmlns="http://www.minfin.fgov.be/InputCommon" IntraListingsNbr="1">
<ns2:Representative>
<RepresentativeID identificationType="NVAT" issuedBy="BE">9876941603</RepresentativeID>
</ns2:Representative>
<ns2:IntraListing SequenceNumber="1" ClientsNbr="1" AmountSum="1000.00">
<ns2:Declarant>
<VATNumber>9876941603</VATNumber>
</ns2:Declarant>
<ns2:Period>
<ns2:Month>07</ns2:Month>
</ns2:Period>
<ns2:IntraClient SequenceNumber="1">
<ns2:CompanyVATNumber issuedBy="DE">123456</ns2:CompanyVATNumber>
<ns2:Amount>1000.00</ns2:Amount>
</ns2:IntraClient>
</ns2:IntraListing>
</ns2:IntraConsignment>
With XSLT 1.0 the choice of namespace prefixes is left largely to the XSLT processor, whereas XSLT 2.0 is much more prescriptive. However, most XSLT 1.0 processors do the "right thing" even though they're not strictly required to.
You basically seem to have two rules:
(a) elements in namespace http://www.minfin.fgov.be/IntraConsignment should be copied using the prefix ns2:
<xsl:template match="x:*" xmlns:x="http://www.minfin.fgov.be/IntraConsignment">
<xsl:element name="ns2:{local-name()}" namespace="http://www.minfin.fgov.be/IntraConsignment">
<xsl:copy-of select="#*"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
(b) elements in namespace http://www.minfin.fgov.be/InputCommon should be output in the default namespace:
<xsl:template match="x:*" xmlns:x="http://www.minfin.fgov.be/InputCommon">
<xsl:element name="{local-name()}" namespace="http://www.minfin.fgov.be/InputCommon">
<xsl:copy-of select="#*"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>

How do I rename an XML element with the value of its first attribute using XSLT?

I am new to XSLT and have XML structures that look like this:
<Loop LoopId="1000A" Name="SUBMITTER NAME">
.... a bunch of sub-elements, etc.
</Loop>
I am trying to write an XSLT that will convert them all to this:
(concatenate the value of the LoopId attribute to its parent element name)
<Loop1000A LoopId="1000A" Name="SUBMITTER NAME">
.... a bunch of sub-elements, etc.
</Loop1000A>
I have a style sheet that gets me almost all of the way there, but it is getting rid of the attribute LoopId and I don't know why - the style sheet below produces this result:
<Loop1000A Name="SUBMITTER NAME">
.... a bunch of sub-elements, etc.
</Loop1000A>
Is there a way to modify it so I keep the LoopId attribute?
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="#LoopId"/>
<xsl:template match="*[#LoopId]">
<xsl:variable name="vRep" select="concat('Loop',#LoopId)"/>
<xsl:element name="{$vRep}">
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Thanks
Remove the template <xsl:template match="#LoopId"/> as that way you remove the LoopId attribute.
Change:
<xsl:element name="concat('Loop', #LoopId)">
to:
<xsl:element name="{concat('Loop', #LoopId)}">
See:
https://www.w3.org/TR/xslt/#attribute-value-templates

replace namespace prefix and add attributes using XSLT

suppose I have following XML as source:
<ns0:msg xmlns:ns0="namespace0">
<ns0:hdr a_lot_of_attrs="value">
some nodes...
</ns0:hdr>
<ns0:body>
<ns0:data a_lot_of_attrs="value">
<ns1:purchase_order xmlns:ns1="namespace1">some nodes...</ns1:purchase_order>
</ns0:data>
</ns0:body>
</ns0:msg>
And I need following XML as the result:
<a:msg xmlns:a="namespace0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<a:hdr a_lot_of_attrs="value">
some nodes...
</a:hdr>
<a:body>
<a:data a_lot_of_attrs="value">
<b:purchase_order
xsi:schemaLocation="filelocation"
xmlns:b="namespace1"
xmlns:c="namespace2">some nodes...</b:purchase_order>
</a:data>
</a:body>
</a:msg>
Basically I need just to replace the namespace prefix ns0 into a and ns1 into b. Further more, the root element <a:msg> as well as the <b:purchase_order> need to be added by some additional attributes.
My attemp is by using following XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="namespace0"
xmlns:ns1="namespace1"
xmlns:a="namespace0"
xmlns:b="namespace1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
exclude-result-prefixes="ns0 ns1">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<a:msg xmlns:msg="namespace1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:copy>
<xsl:apply-templates select="ns0:msg/*"/>
</xsl:copy>
</a:msg>
</xsl:template>
<xsl:template match="/ns0:msg/ns0:body/ns0:data/ns1:purchase_order">
<b:purchase_order xsi:schemaLocation="filelocation" xmlns:c="namespace2">
<xsl:copy>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</b:purchase_order>
</xsl:template>
<xsl:template match="ns0:*">
<xsl:element name="a:{local-name()}">
<xsl:apply-templates select="#* | node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="ns1:*">
<xsl:element name="b:{local-name()}">
<xsl:apply-templates select="#* | node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="#*">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
It works fine so far, except the node <purchase_order> has been populated 2 times:
<a:msg xmlns:a="namespace0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<a:hdr a_lot_of_attrs="value">
some nodes...
</a:hdr>
<a:body>
<a:data a_lot_of_attrs="value">
<b:purchase_order xmlns:b="namespace1" xmlns:c="namespace2" xsi:schemaLocation="filelocation">
<ns1:purchase_order xmlns:ns0="namespace0" xmlns:ns1="namespace1">some nodes...</ns1:purchase_order>
</b:purchase_order>
</a:data>
</a:body>
</a:msg>
I tried several times by tweaking the second <xsl:template> but could not get it right. Would someone pls advise where I get wrong here and how can I get this done?
Thanks a lot.
You current template that matches ns1:purchase_order contains an xsl:copy as well as the creation of the new b:purchase_order. Therefore you are copying the old node as well as creating a new one.
You can remove the xsl:copy from the template, like so:
<xsl:template match="ns1:purchase_order">
<b:purchase_order xsi:schemaLocation="filelocation" xmlns:c="namespace2">
<xsl:apply-templates select="node()"/>
</b:purchase_order>
</xsl:template>
Note that you don't necessarily have to specify the full path in the template match. You would only really need to do this if you had a second ns1:purchase_order in the XML, at a different location, that you didn't want to match.

how to change a text of element in a parent tag using xslt

I want to replace the element tag name using xslt. I have an output like this:
<gl-cor:documentInfo>
<gl-cor:entriesType contextRef="journal_context">DocumentID</gl-cor:entriesType>
<gl-cor:uniqueID contextRef="journal_context">RevisionID</gl-cor:uniqueID>
</gl-cor:documentInfo>
<gl-cor:entityInformation>
<gl-cor:entityPhoneNumber>
<gl-cor:phoneNumber contextRef="journal_context">779633</gl-cor:phoneNumber>
</gl-cor:entityPhoneNumber>
<gl-cor:entityFaxNumberStructure>
<gl-cor:entityFaxNumbercontextRef="journal_context">1234-56-89</gl-cor:entityFaxNumber>
</gl-cor:entityFaxNumberStructure>
</gl-cor:entityInformation>
And, I want my output to be looks like this:
<gl-cor:documentInfo>
<gl-cor:entriesType contextRef="journal_context">DocumentID</gl-cor:entriesType>
<gl-bus:uniqueID contextRef="journal_context">RevisionID</gl-cor:uniqueID>
</gl-cor:documentInfo>
<gl-cor:entityInformation>
<gl-bus:entityPhoneNumber>
<gl-bus:phoneNumber contextRef="journal_context">779633</gl-bus:phoneNumber>
</gl-bus:entityPhoneNumber>
<gl-bus:entityFaxNumberStructure>
<gl-bus:entityFaxNumbercontextRef="journal_context">1234-56-89</gl-bus:entityFaxNumber>
</gl-bus:entityFaxNumberStructure>
</gl-cor:entityInformation>
All the children of <gl-cor:entityInformation> should replace instead of gl-cor, it should be gl-bus. Is it possible to do this?
I tried to create a sample xslt but it didn't work. The error occurs in the <gl-bus:phoneNumber>, because I think it is contain a special characters? like "-" and ":".
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="gl-cor:entityInformation/gl-cor:entityPhoneNumber/gl-cor:phoneNumber">
<gl-bus:phoneNumber>
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</gl-bus:phoneNumber>
</xsl:template>
Can someone help me solve this problem? Thanks alot.
First of all gl-cor and gl-bus are namespace prefixes. Namespace prefixes are written before an XML element and seperated from the XML element with a :. So your problem is not because of the characters - and :, these are all valid characters, please also read these articles/tutorials:
http://www.w3schools.com/xml/xml_namespaces.asp
http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references#Predefined_entities_in_XML
To answer your problem we need to know what the namspace URIs are for gl-cor and gl-bus, but it should look like this:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:gl-cor="http://example.org/gl-cor" xmlns:gl-bus="http://example.org/gl-bus">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="*[ancestor::gl-cor:entityInformation]">
<xsl:element name="gl-bus:{local-name()}">
<xsl:apply-templates select="#*|node()" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
The template *[ancestor::gl-cor:entityInformation] will match on all (grand)children of gl-cor:entityInformation.
NOTE
The namespaces in the XSLT should be updated and match to your input XML:
xmlns:gl-cor="http://example.org/gl-cor"
xmlns:gl-bus="http://example.org/gl-bus"

Updating XML node using XSLT

<Instance xsi:type="ButtonConfig">
<Name>ExitButton</Name>
<Height>89</Height>
<Width>120</Width>
<Margin>
<All>-1</All>
<Bottom>0</Bottom>
<Left>400</Left>
<Right>0</Right>
<Top>11</Top>
</Margin>
</Instance>
In the above xml, I need to change the Left Margin to 420. How do I do it using XSLT?
This is almost the “identify transform”, which simply duplicates the input document.
Here’s a simple stylesheet that mostly performs the identity transform, while overriding the output for a <Left/> within a <Margin/> within an <Instance/> that has a <Name/> containing ExitButton. Note that I had to add a namespace definition to your input XML for xsi, which I assume is elsewhere in the document.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Margin/Left[ancestor::Instance/Name[text()='ExitButton']]">
<Left>420</Left>
</xsl:template>
</xsl:stylesheet>
As any XSLT tutorial would tell you: For something simple like this, start with the identity stylesheet, which copies the document essentially unchanged... then add a template which implements the exception to that.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Margin/Left">
<xsl:copy>
<xsl:text>420</xsl:text>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>