I would like to print path of element and attributes if any along with values using XSLT. e.g
XML :
<root>
<node attr='abc' module='try'>
<subnode>Roshan</subnode>
<subnode>Chetan</subnode>
<subnode>Jennifer</subnode>
</node>
</root>
Output :
/root##
/root/node##
/root/node/#attr##abc
/root/node/#module##try
/root/node/subnode[1]##Roshan
/root/node/subnode[2]##Chetan
/root/node/subnode[3]##Jennifer
I am trying with below snippet, but could only print path of element and it's value
<xsl:template match="*">
<xsl:for-each select="ancestor-or-self::*">
<xsl:value-of select="concat('/',local-name())" />
<xsl:if
test="(preceding-sibling::*|following-sibling::*)[local-name()=local-name(current())]">
<xsl:value-of
select="concat('[',count(preceding-sibling::*[local-name()=local-name(current())])+1,']')" />
</xsl:if>
<!-- <xsl:call-template name="attrData"></xsl:call-template> -->
</xsl:for-each>
<xsl:text>##</xsl:text>
<xsl:apply-templates select="node()" />
</xsl:template>
I am new to XSLT. Please help!!!!
I made the following XSLT and added also the [position] to the output. You can remove that if you need.
This gives this output:
/root[1]
/root[1]/node[1]
/root[1]/node[1]/#attr[1]##abc
/root[1]/node[1]/#module[1]##try
/root[1]/node[1]/subnode[1]##Roshan
/root[1]/node[1]/subnode[2]##Chetan
/root[1]/node[1]/subnode[3]##Jennifer
With this XSLT. With the two output template you can choose how to print the Xpath.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="" version="2.0">
<xsl:output method="text" encoding="utf-8" />
<xsl:template match="/">
<xsl:apply-templates select="*"/>
</xsl:template>
<xsl:template match="*">
<xsl:call-template name="generateXPath">
<xsl:with-param name="previous" select="''"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="generateXPath">
<xsl:param name="previous" as="xs:string"/>
<xsl:variable name="this" select="." as="node()"/>
<xsl:if test="not(empty(.))">
<xsl:variable name="thisXPath" select="concat($previous, '/', name(.),'[', count(preceding-sibling::*[name() = name($this)])+1,']')"></xsl:variable>
<xsl:apply-templates select="." mode="output">
<xsl:with-param name="previous" select="$previous"/>
</xsl:apply-templates>
<xsl:text>
</xsl:text>
<xsl:for-each select="*|#*">
<xsl:call-template name="generateXPath">
<xsl:with-param name="previous" select="$thisXPath"/>
</xsl:call-template>
</xsl:for-each>
</xsl:if>
</xsl:template>
<xsl:template match="*" mode="output">
<xsl:param name="previous" as="xs:string"/>
<xsl:variable name="this" select="." as="node()"/>
<xsl:variable name="thisXPath">
<xsl:value-of select="concat($previous, '/', name(.),'[', count(preceding-sibling::*[name() = name($this)])+1,']')"></xsl:value-of>
<xsl:if test="not(*)">
<xsl:value-of select="concat('##',text())"></xsl:value-of>
</xsl:if>
</xsl:variable>
<xsl:value-of select="$thisXPath" />
</xsl:template>
<xsl:template match="#*" mode="output">
<xsl:param name="previous" as="xs:string"/>
<xsl:variable name="this" select="." as="node()"/>
<xsl:variable name="thisXPath" select="concat($previous, '/#', name(.),'[', count(preceding-sibling::*[name() = name($this)])+1,']','##',.)"></xsl:variable>
<xsl:value-of select="$thisXPath" />
</xsl:template>
</xsl:stylesheet>
Related
I'm working on a xsl template and one specific string is giving me a hard time.
<prixmenu>29.00-90.00</prixmenu>
Desired output :
<prixmenu>29€-90€</prixmenu>
The whole code I have is :
XML (input) :
<?xml version="1.0" encoding="UTF-8"?>
<data>
<etablissement not="15.0" etoile="2" >
<nom>L'Auberge Asterix</nom>
<index>AUBERGE ASTERIX (L')</index>
<id>0123456789</id>
<regionindex>Paris</regionindex>
<equipe>
<chef>Ratatouille</chef>
</equipe>
<pictoPratique cave_remarquable="0" coeur="0" ></pictoPratique>
<coordonnees>
<adresse>Random adress</adresse>
<tel>01 23 45 67 89/tel>
<fermetures>mam,maa,</fermetures>
<pratique terrasse="0"
voiturier="0"
parcPrive="1"
handicap="0"
airConditione="0"
piscine="0"
tennis="0"
chien="1"
relaischat="0"
delivery="0"
clickAndCollect="0"
itineraireGourmand="0"
menu_kids="1"
hebergement="0"
></pratique>
</coordonnees>
<texte>Lorem ipsum</texte>
<prixrestau>
<prixcarte>0</prixcarte>
<prixmenu>29.00-90.00</prixmenu>
</prixrestau>
</etablissement>
</data>
XSL stylesheet :
<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="data | node()[not(self::coordonnees)]">
<xsl:copy>
<xsl:apply-templates select="nom" />
<xsl:choose>
<xsl:when test="#etoile = 1">
<etoile>1 étoile</etoile>
</xsl:when>
<xsl:when test="#etoile > 1">
<etoile><xsl:value-of select="#etoile" /> étoiles</etoile>
</xsl:when>
</xsl:choose>
<xsl:apply-templates select="index" />
<xsl:apply-templates select="id" />
<xsl:apply-templates
select="#*[not(.='0')][name( ) != 'etoile'] | node()[not(self::index)][not(self::id)][not(self::prixrestau)][not(self::nom)][not(self::etoile)]" />
</xsl:copy>
</xsl:template>
<xsl:template match="#*[name( ) != 'etoile']">
<xsl:element name="{name()}">
<xsl:value-of select="number(.)" />
</xsl:element>
</xsl:template>
<xsl:template match="prixrestau/prixmenu" name="split">
<xsl:param name="pText" select="."/>
<xsl:if test="$pText">
<xsl:value-of select="number(substring-before(concat($pText, '-'), '-'))"/>
<xsl:call-template name="split">
<xsl:with-param name="pText" select="substring-after($pText, '-')"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template match="coordonnees">
<xsl:copy>
<xsl:apply-templates select="adresse" />
<xsl:apply-templates select="tel" />
<xsl:element name="prixrestau">
<xsl:value-of select="translate(../prixrestau/prixmenu,'.00.','€')"/>
<xsl:apply-templates select="../prixrestau/prixcarte[not(.='0')]" />
<xsl:element name="prixmenu">
<xsl:apply-templates select="../prixrestau/prixmenu" />
</xsl:element>
</xsl:element>
<xsl:apply-templates select="fermetures" />
<xsl:apply-templates
select="#*[not(.='0')] | node()[not(self::adresse)][not(self::tel)][not(self::fermetures)]" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Desired output :
<?xml version="1.0"?>
<data>
<etablissement>
<nom>L'Auberge Asterix</nom>
<etoile>2 étoiles</etoile>
<index>AUBERGE ASTERIX (L')</index>
<id>0123456789</id>
<not>13</not>
<regionindex>Paris</regionindex>
<equipe>
<chef>Ratatouille</chef>
</equipe>
<pictoPratique/>
<coordonnees>
<adresse>Random adress</adresse>
<tel>01 23 45 67 89</tel>
<prixrestau><prixmenu>29€-90€</prixmenu></prixrestau>
<fermetures>mam,maa,</fermetures>
<pratique>
<parcPrive>1</parcPrive>
<chien>1</chien>
<menu_kids>1</menu_kids>
</pratique>
</coordonnees>
<texte>Lorem ipsum</texte>
</etablissement>
</data>
Any suggestions on how to proceed ? Should I import FXSL or switch to XSLT 2.0 as it probably be less of a pain to get to the desired result ?
I've tried splitting it with the following code (I belive it's called a 'recursive template" :
<xsl:template match="prixrestau/prixmenu" name="split">
<xsl:param name="pText" select="."/>
<xsl:if test="$pText">
<xsl:value-of select="number(substring-before(concat($pText, '-'), '-'))"/>
<xsl:call-template name="split">
<xsl:with-param name="pText" select="substring-after($pText, '-')"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
This outputs
<prixmenu>2990</prixmenu>
And i've also tried
<xsl:value-of select="translate(../prixrestau/prixmenu,'.00.','€')"/>
and the output is :
29€-9€
Because '.00.' and '€'don't have the same length (MDN reference)...
How about:
<xsl:template match="prixmenu">
<xsl:copy>
<xsl:value-of select="format-number(substring-before(., '-'), '0€')"/>
<xsl:text>-</xsl:text>
<xsl:value-of select="format-number(substring-after(., '-'), '0€')"/>
</xsl:copy>
</xsl:template>
If you like, you could change the first xsl:value-of instruction to:
<xsl:value-of select="format-number(substring-before(., '-'), '0€-')"/>
and get rid of the xsl:text part - but I think it's better to keep it to make the code more readable.
This is my input
<SimpleInput>
<variable1>1</variable1>
<variable2>2</variable2>
<variable3>3</variable3>
</SimpleInput>
This is the output i am geting now
<Classes>
<ClassA>
<input1>overwrite 1</input1>
<input2>2</input2>
<input3>3</input3>
</ClassA>
<ClassB>
<input1>1</input1>
<input2>overwrite 2</input2>
<input3>3</input3>
</ClassB>
</Classes>
This is how i have achieved the above
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:variable name="myVar">
<input1><xsl:value-of select="/SimpleInput/variable1"/></input1>
<input2><xsl:value-of select="/SimpleInput/variable2"/></input2>
<input3><xsl:value-of select="/SimpleInput/variable3"/></input3>
</xsl:variable>
<xsl:template match="/">
<Classes>
<xsl:variable name="paramForClassA">
<input1><xsl:value-of select="'overwrite 1'"/></input1>
<input2><xsl:value-of select="/SimpleInput/variable2"/></input2>
<input3><xsl:value-of select="/SimpleInput/variable3"/></input3>
</xsl:variable>
<ClassA>
<xsl:call-template name="buildSection">
<xsl:with-param name="obj" select="$paramForClassA"/>
</xsl:call-template>
</ClassA>
<ClassB>
<xsl:variable name="paramForClassB">
<input1><xsl:value-of select="/SimpleInput/variable1"/></input1>
<input2><xsl:value-of select="'overwrite 2'"/></input2>
<input3><xsl:value-of select="/SimpleInput/variable3"/></input3>
</xsl:variable>
<xsl:call-template name="buildSection">
<xsl:with-param name="obj" select="$paramForClassB"/>
</xsl:call-template>
</ClassB>
</Classes>
</xsl:template>
<xsl:template name="buildSection">
<xsl:param name="obj" select="()"/>
<xsl:for-each select="$obj/*">
<xsl:element name="{name()}">
<xsl:copy-of select="#*|node()" />
</xsl:element>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
But I want to be able to overwrite/create the nodes i want dynamically without rebuilding the entire node tree before passing it to the buildSection template.
Below is an example of the output I am looking for (with an additional input4 on ClassB which i am not able to achieve with the code above)
<Classes>
<ClassA>
<input1>overwrite 1</input1>
<input2>2</input2>
<input3>3</input3>
</ClassA>
<ClassB>
<input1>1</input1>
<input2>overwrite 2</input2>
<input3>3</input3>
<input4>New Item</input4>
</ClassB>
</Classes>
Something similar to what is done here, but i am looking to replace or add the node itself if it doesnt exist.
There are 2 limitations with my current design which i am looking to overcome when passing the parameter to a template call.
Adding new elements to ClassX if necessary
Removing the need to rebuild the entire node tree (There could be over 80 variable in the node tree in some cases)
The build template is actually in a separate file and could be used from multiple callers. If we hard code the node tree building logic in each class (which are also in separate files), if there is a requirement to update the template, then I will need to also update all the callers (which can be upto 30 separate ones). Hope this explains the necessity of the new design.
Ideally something like this when building paramForX
<xsl:variable name="myReplacementsForA">
<input1>overwrite 1</input1>
</xsl:variable>
<xsl:variable name="myReplacementsForB">
<input2>overwrite 2</input2>
<input4>Add 4</input4>
</xsl:variable>
<xsl:variable name="paramForClassA">
<xsl:apply-templates select="$myVar" mode="add-or-replace-value">
<with-param name="replacements" select="$myReplacementsForA"/>
</xsl:apply-templates>
</xsl:variable>
<xsl:variable name="paramForClassB">
<xsl:apply-templates select="$myVar" mode="add-or-replace-value">
<with-param name="replacements" select="$myReplacementsForB"/>
</xsl:apply-templates>
</xsl:variable>
I managed to do it this way. Not sure if it is the most efficient
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:variable name="myVar">
<input1><xsl:value-of select="/SimpleInput/variable1"/></input1>
<input2><xsl:value-of select="/SimpleInput/variable2"/></input2>
<input3><xsl:value-of select="/SimpleInput/variable3"/></input3>
</xsl:variable>
<xsl:template match="/">
<Classes>
<xsl:variable name="myReplacementsForA">
<input1>overwrite 1</input1>
</xsl:variable>
<xsl:variable name="paramForClassA">
<xsl:apply-templates mode="buildNewParam">
<xsl:with-param name="original" select="$myVar"/>
<xsl:with-param name="replacements" select="$myReplacementsForA"/>
</xsl:apply-templates>
</xsl:variable>
<ClassA>
<xsl:value-of select="$paramForClassA/item2"/>
<xsl:call-template name="buildSection">
<xsl:with-param name="obj" select="$paramForClassA"/>
</xsl:call-template>
</ClassA>
<ClassB>
<xsl:variable name="myReplacementsForB">
<input2>overwrite 2</input2>
<input4>Add 4</input4>
</xsl:variable>
<xsl:variable name="paramForClassB">
<xsl:apply-templates mode="buildNewParam">
<xsl:with-param name="original" select="$myVar"/>
<xsl:with-param name="replacements" select="$myReplacementsForB"/>
</xsl:apply-templates>
</xsl:variable>
<xsl:call-template name="buildSection">
<xsl:with-param name="obj" select="$paramForClassB"/>
</xsl:call-template>
</ClassB>
</Classes>
</xsl:template>
<xsl:template name="buildSection">
<xsl:param name="obj" select="()"/>
<xsl:for-each select="$obj/*">
<xsl:element name="{name()}">
<xsl:copy-of select="#*|node()" />
</xsl:element>
</xsl:for-each>
</xsl:template>
<xsl:template mode="buildNewParam" match=".">
<xsl:param name="original"/>
<xsl:param name="replacements"/>
<xsl:variable name="merged">
<xsl:for-each select="$original/*">
<xsl:element name="{name()}">
<xsl:copy-of select="#*|node()" />
</xsl:element>
</xsl:for-each>
<xsl:for-each select="$replacements/*">
<xsl:element name="{name()}">
<xsl:copy-of select="#*|node()" />
</xsl:element>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="sorted">
<xsl:for-each select="$merged/*">
<xsl:sort select="name()"/>
<xsl:element name="{name()}">
<xsl:copy-of select="#*|node()" />
</xsl:element>
</xsl:for-each>
</xsl:variable>
<xsl:for-each select="$sorted/*">
<xsl:if test="name()!=name(following-sibling::node()[1])">
<xsl:element name="{name()}">
<xsl:copy-of select="#*|node()" />
</xsl:element>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
The transform I'm working on mergers two templates that has attributes that are space-separated.
An example would be:
<document template_id="1">
<header class="class1 class2" />
</document>
<document template_id="2">
<header class="class3 class4" />
</document>
And after the transform I want it to be like this:
<document>
<header class="class1 class2 class3 class4" />
</document>
How to achieve this?
I have tried (writing from memory):
<xsl:template match="/">
<header>
<xsl:attribute name="class">
<xsl:for-each select=".//header">
<xsl:value-of select="#class"/>
</xsl:for-each>
</xsl:attribute>
</header>
</xsl:template>
But that appends them all together, but I need them separated... and would be awesome if uniqued as well.
Thank you
Try this template, which simply adds a space before all the headers, apart from the first
<xsl:template match="/">
<header>
<xsl:attribute name="class">
<xsl:for-each select=".//header">
<xsl:if test="position() > 1">
<xsl:text> </xsl:text>
</xsl:if>
<xsl:value-of select="#class"/>
</xsl:for-each>
</xsl:attribute>
</header>
</xsl:template>
If you want your classes without repetitions, then use the following XSLT:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:template match="/">
<document>
<xsl:variable name="cls1">
<xsl:for-each select=".//header/#class">
<xsl:call-template name="tokenize">
<xsl:with-param name="txt" select="."/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="cls" select="exsl:node-set($cls1)"/>
<header>
<xsl:attribute name="class">
<xsl:for-each select="$cls/*[not(preceding-sibling::* = .)]">
<xsl:value-of select="."/>
<xsl:if test="position() < last()">
<xsl:text> </xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:attribute>
</header>
</document>
</xsl:template>
<xsl:template name="tokenize">
<xsl:param name="txt"/>
<xsl:if test="$txt">
<xsl:if test="contains($txt, ' ')">
<cls>
<xsl:value-of select="substring-before($txt, ' ')"/>
</cls>
<xsl:call-template name="tokenize">
<xsl:with-param name="txt" select="substring-after($txt, ' ')"/>
</xsl:call-template>
</xsl:if>
<xsl:if test="not(contains($txt, ' '))">
<cls>
<xsl:value-of select="$txt"/>
</cls>
</xsl:if>
</xsl:if>
</xsl:template>
</xsl:transform>
In XSLT 1.0 it is much more difficult than in XSLT 2.0, but as you see,
it is possible.
Edit
A revised version using Muenchian grouping (inspired by comment from Michael):
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:variable name="cls1">
<xsl:for-each select=".//header/#class">
<xsl:call-template name="tokenize">
<xsl:with-param name="txt" select="."/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="cls2" select="exsl:node-set($cls1)"/>
<xsl:key name="classKey" match="cls" use="."/>
<xsl:template match="/">
<document>
<header>
<xsl:attribute name="class">
<xsl:for-each select="$cls2/*[generate-id() = generate-id(key('classKey', .)[1])]">
<xsl:value-of select="."/>
<xsl:if test="position() < last()">
<xsl:text> </xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:attribute>
</header>
</document>
</xsl:template>
<xsl:template name="tokenize">
<xsl:param name="txt"/>
<xsl:if test="$txt">
<xsl:if test="contains($txt, ' ')">
<cls>
<xsl:value-of select="substring-before($txt, ' ')"/>
</cls>
<xsl:call-template name="tokenize">
<xsl:with-param name="txt" select="substring-after($txt, ' ')"/>
</xsl:call-template>
</xsl:if>
<xsl:if test="not(contains($txt, ' '))">
<cls>
<xsl:value-of select="$txt"/>
</cls>
</xsl:if>
</xsl:if>
</xsl:template>
</xsl:transform>
I'm a bit new to this language so I have several doubts.
I'm working to process an xml to display some data on pdf form.
But there a few strings that have "|" so I can split the data to display properly.
Here is the example of the input data:
<root>
<reference>
<NroLinRef>12</NroLinRef>
<CodRef>I20</CodRef>
<RazonRef>Data1|Data2|Data3|Data4|Data5|Data6|Data7</RazonRef>
</reference>
</root>
In the output I need something like this so I can display in order in row with cells so data must be clear to read.
<root>
<Reference>
<NroLinRef>12</NroLinRef>
<CodRef>I20</CodRef>
<Data1>Data1</Data1>
<Data2>Data2</Data2>
<Data3>Data3</Data3>
<Data4>Data4</Data4>
<Data5>Data5</Data5>
<Data6>Data6</Data6>
<Data7>Data7</Data7>
</Reference>
</root>
To do this I have been using other code that is from another question but can't find how to get the name to be updated or customized.
And the output I get is actually like this:
<root>
<Reference>
<NroLinRef>12</NroLinRef>
<CodRef>I20</CodRef>
<Data>Data1</Data>
<Data>Data2</Data>
<Data>Data3</Data>
<Data>Data4</Data>
<Data>Data5</Data>
<Data>Data6</Data>
<Data>Data7</Data>
</Reference>
</root>
This is the XSL i'm using
<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="Referencia/RazonRef" name="tokenize">
<xsl:param name="text" select="."/>
<xsl:param name="separator" select="'|'"/>
<xsl:choose>
<xsl:when test="not(contains($text, $separator))">
<Data>
<xsl:value-of select="normalize-space($text)"/>
</Data>
</xsl:when>
<xsl:otherwise>
<Data>
<xsl:value-of select="normalize-space(substring-before($text, $separator))"/>
</Data>
<xsl:call-template name="tokenize">
<xsl:with-param name="text" select="substring-after($text, $separator)"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
How can I get the output I want?
The expected result can be achieved by applying the following stylesheet:
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="RazonRef" name="tokenize">
<xsl:param name="text" select="."/>
<xsl:param name="separator" select="'|'"/>
<xsl:param name="i" select="1"/>
<xsl:element name="Data{$i}">
<xsl:value-of select="substring-before(concat($text, $separator), $separator)"/>
</xsl:element>
<xsl:if test="contains($text, $separator)">
<xsl:call-template name="tokenize">
<xsl:with-param name="text" select="substring-after($text, $separator)"/>
<xsl:with-param name="i" select="$i + 1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
I have some xml in the following format:
<top>
<topValue Value="1#1#5" />
<topValue Value="2#2#10" />
<topValue Value="1#1#3" />
<topValue Value="2#2#30" />
</top>
and output should look like that:
<boo>
<booEnrty>
<v>5</v>
<v>10</v>
</booEnrty>
<booEnrty>
<v>3</v>
<v>30</v>
</booEnrty>
</boo>
my XSLT to transform
<boo>
<xsl:for-each select="top/topValue">
<xsl:if test="position() mod 2 = 0">
<booEnrty>
<v><xsl:value-of select="substring-after(substring-after(#Value,'#'),'#')"/></v>
</booEnrty>
</xsl:if>
</xsl:for-each>
</boo>
What should the XSLT document look like to do this transform?
Any ideas?
Thanks
Maybe someone got a better approach to this, but the XSLT below works for your case.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="top">
<boo>
<xsl:apply-templates select="topValue[position() mod 2 = 1]"/>
</boo>
</xsl:template>
<xsl:template match="topValue[position() mod 2 = 1]">
<booEntry>
<v>
<xsl:call-template name="substring-after-last">
<xsl:with-param name="string" select="#Value" />
<xsl:with-param name="delimiter" select="'#'" />
</xsl:call-template>
</v>
<xsl:apply-templates select="following-sibling::*[1]"/>
</booEntry>
</xsl:template>
<xsl:template match="topValue">
<v>
<xsl:call-template name="substring-after-last">
<xsl:with-param name="string" select="#Value" />
<xsl:with-param name="delimiter" select="'#'" />
</xsl:call-template>
</v>
</xsl:template>
<xsl:template name="substring-after-last">
<xsl:param name="string" />
<xsl:param name="delimiter" />
<xsl:choose>
<xsl:when test="contains($string, $delimiter)">
<xsl:call-template name="substring-after-last">
<xsl:with-param name="string"
select="substring-after($string, $delimiter)" />
<xsl:with-param name="delimiter" select="$delimiter" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise><xsl:value-of select="$string"/></xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
How about something short and simple?
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:template match="/top">
<boo>
<xsl:for-each select="topValue[position() mod 2 = 1]">
<booEnrty>
<xsl:for-each select=". | following-sibling::topValue[1]">
<v>
<xsl:value-of select="substring-after(substring-after(#Value,'#'),'#')"/>
</v>
</xsl:for-each>
</booEnrty>
</xsl:for-each>
</boo>
</xsl:template>
</xsl:stylesheet>