How do I replace the namespace of child elements in an xml?
For example I have this source file:
<ns:Parent xmlns:ns="http://test.com">
<ns:Name>John</ns:Name>
<ns:Country>Japan</ns:Country>
<ns:Contact>9999999</ns:Contact>
</ns:Parent>
My output should be like this:
<ns:Parent xmlns:ns="http://test.com">
<ns1:Name xmlns:ns1="http://development.com">John</ns1:Name>
<ns:Country>Japan</ns:Country>
<ns:Contact>9999999</ns:Contact>
</ns:Parent>
So basically All the other fields aside from Name were not affected.
First start with the identity template, to handle copying all the nodes you don't want to change
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
Then, just add a template to match ns:Name, where you create a new node in your required namespace instead (where ns1 is defined on the xsl:stylesheet element)
<xsl:template match="ns:Name">
<ns1:Name>
<xsl:apply-templates select="#*|node()"/>
</ns1:Name>
</xsl:template>
Try this XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:ns="http://test.com"
xmlns:ns1="http://development.com">
<xsl:output method="xml" indent="yes" />
<xsl:template match="ns:Name">
<ns1:Name>
<xsl:apply-templates select="#*|node()"/>
</ns1:Name>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Related
I am trying to filter out elements, and rename element value, but I can't get it to work:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output encoding="UTF-8" indent="yes" method="xml"/>
<xsl:template match="xml">
<xsl:copy>
<xsl:for-each select="product[matches(code, 'C17.*[^V]$')]">
<xsl:copy>
<xsl:copy-of select="#*|node()"/>
</xsl:copy>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template match="title">
<xsl:copy>
<xsl:value-of select="replace(.,'Apple','Carrot')"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Example input data:
<?xml version="1.0" encoding="UTF-8"?>
<xml>
<product>
<code>C17020</code>
<title>Apple</title>
</product>
<product>
<code>C1723V</code>
<title>Samsung</title>
</product>
</xml>
I want to leave <product>'s starting with C17, but not ending to V. I use C17.*[^V]$ regex for this. This part is working.
The problem is with renaming title function. If I add this step to a new XSLT with code:
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
at the begin, then it works.
What I am doing wrong here?
The problem is you are doing <xsl:copy-of select="#*|node()"/> in your template matching xml. This will copy the attributes and child nodes, buy will not apply any templates. So your template matching title is just not used.
You need to use xsl:apply-templates here, but also include the identity template (the template you mention using in your new XSLT code) which ensures code gets copied too
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output encoding="UTF-8" indent="yes" method="xml"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="xml">
<xsl:copy>
<xsl:for-each select="product[matches(code, 'C17.*[^V]$')]">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template match="title">
<xsl:copy>
<xsl:value-of select="replace(.,'Apple','Carrot')"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Note you can actually simplify your XSLT. Rather than being explicit in what you want to copy, by using the identity template you can instead have templates to remove what you don't want to copy....
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output encoding="UTF-8" indent="yes" method="xml"/>
<xsl:strip-space elements="*" />
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="product[not(matches(code, 'C17.*[^V]$'))]" />
<xsl:template match="title">
<xsl:copy>
<xsl:value-of select="replace(.,'Apple','Carrot')"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Another thing to note is that matches and replace is for XSLT 2.0 only.
Assume the following example XML :
<tag>
<subtag1>value1</subtag1>
<subtag2>value2</subtag2>
<subtag3>value3</subtag3>
<subtag4>value4</subtag4>
<subtag5>value5</subtg5>
</tag>
and I would like to get all the tag section, but make some changes, like:
<tag>
<subtag1>value1</subtag1>
<subtag2>value2</subtag2>
<subtag3>value3</subtag3>
<new-subtag4>value4</new-subtag4>
<new-subtag5 type="new">value5</new-subtg5>
</tag>
I tried the following script, but the result is not correct.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="no" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="parent::subtag4">
<xsl:element name="new-subtag4">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="parent::subtag5">
<xsl:element name="new-subtag5" type="n">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
An XSLT that outputs the desired result is the following. It incorporates only two minor modifications concerning the attribute and the removal of the parent:: prefixes.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="no" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="subtag4">
<xsl:element name="new-subtag4">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="subtag5">
<xsl:element name="new-subtag5">
<xsl:attribute name="type">new</xsl:attribute>
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
parent::subtag4 is not a valid match pattern. And you cannot add an attribute to xsl:element like that. Nor do you need to use xsl:element when the element's name is known.
Try instead:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="subtag4">
<new-subtag4>
<xsl:apply-templates/>
</new-subtag4>
</xsl:template>
<xsl:template match="subtag5">
<new-subtag5 type="new">
<xsl:apply-templates/>
</new-subtag5>
</xsl:template>
</xsl:stylesheet>
Say I have an XML like this. I want to introduce a <row3> element.
<create xmlns="urn:partner.com"
<objects xmlns:p0="urn:s.partner.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="p0:IED">
<row1 xmlns="urn:s.partner.com">BookingDataFromCastIron</row1>
<row2 xmlns="urn:s.partner.com">Csv</row2>
</objects>
</create>"
I am using the following XSLT. But it is giving the same XML as output. Am I missing anything?
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="objects">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
<xsl:element name="type">IED</xsl:element>
</xsl:copy>
</xsl:template>
It is all to do with the namespaces, basically your template match above only hits object if there is no namespace in the source XML. However you do have a namespace set xmlns="urn:partner.com" so you need to use the following to remove the binding to the namespace: <xsl:template match="*:objects">.
I think you are looking for this, but it defiantly pushes you in the right direction:
<xsl:stylesheet version="2.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()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*:objects">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
<xsl:element name="row3" xmlns="urn:s.partner.com">IED</xsl:element>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Output:
<create xmlns="urn:partner.com">
<objects xmlns:p0="urn:s.partner.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<row1 xmlns="urn:s.partner.com">BookingDataFromCastIron</row1>
<row2 xmlns="urn:s.partner.com">Csv</row2>
<row3 xmlns="urn:s.partner.com">IED</row3>
</objects>
</create>
Below Is My Input XML.
<ServiceIncident xmlns="http://b2b.ibm.com/schema/IS_B2B_CDM/R2_2">
<ProviderID>INC0011731</ProviderID>
<ProviderPriority>4</ProviderPriority>
<WorkflowStatus>NEW</WorkflowStatus>
<ServiceProvider1>
<Person Role="AffectedUser">
<ContactID>ITELLA_BRIDGE_USER</ContactID>
<FullName>Chad Whaley</FullName>
</Person>
</ServiceProvider1>
Below is my XSL
<xsl:template match="r2:Person/#Role">
<xsl:attribute name="Role">Owner</xsl:attribute>
</xsl:template>
<xsl:template match="r2:Person/#Role">
<xsl:attribute name="Role">ReportedBy</xsl:attribute>
</xsl:template>
My issue is i want to get these 2 fields in output replacing the old one in input.Iam able to get one value in output but iam not getting other value.
I put on a space as a separator between attributes:
<xsl:stylesheet version='1.0' xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:r2="http://b2b.ibm.com/schema/IS_B2B_CDM/R2_2" exclude-result-prefixes="r2">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="r2:Person">
<xsl:copy>
<xsl:attribute name="Role">Owner ReportedBy</xsl:attribute>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
XML
<root>
<Algemeen>
<foto>
<foe>
<fee>
<img src="www.blah.com/sample.jif"></img>
</fee>
</foe>
</foto>
</Algemeen>
</root>
XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<result>
<xsl:apply-templates select="/root/Algemeen/foto/foe/fee/img"/>
</result>
</xsl:template>
<!--specific template match for this img -->
<xsl:template match="/root/Algemeen/foto/foe/fee/img">
<xsl:copy>
<xsl:attribute name="width">100</xsl:attribute>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<!--Identity template copies content forward -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
I'm adding an attribute to "img" tag via template, how can i get the whole "foto" node? is this "#*|node()" refers to 2nd level parent node "foe"?
viewed links:
xslt how to add attributes to copy-of
Can E4X Get Attribute of a Parent Node Based on Attribute of a Child
At Any Level?
is this "#*|node()" refers to 2nd level parent node "foe"?
Nope! This refers to child nodes and attributes ..
How to copy <img> adding an attribute, along with its grand-parent <foto>??
In your code you are matching the root node by saying <xsl:template match="/"> and you are renaming it as <result>. Under that you are saying <xsl:apply-templates select="/root/Algemeen/foto/foe/fee/img"/> .. So that will skip the hierarchy and do what <xsl:template match="/root/Algemeen/foto/foe/fee/img"> says ..
Your <xsl:template match="/root/Algemeen/foto/foe/fee/img"> template looks perfect!! All you need is below correction!
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<result>
<xsl:apply-templates select="/root/Algemeen/foto"/>
</result>
</xsl:template>
<xsl:template match="foto">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<!--specific template match for this img -->
<xsl:template match="/root/Algemeen/foto/foe/fee/img">
<xsl:copy>
<xsl:attribute name="width">100</xsl:attribute>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<!--Identity template copies content forward -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
If you want to access the parent or ancestor try this:
<xsl:for-each select="ancestor::foto">