I am trying to wrap all the text node in a <text> element, but facing challenge when encounter an inline elements (i, b, emphasis), that should be in same <text> node (in other words, it should be considered as text)... Please see input and desired output below:
(Note: I have to do this for specific inline elements only, hence kept it in param (it could be anything), for rest of the elements standard <text> rule should be applied. (Please see my xslt for details)
Input XML:
<?xml version="1.0" encoding="utf-8"?>
<root>
<para>XML Translation is a format that's used to <emphasis>exchange <i>localisation</i></emphasis>data</para>
<para>The process can now be reformulated with more detail as follows:<ul>
<li>Text extraction <note>Separation of translatable text from layout data</note></li>
<li>Pre-translation</li>
<li>Translation</li>
<li>Reverse conversion</li>
<li>Translation memory improvement</li>
</ul>above mentioned steps should <b>executed</b> sequentially</para>
</root>
OutPut should be:
<?xml version="1.0" encoding="utf-8"?>
<root>
<para>
<text xid="d0t3">XML Translation is a format that's used to <g ctype="emphasis">exchange <g ctype="i">localisation</g></g>data </text>
</para>
<para>
<text xid="d0t10">The process can now be reformulated with more detail as follows:</text>
<ul>
<li><text xid="d0t13">Text extraction <g ctype="note">Separation of translatable text from layout data</g></text></li>
<li><text xid="d0t17">Pre-translation</text></li>
<li><text xid="d0t19">Translation</text></li>
<li><text xid="d0t21">Reverse conversion</text></li>
<li><text xid="d0t23">Translation memory improvement</text></li>
</ul>
<text xid="d0t24">above mentioned steps should <g ctype="b">executed</g> sequentially</text>
</para>
</root>
I am trying something like this, but not able to achieve correct result:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:strip-space elements="*"/>
<xsl:param name="inlineElement" select="('emphasis', 'i', 'note', 'b')"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()">
<text>
<xsl:attribute name="xid">
<xsl:value-of select="generate-id()"/>
</xsl:attribute>
<xsl:value-of select="."/>
<xsl:if test="following-sibling::node()[local-name()=$inlineElement]">
<g>
<xsl:apply-templates select="following-sibling::node()[local-name()=$inlineElement]/text()"/>
</g>
</xsl:if>
</text>
</xsl:template>
</xsl:stylesheet>
I would use for-each-group group-adjacent:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:param name="inlineElement" select="('emphasis', 'i', 'note', 'b')"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[not(local-name() = $inlineElement)]">
<xsl:copy>
<xsl:for-each-group select="node()" group-adjacent="boolean(self::text() | self::*[local-name() = $inlineElement])">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<text xid="{generate-id(current-group()[self::text()][1])}">
<xsl:apply-templates select="current-group()"/>
</text>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
<xsl:template match="*[local-name() = $inlineElement]">
<g ctype="{local-name()}">
<xsl:apply-templates/>
</g>
</xsl:template>
</xsl:stylesheet>
That way, with Saxon 9.5, I get
<?xml version="1.0" encoding="UTF-8"?>
<root>
<para>
<text xid="d1t3">XML Translation is a format that's used to <g ctype="emphasis">exchange <g ctype="i">localisation</g>
</g>data</text>
</para>
<para>
<text xid="d1t10">The process can now be reformulated with more detail as follows:</text>
<ul>
<li>
<text xid="d1t13">Text extraction <g ctype="note">Separation of translatable text from layout data</g>
</text>
</li>
<li>
<text xid="d1t17">Pre-translation</text>
</li>
<li>
<text xid="d1t19">Translation</text>
</li>
<li>
<text xid="d1t21">Reverse conversion</text>
</li>
<li>
<text xid="d1t23">Translation memory improvement</text>
</li>
</ul>
<text xid="d1t24">above mentioned steps should <g ctype="b">executed</g> sequentially</text>
</para>
</root>
Related
Need to transform following XML snippet into DITA using XSLT. My requirements are:
1. All the tags comes before "orderedlist" should be wrapped under "context" node.
2. All the tags comes after "orderedlist" should be in "result".
3. All the "include" tags should be wrapped under their preceding sibling nodes.
XML:
<?xml version="1.0" encoding="UTF-8"?>
<procedure>
<para>This is first para</para>
<para>This is second para</para>
<include>This is include</include>
<orderedlist>
<listitem>this is list item</listitem>
<include>This is include</include>
<listitem>this is list item <include>this is include</include></listitem>
</orderedlist>
<observation>this is observation</observation>
<para>this is result para <include>this is include</include></para>
<include>This is include</include>
</procedure>
Output:
<?xml version="1.0" encoding="UTF-8"?>
<task>
<context>
<p>This is first para</p>
<p>This is second para <included type='tag'>This is include</included>
</p>
</context>
<ol>
<li>this is list item <included type='tag'>This is include</included>
</li>
<li>this is list item <included type='tag'>this is include</included></li>
</ol>
<result>
<observation>this is observation</observation>
<p>this is result para <included type='tag'>this is include</included><included type='tag'>this is include</included>
</p>
</result>
</task>
My XSL:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template match="procedure">
<task>
<context>
<xsl:apply-templates select="*[parent::procedure][following-sibling::orderedlist]"/>
</context>
<xsl:apply-templates select="orderedlist"/>
<result>
<xsl:apply-templates select="*[parent::procedure][preceding-sibling::orderedlist]"/>
</result>
</task>
</xsl:template>
<xsl:template match="para">
<p>
<xsl:apply-templates/>
<include>
<xsl:apply-templates select="following-sibling::include"/>
</include>
</p>
</xsl:template>
<!-- rest of the template goes here -->
<xsl:template match="listitem">
<li>
<xsl:apply-templates/>
<include>
<xsl:apply-templates select="following-sibling::include"/>
</include>
</li>
</xsl:template>
</xsl:stylesheet>
Any pointer will be a great help. Thanks.
The first thing to note is you can simplify the following expression:
<xsl:apply-templates select="*[parent::procedure][following-sibling::orderedlist]"/>
You don't need the [parent::procedure] here, because you are already positioned on a procedure element, so so you know if you select any child element, it will have that as a parent!
<xsl:apply-templates select="*[following-sibling::orderedlist]"/>
However, you might need to add an clause to ensure you don't output the include elements at this point, as you will need special code to handle them being included later
<xsl:template match="include" />
To handle the include elements, it might be worth defining a key, so you can group them by the first most proceding non-include element, like so
<xsl:key name="include" match="include" use="generate-id(preceding-sibling::*[not(self::include)][1])"/>
Then, when matching an element such as para or listitem, you can then get the include elements to include, just like this:
<xsl:copy-of select="key('include', generate-id())"/>
Note I am not sure how you want to handle multipe include elements for a single element, but in my example, it will output them separately as opposing to merging them:
Here is the full XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="include" match="include" use="generate-id(preceding-sibling::*[not(self::include)][1])"/>
<xsl:template match="procedure">
<task>
<context>
<xsl:apply-templates select="*[following-sibling::orderedlist]"/>
</context>
<xsl:apply-templates select="orderedlist"/>
<result>
<xsl:apply-templates select="*[preceding-sibling::orderedlist]"/>
</result>
</task>
</xsl:template>
<xsl:template match="orderedlist">
<ol>
<xsl:apply-templates />
</ol>
</xsl:template>
<xsl:template match="para">
<p>
<xsl:apply-templates/>
<xsl:copy-of select="key('include', generate-id())" />
</p>
</xsl:template>
<xsl:template match="listitem">
<li>
<xsl:apply-templates/>
<xsl:copy-of select="key('include', generate-id())" />
</li>
</xsl:template>
<xsl:template match="include" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
When applied to your sample XML, the following is output
<task>
<context>
<p>This is first para</p>
<p>This is second para<include>This is include</include></p>
</context>
<ol>
<li>this is list item<include>This is include</include></li>
<li>this is list item</li>
</ol>
<result>
<observation>this is observation</observation>
<p>this is result para<include>This is include</include></p>
</result>
</task>
Give this a try:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="#* | node()" name="Copy">
<xsl:copy>
<xsl:apply-templates select="#* | node()" />
<xsl:call-template name="Include" />
</xsl:copy>
</xsl:template>
<xsl:template match="procedure">
<task>
<context>
<xsl:apply-templates select="*[following-sibling::orderedlist]"/>
</context>
<xsl:apply-templates select="orderedlist"/>
<result>
<xsl:apply-templates select="*[preceding-sibling::orderedlist]"/>
</result>
</task>
</xsl:template>
<xsl:template match="para">
<p>
<xsl:apply-templates/>
<xsl:call-template name="Include" />
</p>
</xsl:template>
<!-- rest of the template goes here -->
<xsl:template match="listitem">
<li>
<xsl:apply-templates/>
<xsl:call-template name="Include" />
</li>
</xsl:template>
<xsl:template name="Include">
<xsl:apply-templates
select="following-sibling::include[
generate-id(preceding-sibling::*[not(self::include)][1]) =
generate-id(current())]"
mode="performIncludes"/>
</xsl:template>
<xsl:template match="include" />
<xsl:template match="include" mode="performIncludes">
<xsl:call-template name="Copy" />
</xsl:template>
</xsl:stylesheet>
Output when run on your sample input:
<task>
<context>
<p>This is first para</p>
<p>This is second para<include>This is include</include></p>
</context>
<orderedlist>
<li>this is list item<include>This is include</include></li>
<li>this is list item</li>
</orderedlist>
<result>
<observation>this is observation</observation>
<p>this is result para<include>This is include</include></p>
</result>
</task>
I am new to XSLT.
I need to transform the below input xml format to the desired output format which is under it (O/P Format is an unorderedList in HTML) using XSLT to use this in a JQuery plugin. I have tried with the below XSLT code myself but i need to add more to it. I am finding hard time to get this transformation done, can any one please help me on this.
Input Format
<Unit id = "2000001">
<Unit id = "2000002">
<Unit id = "2000006">
<Unit id = "2000032">
<Data>
<PartyId>2000032</PartyId>
<PartyTypeCode>DEPT</PartyTypeCode>
<PartyName>2017964 SM Retirement Party</PartyName>
</Data>
</Unit>
<Unit id = "2000033">
<Data>
<PartyId>2000033</PartyId>
<PartyTypeCode>DEPT</PartyTypeCode>
<PartyName>2018370 2012 Director's Ornament</PartyName>
</Data>
</Unit>
<Data>
<PartyId>2000006</PartyId>
<PartyTypeCode>DEPT</PartyTypeCode>
<PartyName>Projects Executive</PartyName>
</Data>
</Unit>
<Data>
<PartyId>2000002</PartyId>
<PartyTypeCode>SEG</PartyTypeCode>
<PartyName>Tres Aguilas Management</PartyName>
</Data>
</Unit>
<Data>
<PartyId>2000001</PartyId>
<PartyTypeCode>SEG</PartyTypeCode>
<PartyName>Tres Aguilas Enterprise</PartyName>
</Data>
</Unit>
Output Format:
<ul>
<li id = "2000001">
<span>Tres Aguilas Enterprise</span>
<ul>
<li id = "2000002">
<span>Tres Aguilas Management</span>
<ul>
<li id = "2000006">
<span>Projects Executive</span>
<ul>
<li id = "2000032">
<span>2017964 SM Retirement Party</span>
</li>
<li id = "2000033">
<span>2018370 2012 Director's Ornament</span>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
XSLT Code:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="//Unit">
<ul>
<li><xsl:value-of select="Data/PartyName"/></li>
</ul>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
This is a "push style" stylesheet that achieves what you want.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output indent="yes"/>
<!--identity template-->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<!--convert every <Unit> into a <UL>,
then "push" the attributes(i.e. #id),
and then "push" any <Unit> children-->
<xsl:template match="Unit">
<ul>
<xsl:apply-templates select="#*"/>
</ul>
</xsl:template>
<!--Create an <li> and copy the #id attribute,
then "push" the Data/PartyName that are children of this <Unit>-->
<xsl:template match="Unit/#id">
<li>
<xsl:copy/>
<xsl:apply-templates select="../Data/PartyName"/>
<xsl:apply-templates select="../Unit"/>
</li>
</xsl:template>
<!--convert <PartyName> into <span> -->
<xsl:template match="Data/PartyName">
<span><xsl:value-of select="."/></span>
</xsl:template>
</xsl:stylesheet>
:) Thanks a lot Mads Hansen, for contributing to my question. I finally did changes to the XSLT you gave and succeeded in achieving the Transformation to required Format.
Here is the final XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output indent="yes"/>
<!--identity template-->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<!--convert every <Unit> into a <UL>,
then "push" the attributes(i.e. #id),
and then "push" any <Unit> children-->
<xsl:template match="Unit">
<xsl:apply-templates select="#*"/>
</xsl:template>
<!--Create an <li> and copy the #id attribute,
then "push" the Data/PartyName that are children of this <Unit>-->
<xsl:template match="Unit/#id">
<li>
<xsl:copy/>
<xsl:apply-templates select="../Data/PartyName"/>
<xsl:if test= "../Unit">
<ul>
<xsl:apply-templates select="../Unit"/>
</ul>
</xsl:if>
</li>
</xsl:template>
<!--convert <PartyName> into <span> -->
<xsl:template match="Data/PartyName">
<span>
<xsl:value-of select="."/>
</span>
</xsl:template>
</xsl:stylesheet>
need to convert an xml file having a tag(dynamicVariable) that has an attribute(name).This xml file has to be converted using xsl into the same xml file such that the tag (dynamicVariable) should have the same structure along with it and its the tag-content also should be the value of the attribute.
need to convert the below xml file
<Content>
<alertHeader>
<text xmlns="http://abc.com" xmlns:w="http://def.com"> Claim
<dynamicVariable name="Claim_Reference" />: More Information Needed
</text>
<contactUs>false</contactUs>
</alertHeader>
<body>
<text> ATM/Debit Card Claim:
<strong><dynamicVariable name="Claim_Reference" /></strong>
</text>
</body>
</Content>
into the same format but the tag having 'name' attribute should appear in the output xml file as this format
<dynamicVariable name="Claim_Reference" />Claim_Reference</dynamicVariable>
Can anyone provide the necessary xsl file in converting the same. Hope that its done using
<xsl:copy></xsl:copy> or <xsl:copy-of /> tags .
As simple as this:
<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="*[name() = 'dynamicVariable']">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:value-of select="#name"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the provided XML document:
<Content>
<alertHeader>
<text xmlns="http://abc.com" xmlns:w="http://def.com"> Claim
<dynamicVariable name="Claim_Reference" />: More Information Needed
</text>
<contactUs>false</contactUs>
</alertHeader>
<body>
<text> ATM/Debit Card Claim:
<strong>
<dynamicVariable name="Claim_Reference" />
</strong>
</text>
</body>
</Content>
the wanted, correct result is produced:
<Content>
<alertHeader>
<text xmlns="http://abc.com" xmlns:w="http://def.com"> Claim
<dynamicVariable name="Claim_Reference">Claim_Reference</dynamicVariable>: More Information Needed
</text>
<contactUs>false</contactUs>
</alertHeader>
<body>
<text> ATM/Debit Card Claim:
<strong>
<dynamicVariable name="Claim_Reference">Claim_Reference</dynamicVariable>
</strong>
</text>
</body>
</Content>
Explanation:
The identity rule copies every node "as-is".
A single template overrides the identity template. It matches any that has athe name "dynamicVariable" regardless of namespace, and that is a child of strong (thus specifying more context helps us process only this occurence of dynamicVariable but leave the preceding one "as-is").
The overriding tempalte shallo-copies the current node, then copies its attributes, then finally creates a text-node child whose contents is the string value of the name attribute of the current (matched) element.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:t="http://abc.com">
<xsl:output method="xml"/>
<xsl:template match="*">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="dynamicVariable[#name]|t:dynamicVariable[#name]">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:value-of select="#name"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
I have below scenario for my XML.
<content>
<para>text-1 <emphasis type="bold">text-2</emphasis> text-3</para>
</content>
I want to parse it like below
<content>
<p>text-1 <b>text-2</b> text-3</p>
</content>
I have created my XSLT as below
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" encoding="ISO-8859-1" indent="no"/>
<xsl:template name="para">
<p>
<xsl:value-of select="text()" disable-output-escaping="yes"/>
<xsl:for-each select="child::*">
<xsl:if test="name()='emphasis'">
<xsl:call-template name="emphasis"/>
</xsl:if>
</xsl:for-each>
</p>
</xsl:template>
<xsl:template name="emphasis">
<xsl:if test="attribute::type = 'bold'">
<b>
<xsl:value-of select="text()" disable-output-escaping="yes"/>
</b>
</xsl:if>
</xsl:template>
<xsl:template match="/">
<content>
<xsl:for-each select="content/child::*">
<xsl:if test="name()='para'">
<xsl:call-template name="para"/>
</xsl:if>
</xsl:for-each>
</content>
</xsl:template>
</xsl:stylesheet>
XSLT provided above is generating output like below
<content>
<p>text-1 text-3<b>text-2 </b></p>
</content>
Please guide me with your suggestions, how can I get my desire output?
To do this, you just need to extend the standard Identity Transform with special cases for matching your para and emphasis elements. For example, for para elements you would the following to replace para with p and then continue matching all the child nodes
<xsl:template match="para">
<p>
<xsl:apply-templates select="#*|node()"/>
</p>
</xsl:template>
So, given the following XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<!-- This is the Identity Transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<!-- Replace para with p -->
<xsl:template match="para">
<p>
<xsl:apply-templates select="#*|node()"/>
</p>
</xsl:template>
<!-- Replace emphasis with b -->
<xsl:template match="emphasis[#type='bold']">
<b>
<xsl:apply-templates select="node()"/>
</b>
</xsl:template>
</xsl:stylesheet>
When applied to the following input XML
<content>
<para>text-1 <emphasis type="bold">text-2</emphasis> text-3</para>
</content>
The following is output
<content>
<p>text-1 <b>text-2</b> text-3</p>
</content>
You should be able to see how easy it is to extend to other cases should you input XML have more tags to transform.
do it like this ;)
<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:template match="content">
<content><xsl:apply-templates select="para" /></content>
</xsl:template>
<xsl:template match="emphasis [#type='bold']">
<b><xsl:value-of select="." /></b>
</xsl:template>
</xsl:stylesheet>
when you do it like this the default template will catch text-1 and text-3
There is some problem in my xsl ,I do not know the reason
I want to use apply-templates to reverse the different sequences of XML without xsl:sort;
For example : the following is the input
<book title="XML">
<author first="P" />
<chapter title="A">
<section title="A.1" />
<section title="A.2">
<section title="A.2.1" />
<section title="A.2.2" />
</section>
<section title="A.3">
<section title="A.3.1" />
</section>
</chapter>
<chapter title="B">
<section title="B.1" />
<section title="B.2">
<section title="B.2.1" />
<section title="B.2.2" />
</section>
</chapter>
</book>
I want to get the output like this:this is my xsl.
<?xml version="1.0" encoding="UTF-8"?>
<book title="XML">
<author first="P"/>
<chapter title="A">
<section title="A.1">
<section title="A.3.1"/>
</section>
<section title="A.2">
<section title="A.2.2"/>
<section title="A.2.1"/>
</section>
<section title="A.1"/>
</chapter>
<chapter title="B">
<section title="B.2">
<section title="B.2.2"/>
<section title="B.2.1"/>
</section>
<section title="B.1"/>
</chapter>
</book>
Yes,the sections have been reversed but the chapters are not.
the following is my xsl ,there is some problem here ,could you help me to find it??
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent ="yes"/>
<xsl:template match="/">
<xsl:apply-templates/>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="book">
<xsl:copy>
<xsl:sequence select="#title"/>
<xsl:sequence select="author"/>
<xsl:apply-templates select="chapter">
<xsl:with-param name="seq" select="section"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match ="chapter|section" as="element()">
<xsl:param name="seq" as="element(section)*"/>
<xsl:copy>
<xsl:sequence select="#title"/>
<xsl:if test="not(empty($seq))">
<xsl:apply-templates select="chapter">
<xsl:with-param name="seq" select="$seq"/>
</xsl:apply-templates>
<xsl:apply-templates select="$seq[1]"/>
</xsl:if>
</xsl:copy>
</xsl:template>
</xsl:transform>
This stylesheet:
<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()[1]|#*"/>
</xsl:copy>
<xsl:apply-templates select="following-sibling::node()[1]"/>
</xsl:template>
<xsl:template match="section">
<xsl:apply-templates select="following-sibling::node()[1]"/>
<xsl:copy>
<xsl:apply-templates select="node()[1]|#*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Output:
<book title="XML">
<author first="P"></author>
<chapter title="A ">
<section title="A.3 ">
<section title="A.3.1"></section>
</section>
<section title="A.2">
<section title="A.2.2"></section>
<section title="A.2.1"></section>
</section>
<section title="A.1"></section>
</chapter>
<chapter title="B">
<section title="B.2">
<section title="B.2.2"></section>
<section title="B.2.1"></section>
</section>
<section title="B.1"></section>
</chapter>
</book>
How about this?
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="2.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 ="chapter|section">
<xsl:copy>
<xsl:copy-of select="#*" />
<xsl:for-each select="*">
<xsl:sort select="position()" data-type="number" order="descending"/>
<xsl:apply-templates select="." />
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:copy>
<xsl:copy-of select="#*" />
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:transform>
A couple of things to note:
match="*" template: This provides a default behavior for elements that we just need to copy with attributes and then process the children. This replaces your "book" and "/" templates and doesn't make assumptions about what elements are in it. This means we now can focus on providing template(s) for elements that are not covered by default behavior.
for-each: This is where the magic happens by enumerating the children which we then sort in descending order based on position before processing them with apply templates.