xml xslt transformation: unable to get one node inside another - java

I am new to XSLT, cant get my head around it. Need to transform the below input file to below output file, can someone help me with xslt code. thanks in advance.
inputFile:
<input>
<inputOne>
<numberOne>1</numberOne>
</inputOne>
<inputTwo>
<numberTwo>2</numberTwo>
</inputTwo>
<inputThree>
<numberThree>3</numberThree>
</inputThree>
<inputFive>
<numberFive>5</numberFive>
</inputFive>
<inputFour>
<numberFour>4</numberFour>
</inputFour>
<inputThree>
<numberThree>32</numberThree>
</inputThree>
<inputFive>
<numberFive>52</numberFive>
</inputFive>
<inputFour>
<numberFour>42</numberFour>
</inputFour>
</input>
outputFile:
<input>
<inputOne>
<numberOne>1</numberOne>
<inputTwo>
<numberTwo>2</numberTwo>
<inputThree>
<numberThree>3</numberThree>
<inputFour>
<numberFour>4</numberFour>
<inputFive>
<numberFive>5</numberFive>
</inputFive>
</inputFour>
</inputThree>
<inputThree>
<numberThree>32</numberThree>
<inputFour>
<numberFour>42</numberFour>
<inputFive>
<numberFive>52</numberFive>
</inputFive>
</inputFour>
</inputThree>
</inputTwo>
</inputOne>
</input>
I am using Transformer object to transform streamsource into streamresult object. the transform object is created using xsl file.
my xsl file is not working.
xslcode:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8"/>
<xsl:template match="/input">
<xsl:copy>
<xsl:apply-templates select="inputOne"/>
</xsl:copy>
</xsl:template>
<xsl:template match="inputOne">
<xsl:apply-templates select="inputTwo"/>
</xsl:template>
<xsl:template match="inputOne[not(inputTwo)]">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="inputTwo">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
with above xsl i am trying to get inputOne tag and inside it inputTwo tag.
but just getting the below:
<input>
<inputOne>
<numberOne>1</numberOne>
</inputOne>
</input>
appreciate any help to fix the xsl code. Thanks.

FWIW, the following stylesheet will generate, with a lot of effort, the result shown in your question. Whether the logic implemented here will suit all your possible inputs is not clear to me.
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" oversion="1.0" encoding="utf-8" indent="yes"/>
<xsl:key name="in4" match="inputFour" use="generate-id(preceding-sibling::inputThree[1])" />
<xsl:key name="in5" match="inputFive" use="generate-id(following-sibling::inputFour[1])" />
<xsl:template match="/input">
<xsl:copy>
<xsl:apply-templates select="inputOne"/>
</xsl:copy>
</xsl:template>
<xsl:template match="inputOne">
<xsl:copy>
<xsl:copy-of select="numberOne"/>
<xsl:apply-templates select="../inputTwo"/>
</xsl:copy>
</xsl:template>
<xsl:template match="inputTwo">
<xsl:copy>
<xsl:copy-of select="numberTwo"/>
<xsl:apply-templates select="../inputThree"/>
</xsl:copy>
</xsl:template>
<xsl:template match="inputThree">
<xsl:copy>
<xsl:copy-of select="numberThree"/>
<xsl:apply-templates select="key('in4', generate-id())"/>
</xsl:copy>
</xsl:template>
<xsl:template match="inputFour">
<xsl:copy>
<xsl:copy-of select="numberFour"/>
<xsl:apply-templates select="key('in5', generate-id())"/>
</xsl:copy>
</xsl:template>
<xsl:template match="inputFive">
<xsl:copy>
<xsl:copy-of select="numberFive"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

Related

when replace the xml elements with the help of xsl stylesheet using java,not getting replaced

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>

Need help on xslt logic for translating element attributes into element

My requirement is as follows
If any complex element contains only text then corresponding element attributes translate into element to parent level.
If any complex element contains children then corresponding element attributes translate into element to same element level.
This translation want to achieve using xslt logic.
Input XML
<root>
<food name="desert">butter scotch</food>
<special type="nonveg">
<name>chicken</name>
</special>
</root>
Output XML
<root>
<food>butter scotch</food>
<name>desert</name>
<special>
<type>nonveg</type>
<name>chicken</name>
</special>
</root>
Start off with the Identity Transform....
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
For the rule "If any complex element contains only text then corresponding element attributes translate into element to parent level", you could use the following template (I am ignoring comments and processing-instuctions here, and just checking the element has no child element)
<xsl:template match="*[not(*)][#*]">
<xsl:copy>
<xsl:apply-templates select="node()"/>
</xsl:copy>
<xsl:apply-templates select="#*" mode="toelement"/>
</xsl:template>
The template with mode "toelement" will turn the attribute to an element. (It will be re-used by the other rule).
<xsl:template match="#*" mode="toelement">
<xsl:element name="{local-name()}">
<xsl:value-of select="." />
</xsl:element>
</xsl:template>
For the rule "If any complex element contains children then corresponding element attributes translate into element to same element level." then you could actually match on the attribute directly:
<xsl:template match="*[*]/#*">
<xsl:apply-templates select="." mode="toelement"/>
</xsl:template>
Try this XSLT:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="*[*]/#*">
<xsl:apply-templates select="." mode="toelement"/>
</xsl:template>
<xsl:template match="*[not(*)][#*]">
<xsl:copy>
<xsl:apply-templates select="node()"/>
</xsl:copy>
<xsl:apply-templates select="#*" mode="toelement"/>
</xsl:template>
<xsl:template match="#*" mode="toelement">
<xsl:element name="{local-name()}">
<xsl:value-of select="." />
</xsl:element>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

XSLT 1.0: how to wrap XML element around other templates?

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>

Generate xpath of XML using XSLT for all Nodes

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).

Replace xmlns attribute of root node using xslt

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>

Categories

Resources