I have xml like below
<rnp xmsns="v1">
<ele1 line="1">
<ele2></ele2>
</ele1>
</rnp>
I want to change it to
<rnp xmsns="v2">
<ele1 line="1">
<ele2></ele2>
</ele1>
</rnp>
using xslt 1.0.
I am using below xsl.
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="v2">
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="#*|*|node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="rnp">
<rnp>
<xsl:apply-templates select="*"/>
</rnp>
</xsl:template>
</xsl:stylesheet>
But this xsl does not copy the attributes so line attribute is not generated in output.
sample output
<?xml version="1.0" encoding="UTF-8"?><rnp xmlns="v2"><ele1>1
<ele2/>
</ele1></rnp>
How to change only the text of xmlns attrbiute using xslt? Is there any other way to change xmlns using xslt? I have only option of xslt 1.0.
Thanks.
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:param name="pNS" select="'v2'"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[true()]">
<xsl:element name="{local-name()}" namespace="{$pNS}">
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document (corrected to make it in the namespace "v1":
<rnp xmlns="v1">
<ele1 line="1">
<ele2></ele2>
</ele1>
</rnp>
produces the wanted, correct result:
<rnp xmlns="v2">
<ele1 line="1">
<ele2/>
</ele1>
</rnp>
Do note:
The desired new default namespace is passed to the transformation as an external parameter -- thus the smae transformation without any modification can be used in every case when the default namespace must be modified.
This unusual looking template match: <xsl:template match="*[true()]"> makes it possible to avoid the XSLT processors "recoverable ambiguity error" messages if we had coded it just as <xsl:template match="*"> and is shorter and more elegant than specifying a priority.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="v2">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="#* | node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Output:
<rnp xmlns="v2">
<ele1 line="1">
<ele2 />
</ele1>
</rnp>
Related
how to replace the child tag name with xsl.
here the below is my structure of xml.
<Checkpax xmlns="http://xml.api.com/test">
<customerLevel>
<customerDetails>
<paxDetails>
<surname>MUKHERJEE</surname>
<type>A</type>
<gender>M</gender>
</paxDetails>
<otherPaxDetails>
<givenName>JOY</givenName>
<title>MR</title>
<age>11</age>
</otherPaxDetails>
<otherPaxDetails>
<title>MR</title>
</otherPaxDetails>
</customerDetails>
<staffDetails>
<staffInfo/>
<staffCategoryInfo>
<attributeDetails>
<attributeType>NA</attributeType>
</attributeDetails>
</staffCategoryInfo>
</staffDetails>
<productLevel>
<legLevel>
<legLevelIndicator>
<statusDetails>
<indicator>abc</indicator>
<action>1</action>
</statusDetails>
</legLevelIndicator>
</legLevel>
</productLevel>
<CustomerLevel>
<legLevel>
<legLevelIndicator>
<statusDetails>
<indicator>cde</indicator>
<action>1</action>
</statusDetails>
</legLevelIndicator>
</legLevel>
</CustomerLevel>
</customerLevel>
</Checkpax>
The below is my XSL file
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="customerLevel/productLevel/legLevel/legLevelIndicator/statusDetails">
<statusInformation>
<xsl:apply-templates select="#*|node()" />
</statusInformation>
</xsl:template>
</xsl:stylesheet>
here the statusDetails name should be changed as staffInformation inside the ProductLevel/LeglevelIndicator . Kindly give me the suggestion for doing this.
The below is expected result
<Checkpax xmlns="http://xml.api.com/test">
<customerLevel>
<customerDetails>
<paxDetails>
<surname>MUKHERJEE</surname>
<type>A</type>
<gender>M</gender>
</paxDetails>
<otherPaxDetails>
<givenName>JOY</givenName>
<title>MR</title>
<age>11</age>
</otherPaxDetails>
<otherPaxDetails>
<title>MR</title>
</otherPaxDetails>
</customerDetails>
<staffDetails>
<staffInfo/>
<staffCategoryInfo>
<attributeDetails>
<attributeType>NA</attributeType>
</attributeDetails>
</staffCategoryInfo>
</staffDetails>
<productLevel>
<legLevel>
<legLevelIndicator>
<statusInformation>
<indicator>abc</indicator>
<action>1</action>
</statusInformation>
</legLevelIndicator>
</legLevel>
</productLevel>
<CustomerLevel>
<legLevel>
<legLevelIndicator>
<statusDetails>
<indicator>cde</indicator>
<action>1</action>
</statusDetails>
</legLevelIndicator>
</legLevel>
</CustomerLevel>
</customerLevel>
</Checkpax>
the statusDetails name should be changed as staffInformation inside
the ProductLevel/LeglevelIndicator
Try it this way:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="http://xml.api.com/test"
exclude-result-prefixes="ns0">
<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="ns0:productLevel/ns0:legLevel/ns0:legLevelIndicator/ns0:statusDetails">
<staffInformation xmlns="http://xml.api.com/test">
<xsl:apply-templates/>
</staffInformation>
</xsl:template>
</xsl:stylesheet>
I am using xsltproc to process XSLT 1.0 transform on OS X Yosemite; input is HTML, and output is XML.
The idea is that the templates below matching h1[#class='page-header'] and div[#class='mixins'] actually work, but the problem is wrapping them in a custom parent XML element (here called dye).
I realize my template matching * is broken; it's there simply to illustrate the kind of structure I would like to output.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" method="xml"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|style|script"/>
<xsl:template match="*">
<xsl:element name="dye">
<xsl:apply-templates select="h1[#class='page-header']"/>
<xsl:apply-templates select="div[#class='mixins']"/>
</xsl:element>
</xsl:template>
<xsl:template match="h1[#class='page-header']">
<xsl:element name="color">
<xsl:value-of select="text()"/>
</xsl:element>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="div[#class='mixins']">
<xsl:element name="tone">
<xsl:value-of select="p/a[#class='tone']/#href"/>
</xsl:element>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
Thanks for your interest!
I believe this should work:
<xsl:template match="*">
<dye>
<xsl:apply-templates select="h1[#class='page-header']"/>
<xsl:apply-templates select="div[#class='mixins']"/>
</dye>
</xsl:template>
I was trying to find a way to convert the XML tags to their respective unique address like xPath. Nd I found an XSLT, where XML is processed and the unique address is created only for the nodes which doesnt have child elements and with attributes. [link]:Generate/get xpath from XML node java
XSLT :
<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="vApos">'</xsl:variable>
<xsl:template match="*[#* or not(*)] ">
<xsl:if test="not(*)">
<xsl:apply-templates select="ancestor-or-self::*" mode="path"/>
<xsl:value-of select="concat('=',$vApos,.,$vApos)"/>
<xsl:text>
</xsl:text>
</xsl:if>
<xsl:apply-templates select="#*|*"/>
</xsl:template>
<xsl:template match="*" mode="path">
<xsl:value-of select="concat('/',name())"/>
<xsl:variable name="vnumPrecSiblings" select=
"count(preceding-sibling::*[name()=name(current())])"/>
<xsl:if test="$vnumPrecSiblings">
<xsl:value-of select="concat('[', $vnumPrecSiblings +1, ']')"/>
</xsl:if>
</xsl:template>
<xsl:template match="#*">
<xsl:apply-templates select="../ancestor-or-self::*" mode="path"/>
<xsl:value-of select="concat('[#',name(), '=',$vApos,.,$vApos,']')"/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
when passed to this
<?xml version="1.0" encoding="UTF-8"?>
<root>
<main>
<tag1>001</tag1>
<tag2>002</tag2>
<tag3>
<tag4>004</tag4>
</tag3>
<tag2>002</tag2>
<tag5>005</tag5>
</main>
</root>
produces
/root/main/tag1='001' /root/main/tag2='002' /root/main/tag3/tag4='004' /root/main/tag2[2]='002' /root/main/tag5='005'
So I need the xslt to generate in the following way
/root
/root/main
/root/main/tag1
/root/main/tag2
/root/main/tag3
/root/main/tag3/tag4
/root/main/tag2[2]
/root/main/tag5
Also I dont need values. So please help me with this
Your result could be produced rather simply by:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="*">
<xsl:for-each select="ancestor-or-self::*">
<xsl:value-of select="name()" />
<xsl:variable name="i" select="count(preceding-sibling::*[name()=name(current())])"/>
<xsl:if test="$i">
<xsl:value-of select="concat('[', $i + 1, ']')"/>
</xsl:if>
<xsl:if test="position()!=last()">
<xsl:text>/</xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:text>
</xsl:text>
<xsl:apply-templates select="*"/>
</xsl:template>
</xsl:stylesheet>
Note that this does not process attributes (or any other type of nodes other than elements).
A question about Martin's answer:
Martin Honnen's answer works great, but not with the root element. Let's say I have "cars" as a root element:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="foo">
<cars>
<car1 />
<car2 />
</cars>
</xsl:template>
</xsl:stylesheet>
And I want to obtain:
<xsl:template match="foo">
<cars>
<car1 />
<car2 />
<TANK />
</cars>
</xsl:template>
For this, I'd use:
<xsl:template match="cars" >
<xsl:copy>
<xsl:apply-templates/>
<TANK />
</xsl:copy>
</xsl:template>
Which outputs the exact input, without changing anything. I can try:
<xsl:template match="/" >
<xsl:copy>
<xsl:apply-templates/>
<TANK />
</xsl:copy>
</xsl:template>
But it will place the TANK node outside the stylesheet, like this:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="order">
<cars>
<car1/>
<car2/>
</cars>
</xsl:template>
</xsl:stylesheet><TANK/>
How to get the TANK element inside cars?
Original question:
I have a XSL that I use to transform an XML:
XML_format1 -> XSL1 -> XML_format2
I need to transform this first XSL file (using a second XSL) to obtain a third XSL file, which will output an XML with a third format. In short:
XSL1 -> XSL2 -> XSL3
XML_format1 -> XSL3 -> XML_format3
Using the following stylesheet, I am able to copy the first XSL's contents and also skip certain nodes:
<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="//skipThisNode"/>
</xsl:stylesheet>
My problem: in addition to this, I also need to change some nodes' structure (add something), from this:
<car>
<color>green</color>
<fuel>petrol</fuel>
</car>
To this:
<car>
<color>green</color>
<fuel>petrol</fuel>
<topSpeed>99</topSpeed>
</car>
LE: I could create a template to match the specific nodes that I need to add children to, like so:
<xsl:template match="car">
<color>
<!-- existing value-of -->
</color>
<fuel>
<!-- existing value-of -->
</fuel>
<topSpeed>
<!-- * new value-of * -->
</topSpeed>
</xsl:template>
But this seems like going over the top. Is there a simpler way of achieving what I want?
I would rather use
<xsl:param name="newSpeed" select="99"/>
<xsl:template match="car">
<xsl:copy>
<xsl:apply-templates/>
<topSpeed>
<xsl:value-of select="$newSpeed"/>
</topSpeed>
</xsl:copy>
</xsl:template>
that keeps the processing chain up, allowing you to add templates to transform or delete child and descendants of car elements when needed.
[edit]
I am not sure I understand your latest requirement as the input seems to be a complete stylesheet but then as the wanted output you have only shown a single template. So assuming you have the input as
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="order">
<cars>
<car1 />
<car2 />
</cars>
</xsl:template>
</xsl:stylesheet>
and you want to both transform the xsl:template's match attribute as well as the literal result elements in the template body I would use
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="xsl:template[#match = 'order']/#match">
<xsl:attribute name="{name()}">
<xsl:text>foo</xsl:text>
</xsl:attribute>
</xsl:template>
<xsl:template match="xsl:template[#match = 'order']/cars">
<xsl:copy>
<xsl:apply-templates/>
<TANK/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
that way I get (tested with Saxon 6.5.5) the result
<?xml version="1.0" encoding="utf-8"?><xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="foo">
<cars>
<car1/>
<car2/>
<TANK/></cars>
</xsl:template>
</xsl:stylesheet>
which is hopefully what you want (lacking proper indentation perhaps).
I'm working on an XSLT that is giving me a little headache, and was looking for some tips. I'm working on converting an XML where some of the tags have namespaces prefixes, and others do not. I am working to convert all of the tags to one common namespace prefix.
Example of XML:
<yes:Books>
<no:Book>
<Title>Yes</Title>
<maybe:Version>1</maybe:Version>
</no:Book>
</yes:Books>
What I'm trying to get:
<yes:Books>
<yes:Book>
<yes:Title>Yes</yes:Title>
<yes:Version>1</yes:Version>
</yes:Book>
</yes:Books>
The XML input is the aggregate of several webservices, that are returning various namespaces. I have no issue aggregating it together appropriately, it's creating one common prefix namespace that I am having an issue with.
Worst case, I could regex them away, but I'm sure that isn't recomended.
Thanks.
This transformation allows the wanted final prefix and its namespace to be specified as external/global parameters. It shows how to process in the same way attribute names:
<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:param name="pPrefix" select="'yes'"/>
<xsl:param name="pNamespace" select="'yes'"/>
<xsl:template match="*">
<xsl:element name="{$pPrefix}:{local-name()}" namespace="{$pNamespace}">
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
<xsl:template match="#*">
<xsl:attribute name="{$pPrefix}:{local-name()}" namespace="{$pNamespace}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
when applied on the following document (the provided one with one added attribute to make the problem more challenging):
<yes:Books xmlns:yes="yes">
<no:Book xmlns:no="no">
<Title no:Major="true">Yes</Title>
<maybe:Version xmlns:maybe="maybe">1</maybe:Version>
</no:Book>
</yes:Books>
produces the wanted, correct result:
<yes:Books xmlns:yes="yes">
<yes:Book>
<yes:Title yes:Major="true">Yes</yes:Title>
<yes:Version>1</yes:Version>
</yes:Book>
</yes:Books>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:custom="c">
<xsl:template match="/">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:element name="custom:{local-name()}" namespace-uri="c">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>