How to remove the rootnodes using XSLT? - xslt

Input file:
<?xml version="1.0" encoding="UTF-8"?>
<ns0:root xmlns:ns0="http://xyz.com/separate">
<ns0:root1>
<ns3:Detail xmlns:ns3="http://POProject/Details">
<DetailLines>
<ItemID>
<ItemDescription/>
</DetailLines>
</ns3:Detail>
</ns0:root1>
</ns0:root>
Output file:
<?xml version="1.0" encoding="UTF-8"?>
<ns0:Detail xmlns:ns0="http://POProject/Details">
<DetailLines>
<ItemID>
<ItemDescription/>
</DetailLines>
</ns0:Detail>
Question: I have to remove the root1 and root nodes and need to do small
changes in Detail node. How to write a xslt code to achieve this?

This...
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="http://xyz.com/separate"
xmlns:ns3="http://POProject/Details">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="*/*/ns3:Detail" />
</xsl:template>
<xsl:template match="ns3:Detail">
<xsl:apply-templates select="." mode="copy-sans-namespace" />
</xsl:template>
<xsl:template match="*" mode="copy-sans-namespace">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:copy-of select="#*"/>
<xsl:apply-templates mode="copy-sans-namespace" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
...will yield this...
<?xml version="1.0" encoding="utf-8"?>
<ns3:Detail xmlns:ns3="http://POProject/Details">
<DetailLines>
<ItemID />
<ItemDescription />
</DetailLines>
</ns3:Detail>
I'm not sure it is possible to control the prefix. The XDM data model does not consider it to be significant information.
UDPATE
To get the prefix rename, I thought you would have to go to an XML 1.1 supporting XSLT processor (allowing prefix undefine), but I found a way to do it with XML 1.0 . Try this ...
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="http://xyz.com/separate">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/" xmlns:ns3="http://POProject/Details">
<xsl:apply-templates select="*/*/ns3:Detail" />
</xsl:template>
<xsl:template match="ns0:Detail" xmlns:ns0="http://POProject/Details">
<ns0:Detail xmlns:ns0="http://POProject/Details">
<xsl:apply-templates select="*" mode="copy-sans-namespace" />
</ns0:Detail>
</xsl:template>
<xsl:template match="*" mode="copy-sans-namespace">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:copy-of select="#*"/>
<xsl:apply-templates mode="copy-sans-namespace" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>

Related

How to remove the ns0 prefix from the xml output file with out removing the namespace declaration

i want to remove "nso" prefix from the output xml file with out removing the namespace declaration but in the declaration part also i need to remove "ns0:" & ":ns0".
`
<?xml version="1.0" encoding="UTF-8"?>
<ns0:Document xmlns:ns0="urn:iso:std:iso:20022:tech:xsd:abcd">**<!-- I do not want to remove this declaration line from the output only needs to remove "ns0:" & ":ns0" from the declaration-->**
<ns0:CstmrCdtTrfInitn>
<ns0:GrpHdr>
<ns0:MsgId>abcd</ns0:MsgId>
<ns0:CreDtTm>2023-01-24T14:47:17Z</ns0:CreDtTm>
<ns0:NbOfTxs>2 </ns0:NbOfTxs>
<ns0:CtrlSum>580000.00</ns0:CtrlSum>
<ns0:InitgPty>
<ns0:Nm>abcd</ns0:Nm>
<ns0:CtryOfRes>IN</ns0:CtryOfRes>
</ns0:InitgPty>
</ns0:GrpHdr>
</ns0:CstmrCdtTrfInitn>
</ns0:Document>`
`
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns ="urn:iso:std:iso:20022:tech:xsd:abcd">
<CstmrCdtTrfInitn>
<GrpHdr>
<MsgId>abcd</MsgId>
<CreDtTm>2023-01-24T14:47:17Z</CreDtTm>
<NbOfTxs>2 </NbOfTxs>
<CtrlSum>580000.00</CtrlSum>
<InitgPty>
<Nm>abcd</Nm>
<:CtryOfRes>IN</CtryOfRes>
</InitgPty>
</GrpHdr>
</CstmrCdtTrfInitn>
</Document>`
Please help me on this requirment.
Thanks.
i used below code but it is removing all the nso prefix's along with namespace declarations but i want to remove only nso prefix's for individual xml tags from the element "ns0:CstmrCdtTrfInitn" before this element i want to remove "ns0:" & ":ns0" and keep the declaration with out "ns0".
`
<?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="no" />
<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:stylesheet>
Change
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="#*|node()" />
</xsl:element>
</xsl:template>
to
<xsl:template match="/*//*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="#*|node()" />
</xsl:element>
</xsl:template>
and add a template
<xsl:template match="/*">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
--- edited in view of changed requirement ---
To remove the ns0 prefix from all elements in the input XML, while keeping them in the original namespace, do:
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="*"/>
<xsl:template match="*">
<xsl:element name="{local-name()}" namespace="{namespace-uri()}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>

xslt for converting one element to attribute among multiple

I have an xml with subelements and need to change one of the subelement to attribute using XSLT 1.0
<TransportationRequest>
<actionCode>01</actionCode>
<ContractConditionCode>DC</ContractConditionCode>
<ShippingTypeCode>17</ShippingTypeCode>
<MovementTypeCode>3</MovementTypeCode>
<DangerousGoodsIndicator>false</DangerousGoodsIndicator>
<DefaultCurrencyCode>SAR</DefaultCurrencyCode>
The Expected xml is as below using the XSLT code:
<TransportationRequest actionCode="01">
<ContractConditionCode>DC</ContractConditionCode>
<ShippingTypeCode>17</ShippingTypeCode>
<MovementTypeCode>3</MovementTypeCode>
<DangerousGoodsIndicator>false</DangerousGoodsIndicator>
<DefaultCurrencyCode>SAR</DefaultCurrencyCode>
First, close the root tag on your xml:
<TransportationRequest>
<actionCode>01</actionCode>
<ContractConditionCode>DC</ContractConditionCode>
<ShippingTypeCode>17</ShippingTypeCode>
<MovementTypeCode>3</MovementTypeCode>
<DangerousGoodsIndicator>false</DangerousGoodsIndicator>
<DefaultCurrencyCode>SAR</DefaultCurrencyCode>
</TransportationRequest>
then this xsl will do what you asked for:
<?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" encoding="UTF-8" />
<xsl:template match="/">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="#*|node()">
<!-- Copy every node as is -->
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="TransportationRequest">
<!-- transform the TransportationRequest node in a special way -->
<xsl:element name="TransportationRequest">
<xsl:attribute name="actionCode"><xsl:value-of select="actionCode" /></xsl:attribute>
<!-- don't transform the actionCode node (is in the attribute) -->
<xsl:apply-templates select="#*|node()[name()!='actionCode']"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
You could to it like this :
<?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="TransportationRequest">
<xsl:copy>
<xsl:attribute name="actionCode">
<xsl:value-of select="actionCode"/>
</xsl:attribute>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="actionCode"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
See it working here : https://xsltfiddle.liberty-development.net/naZYrpW/1

XSLT Transformation that add namespace prefix doesn't copy attributes

I have a requirement to add a namespace prefix to all my xml elements.
I have a working xslt for this but unfortunately it doesn't copy the attributes. What do I need to change to also copy these attributes.
This my code:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:ns0="http://ns.hr-xml.org/2007-04-15" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:template match="*">
<xsl:element name="ns0:{local-name()}">
<xsl:apply-templates select="*|node()" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
The input XML is this:
<HumanResource schemaLocation="http://ns.hr-xml.org/2007-04-15 ../HumanResource.xsd">
<HumanResourceId idOwner="StaffingCompany">
<IdValue>123COMP</IdValue>
</HumanResourceId>
<HumanResourceId idOwner="StaffingCustomer">
<IdValue>456CUST</IdValue>
<!--double hre-id, due fms wnr-code swap-->
</HumanResourceId>
<HumanResourceStatus status="x:Assigned"/>
<ReferenceInformation>
<StaffingSupplierId idOwner="StaffingCustomer">
<IdValue>105964</IdValue>
</StaffingSupplierId>
<StaffingCustomerId idOwner="StaffingCompany">
<IdValue>MIN0000612</IdValue>
</StaffingCustomerId>
<StaffingCustomerId idOwner="StaffingCustomer">
<IdValue>ELI</IdValue>
</StaffingCustomerId>
<StaffingSupplierOrgUnitId idOwner="StaffingCompany">
<IdValue>2606379</IdValue>
</StaffingSupplierOrgUnitId>
<StaffingCustomerOrgUnitId idOwner="StaffingCustomer">
<IdValue>ELI</IdValue>
</StaffingCustomerOrgUnitId>
</ReferenceInformation>
<ResourceInformation>
<PersonName>
<FormattedName>J</FormattedName>
<LegalName>C</LegalName>
<GivenName>J</GivenName>
<PreferredGivenName>J</PreferredGivenName>
<MiddleName>C.J.</MiddleName>
<FamilyName primary="true"></FamilyName>
</PersonName>
<EntityContactInfo>
<EntityName></EntityName>
<PersonName>
<FormattedName>Liesbeth Kramer</FormattedName>
</PersonName>
<ContactMethod>
<Telephone>
<FormattedNumber>070-3102150</FormattedNumber>
</Telephone>
</ContactMethod>
</EntityContactInfo>
<PostalAddress>
<CountryCode>NL</CountryCode>
<PostalCode></PostalCode>
<Municipality></Municipality>
<DeliveryAddress>
<AddressLine></AddressLine>
<StreetName></StreetName>
<BuildingNumber></BuildingNumber>
</DeliveryAddress>
</PostalAddress>
</ResourceInformation>
<Profile/>
<Preferences/>
<UserArea>
<ns2:HumanResourceAdditionalNL xmlns:ns2="http://ns.setu.nl/2008-01">
<ns2:BirthDate>1961-07-13</ns2:BirthDate>
<ns2:Sex>female</ns2:Sex>
</ns2:HumanResourceAdditionalNL>
</UserArea>
</HumanResource>
My result with my code looks like this:
<?xml version='1.0' ?>
<ns0:HumanResource xmlns:ns0="http://ns.hr-xml.org/2007-04-15">
<ns0:HumanResourceId>
<ns0:IdValue>123COMP</ns0:IdValue>
</ns0:HumanResourceId>
<ns0:HumanResourceId>
<ns0:IdValue>456CUST</ns0:IdValue>
</ns0:HumanResourceId>
<ns0:HumanResourceStatus/>
<ns0:ReferenceInformation>
As you can see, the ns0: is added ok but I lost the attributes.
You have lost the attributes because you have no code to select them. You currently do <xsl:apply-templates select="*|node()" />, but * select elements, and node() selects elements, text nodes, comments and processing instructions. You need to change it to this...
<xsl:apply-templates select="#*|node()" />
You would then need a separate template to match attributes and copy them.
<xsl:template match="#*">
<xsl:copy />
</xsl:template>
Try this XSLT
<xsl:stylesheet version="1.0" xmlns:ns0="http://ns.hr-xml.org/2007-04-15" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:template match="*">
<xsl:element name="ns0:{local-name()}">
<xsl:apply-templates select="#*|node()" />
</xsl:element>
</xsl:template>
<xsl:template match="#*">
<xsl:copy />
</xsl:template>
</xsl:stylesheet>
Alternatively, you could use xsl:copy-of to copy the attributes. Try this XSLT too
<xsl:stylesheet version="1.0" xmlns:ns0="http://ns.hr-xml.org/2007-04-15" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:template match="*">
<xsl:element name="ns0:{local-name()}">
<xsl:copy-of select="#*" />
<xsl:apply-templates />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Note that <xsl:apply-templates /> is short-hand for <xsl:apply-templates select="node()" />

Copying all XML elements and updating one of them in XSL

I have a requirement in my project some thing like this,
I have to copy all the elements from an xml and for few elements I have to update if present else I have to add it.
For example in the below xml I have an element Extrensic name "taxIncluded"> , in translated xml I want the value of it be updated.If it is missing I have to include it.
input xml 1
<?xml version="1.0" encoding="UTF-8"?>
<InvoiceHeader>
<Item1>
Item description
</Item1>
<Extrensic name="taxIncluded">
<percentage>
10%
</percentage>
</Extrensic>
</InvoiceHeader>
output
<?xml version="1.0" encoding="UTF-8"?>
<InvoiceHeader>
<Item1>
Item description
</Item1>
<Extrensic name="taxIncluded">
<percentage>
20%
</percentage>
</Extrensic>
</InvoiceHeader>
input xml 2
<?xml version="1.0" encoding="UTF-8"?>
<InvoiceHeader>
<Item1>
Item description
</Item1>
</InvoiceHeader>
output
<?xml version="1.0" encoding="UTF-8"?>
<InvoiceHeader>
<Item1>
Item description
</Item1>
<Extrensic name="taxIncluded">
<percentage>
20%
</percentage>
</Extrensic>
</InvoiceHeader>
I tried creating xsl but it is not working as expected, I thought of including it here but it is a very big xsl, in the above xml example I added only a part of it.
Could some one please help me how to do it?
Here are two ways to do it with XSLT 2.0 ...
Method 1:
<xsl:transform
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:param name="taxIncluded" select="20" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="InvoiceHeader[not( Extrensic[#name='taxIncluded'])]">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
<Extrensic name="taxIncluded">
<percentage>
<xsl:value-of select="$taxIncluded" />%
</percentage>
</Extrensic>
</xsl:copy>
</xsl:template>
<xsl:template match="Extrensic[#name='taxIncluded']/percentage">
<xsl:copy>
<xsl:value-of select="$taxIncluded" />%
</xsl:copy>
</xsl:template>
</xsl:transform>
Method 2:
<xsl:transform
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:param name="taxIncluded" select="20" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="InvoiceHeader">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
<xsl:variable name="Ex" as="element(Extrensic)?">
<xsl:if test="not( Extrensic[#name='taxIncluded'])">
<Extrensic name="taxIncluded" />
</xsl:if>
</xsl:variable>
<xsl:apply-templates select="$Ex" />
</xsl:copy>
</xsl:template>
<xsl:template match="Extrensic[#name='taxIncluded']">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<percentage>
<xsl:value-of select="$taxIncluded" />%
</percentage>
</xsl:copy>
</xsl:template>
</xsl:transform>

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>