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>
Related
Thank you for taking the time to look at my question
I have a source xml that looks like so
<root>
<a>asdf</a>
<b>asdfdsaf</b>
<c>adfasd</c>
<d>asddf</d>
<e></e>
<others>
<foo>sdfd</foo>
<bar>hghg</bar>
</others>
</root>
I need to wrap certain elements Eg:a,b,c into a new parent and remove empty elements.
so output like so
<root>
<newparent>
<a>asdf</a>
<b>asdfdsaf</b>
<c>adfasd</c>
</newparent>
<d>asddf</d>
<others>
<foo>sdfd</foo>
<bar>hghg</bar>
</others>
</root>
I managed to remove the empty elements using this XSL -
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[not(#*) and not(*) and (not(text()) or .=-1)]"/>
<xsl:template match="name">
</xsl:template>
</xsl:stylesheet>
Getting stuck at adding the newparent node. Any pointers/help is much appreciated.
Try it this way:
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="/root">
<xsl:copy>
<newparent>
<xsl:apply-templates select="a|b|c"/>
</newparent>
<xsl:apply-templates select="*[not(self::a or self::b or self::c)]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[not(#* or node())]"/>
</xsl:stylesheet>
<xsl:template match="root">
<xsl:copy>
<newparent>
<xsl:copy-of select="a|b|c"/>
</newparent>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[.= '' or name() ='a' or name()='b' or name()='c']"/>
check it if it is fullfill your requirement.
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>
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>
I have a style-sheet that I am using to remove certain elements based on the value of an other element. However, it is not working ...
Sample Input XML
<Model>
<Year>1999</Year>
<Operation>ABC</Operation>
<Text>Testing</Text>
<Status>Ok</Status>
</Model>
If Operation value is 'ABC' then remove Text and Status nodes from XML.
And gives the following output.
<Model>
<Year>1999</Year>
<Operation>ABC</Operation>
</Model>
Here is my style sheet that I am using but it is removing Text and Status nodes from all XMLs even when operation is not 'ABC'.
<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:variable name="ID" select="//Operation"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Text | Status">
<xsl:if test ="$ID ='ABC'">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Thanks in Advance
How would I do the same when namespace is present like
<ns0:next type="Sale" xmlns:ns0="http://Test.Schemas.Inside_Sales">
Here is a complete XSLT transformation -- short and simple (no variables, no xsl:if, xsl:choose, xsl:when, xsl:otherwise):
<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()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match=
"*[Operation='ABC']/Text | *[Operation='ABC']/Status"/>
</xsl:stylesheet>
When this transformation is applied on the provided XML document:
<Model>
<Year>1999</Year>
<Operation>ABC</Operation>
<Text>Testing</Text>
<Status>Ok</Status>
</Model>
the wanted, correct result is produced:
<Model>
<Year>1999</Year>
<Operation>ABC</Operation>
</Model>
Change your xsl:if as follows:
<xsl:if test="../Operation!='ABC'">
and you can get rid of xsl:variable.
A better pattern in XSLT than using <xsl:if> is to add new templates with match conditions:
<xsl:template match="(Text | Status)[../Operation != 'ABC']"/>
I found this works:
<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()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/Model">
<xsl:choose>
<xsl:when test="Operation[text()!='ABC']">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:apply-templates select="Year"/>
<xsl:apply-templates select="Operation"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>