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