How to count disp-quote in section - xslt

Count multiple disp-quote in section if disp-quote count > 1 in section then EXAMPLE S/B EXAMPLE 1 If I am run this XSLT then generate number in single disp-quote
Input
<?xml version="1.0" encoding="UTF-8"?>
<book>
<sec id="ceb_6511034722757hl" disp-level="1" specific-use="15.1"><label>15.1 </label><title>I. OVERVIEW</title>
<p content-type="new">This chapter provides</p>
<disp-quote>
<p content-type="example"><bold>EXAMPLE</bold> An employer notices.</p>
</disp-quote>
</sec>
<sec id="ceb_6511034722757hl" disp-level="1" specific-use="15.2"><label>15.2 </label><title>I. Employer</title>
<p content-type="new">This chapter provides</p>
<disp-quote>
<p content-type="example"><bold>EXAMPLE</bold> An employer notices.</p>
</disp-quote>
<p content-type="new">This chapter provides</p>
<disp-quote>
<p content-type="example"><bold>EXAMPLE</bold> An employer notices.</p>
</disp-quote>
<p content-type="new">This chapter provides</p>
<disp-quote>
<p content-type="example"><bold>EXAMPLE</bold> An employer notices.</p>
</disp-quote>
<disp-quote>
<p content-type="example"><bold>EXAMPLE</bold> An employer notices.</p>
</disp-quote>
</sec>
</book>
Expected Output
<?xml version="1.0" encoding="UTF-8"?><book>
<sec id="ceb_6511034722757hl" disp-level="1" specific-use="15.1"><label>15.1 </label><title>I. OVERVIEW</title>
<p content-type="new">This chapter provides</p>
<disp-quote>
<p content-type="example"><bold>EXAMPLE</bold> An employer notices.</p>
</disp-quote>
</sec>
<sec id="ceb_6511034722757hl" disp-level="1" specific-use="15.2"><label>15.2 </label><title>I. Employer</title>
<p content-type="new">This chapter provides</p>
<disp-quote>
<p content-type="example"><bold>EXAMPLE 1</bold> An employer notices.</p>
</disp-quote>
<p content-type="new">This chapter provides</p>
<disp-quote>
<p content-type="example"><bold>EXAMPLE 2</bold> An employer notices.</p>
</disp-quote>
<p content-type="new">This chapter provides</p>
<disp-quote>
<p content-type="example"><bold>EXAMPLE 3</bold> An employer notices.</p>
</disp-quote>
<disp-quote>
<p content-type="example"><bold>EXAMPLE 4</bold> An employer notices.</p>
</disp-quote>
</sec>
</book>
XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output method="xml" omit-xml-declaration="no"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="disp-quote//bold[.='EXAMPLE']">
<bold>
<xsl:value-of select="."/>
<xsl:number level="any" count="bold" from="sec" format=" 1"/>
</bold>
</xsl:template>
</xsl:stylesheet>
Count multiple disp-quote in section if disp-quote count > 1 in section then EXAMPLE S/B EXAMPLE 1 If I am run this XSLT then generate number in single disp-quote.

In XSLT 3 you could use an accumulator:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
expand-text="yes"
exclude-result-prefixes="#all"
version="3.0">
<xsl:mode on-no-match="shallow-copy" use-accumulators="#all"/>
<xsl:output indent="yes"/>
<xsl:accumulator name="disp-quote-count" as="xs:integer" initial-value="0">
<xsl:accumulator-rule match="sec" select="0"/>
<xsl:accumulator-rule match="sec/disp-quote" select="$value + 1"/>
</xsl:accumulator>
<xsl:template match="sec[accumulator-after('disp-quote-count') > 1]/disp-quote//bold[. = 'EXAMPLE']">
<xsl:copy>{.} {accumulator-before('disp-quote-count')}</xsl:copy>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/bwe3bW/2
Or in XSLT 2 count the disp-quote children in the match pattern and only match if there are at least two:
<xsl:template match="sec[disp-quote[2]]/disp-quote//bold[. = 'EXAMPLE']">
<xsl:copy>
<xsl:value-of select="."/>
<xsl:number level="any" count="bold" from="sec" format=" 1"/>
</xsl:copy>
</xsl:template>
https://xsltfiddle.liberty-development.net/bwe3bW/3

Related

XSLT - Change value of element in xml based on some condition

I need to modify the content of xml based on value of some elemnt in the input xml.
Input XML:
<?xml version="1.0" encoding="UTF-8"?>
<Objects>
<Object class="Item" version="1.0" distName="A-1/B-1/Item-0">
<p name="sDate">2013-02-11T00:00:00+02:00:00</p>
<p name="present">1</p>
<p name="stopD">2013-02-21T00:00:00+02:00:00</p>
<p name="id">CPU</p>
</Object>
<Object class="Item" version="1.0" distName="A-1/B-1/Item-1">
<p name="sDate">2013-02-11T00:00:00+02:00:00</p>
<p name="present">1</p>
<p name="stopD">2013-02-21T00:00:00+02:00:00</p>
<p name="id">CPU</p>
</Object>
</Objects>
The XSL should change the value of an element based on its value.
For Eg:
In node Item, if the value of element sDate is 2013-02-11T00:00:00+02:00:00 , i need to make it empty like shown below.
Output XML:
<?xml version="1.0" encoding="UTF-8"?>
<Objects>
<Object class="Item" version="1.0" distName="A-1/B-1/Item-0">
<p name="sDate"></p>
<p name="present">1</p>
<p name="stopD">2013-02-21T00:00:00+02:00:00</p>
<p name="id">CPU</p>
</Object>
<Object class="Item" version="1.0" distName="A-1/B-1/Item-1">
<p name="sDate"></p>
<p name="present">1</p>
<p name="stopD">2013-02-21T00:00:00+02:00:00</p>
<p name="id">CPU</p>
</Object>
</Objects>
I tried some xsl but couldnt get the thing working.. Any leads?
Your question is not quite clear. The following stylesheet will do exactly what you ask for - but I am not sure it provides a general example:
XSLT 1.0
<xsl:stylesheet 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:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="p[#name='sDate'][.='2013-02-11T00:00:00+02:00:00']">
<p name="sDate"/>
</xsl:template>
</xsl:stylesheet>
Note:
In node Item, if the value of element sDate is
2013-02-11T00:00:00+02:00:00
There is no Item node in your XML, nor a sDate element.

xslt how to fill missing numbers

This is the input xml
<?xml version="1.0" encoding="UTF-8"?>
<record>
<Tubes>
<Tube carousel_pos="1" tube_pos="1">
<TubeID>FLW140000293A0101</TubeID>
<markers>
<marker position="4">MSIGG1-PC55</marker>
<marker position="9">MSIGG1-PB</marker>
<marker position="8">MSIGG1-APCAF750</marker>
<marker position="10">CD45-KO</marker>
</markers>
</Tube>
<Tube carousel_pos="2" tube_pos="2">
<TubeID>FLW140000293A0102</TubeID>
<markers>
<marker position="4">CD3-PC55</marker>
<marker position="9">CD8-PB</marker>
<marker position="8">CD4-APCAF750</marker>
<marker position="10">CD45-KO</marker>
</markers>
</Tube>
</Tubes>
</record>
This is what it should output
<p num="1">Empty</p>
<p num="2">Empty</p>
<p num="3">Empty</p>
<p num="4">CD3-PC55</p>
<p num="5">Empty</p>
<p num="6">Empty</p>
<p num="7">Empty</p>
<p num="8">CD4-APCAF750</p>
<p num="9">CD8-PB</p>
<p num="10">CD45-KO</p>
This is my xslt
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" exclude-result-prefixes="#all"/>
<xsl:template match="/record/Tubes/Tube">
<xsl:for-each select="markers/marker">
<xsl:sort select="#position" data-type="number"/>
<xsl:choose>
<xsl:when test="position() < #position">
<xsl:call-template name="routine">
<xsl:with-param name="PC" select="position()"/>
<xsl:with-param name="PT" select="#position"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
<xsl:template name="routine">
<xsl:param name="PC"/>
<xsl:param name="PT"/>
</xsl:template>
</xsl:stylesheet>
If you are able to use XSLT 2.0, as your current XSLT is showing, you should be able to make use of an incrementing loop, like so
<xsl:for-each select="1 to 10">
First create a variable holding all the marker elements, the get the maximum #position attribute
<xsl:variable name="markers" select="markers/marker" />
<xsl:variable name="max" select="max($markers/#position)" />
Then, you have your xsl:for-each loop like this:
<xsl:for-each select="1 to xs:integer($max)">
To check if the element exists for each position is then quite straight-forward using the previous markers variable
<xsl:variable name="position" select="position()" />
<xsl:choose>
<xsl:when test="$markers[#position = $position]">
Try this XSLT
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" exclude-result-prefixes="#all">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/record/Tubes/Tube">
<xsl:variable name="markers" select="markers/marker" />
<xsl:variable name="max" select="max($markers/#position)" />
<div>
<xsl:for-each select="1 to xs:integer($max)">
<xsl:variable name="position" select="position()" />
<p num="{$position}">
<xsl:choose>
<xsl:when test="$markers[#position = $position]">
<xsl:value-of select="$markers[#position = $position]"/>
</xsl:when>
<xsl:otherwise>
<xsl:text>Empty</xsl:text>
</xsl:otherwise>
</xsl:choose>
</p>
</xsl:for-each>
</div>
</xsl:template>
</xsl:stylesheet>
This produces the following output (This assumed your wanted to do it separately by each tube element:
<div>
<p num="1">Empty</p>
<p num="2">Empty</p>
<p num="3">Empty</p>
<p num="4">MSIGG1-PC55</p>
<p num="5">Empty</p>
<p num="6">Empty</p>
<p num="7">Empty</p>
<p num="8">MSIGG1-APCAF750</p>
<p num="9">MSIGG1-PB</p>
<p num="10">CD45-KO</p>
</div>
<div>
<p num="1">Empty</p>
<p num="2">Empty</p>
<p num="3">Empty</p>
<p num="4">CD3-PC55</p>
<p num="5">Empty</p>
<p num="6">Empty</p>
<p num="7">Empty</p>
<p num="8">CD4-APCAF750</p>
<p num="9">CD8-PB</p>
<p num="10">CD45-KO</p>
</div>

Order of nodes in XSL Transformation

I have a xml which looks like below :
<?xml version="1.0" encoding="UTF-8"?>
<Object>
<Data type="plan" name="testAom" id="10">
<obj class="D" version="1.0" distName="A-1/B-1/C-1/D-1" operation="create" >
<p name="Active">1</p>
<p name="Type">CPU</p>
<p name="StDate">2013-07-27T00:00:00+00:00</p>
<p name="StpDate">2013-07-29T00:00:00+00:00</p>
</obj>
<obj class="E" version="1.0" distName="A-1/B-1/C-1/D-1/E-1" operation="create">
<p name="dayOfWeek">0</p>
<p name="interval">10</p>
</obj>
<obj class="E" version="1.0" distName="A-1/B-1/C-1/D-2/E-1" operation="update">
<p name="dayOfWeek">0</p>
<p name="interval">10</p>
</obj>
<obj class="D" version="1.0" distName="A-1/B-1/C-1/D-2" operation="update">
<p name="Active">1</p>
<p name="Type">CPU</p>
<p name="StDate">2013-07-27T00:00:00+00:00</p>
<p name="StpDate">2013-07-29T00:00:00+00:00</p>
</obj>
</Data>
</Object>
Here the order of the input source file is not guaranteed. But in the output after an XSL transformation, i require the output to be in certain order.
Below is the XSL:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="obj[#class = 'D' ]">
<xsl:variable name="item" select="."/>
<xsl:choose>
<xsl:when test="$item/#operation='update'">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:attribute name="operation">delete</xsl:attribute>
<xsl:apply-templates select="node()"/>
</xsl:copy>
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:attribute name="operation">create</xsl:attribute>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:attribute name="operation">NEW_create</xsl:attribute>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="obj[#class = 'E' ]">
<xsl:variable name="childitem" select="."/>
<xsl:choose>
<xsl:when test="$childitem/#operation='update'">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:attribute name="operation">delete</xsl:attribute>
<xsl:apply-templates select="node()"/>
</xsl:copy>
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:attribute name="operation">create</xsl:attribute>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:attribute name="operation">NEW_create</xsl:attribute>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
The output i get is :
<?xml version="1.0" encoding="UTF-8"?>
<Object>
<Data type="plan" name="testAom" id="10">
<obj class="D" version="1.0" distName="A-1/B-1/C-1/D-1" operation="NEW_create">
<p name="Active">1</p>
<p name="Type">CPU</p>
<p name="StDate">2013-07-27T00:00:00+00:00</p>
<p name="StpDate">2013-07-29T00:00:00+00:00</p>
</obj>
<obj class="E" version="1.0" distName="A-1/B-1/C-1/D-1/E-1" operation="NEW_create">
<p name="dayOfWeek">0</p>
<p name="interval">10</p>
</obj>
<obj class="E" version="1.0" distName="A-1/B-1/C-1/D-2/E-1" operation="delete">
<p name="dayOfWeek">0</p>
<p name="interval">10</p>
</obj>
<obj class="E" version="1.0" distName="A-1/B-1/C-1/D-2/E-1" operation="create">
<p name="dayOfWeek">0</p>
<p name="interval">10</p>
</obj>
<obj class="D" version="1.0" distName="A-1/B-1/C-1/D-2" operation="delete">
<p name="Active">1</p>
<p name="Type">CPU</p>
<p name="StDate">2013-07-27T00:00:00+00:00</p>
<p name="StpDate">2013-07-29T00:00:00+00:00</p>
</obj>
<obj class="D" version="1.0" distName="A-1/B-1/C-1/D-2" operation="create">
<p name="Active">1</p>
<p name="Type">CPU</p>
<p name="StDate">2013-07-27T00:00:00+00:00</p>
<p name="StpDate">2013-07-29T00:00:00+00:00</p>
</obj>
</Data>
</Object>
Here when the operation attribute is "update", i need to do a delete and create.
The nodes above have a parent child relationship based on attribute distName, ie A-1/B-1/C-1/D-1 is parent of A-1/B-1/C-1/D-1/E-1.
For the update operation to work correct, i need the parent create and delete first and then followed by child delete and create always.
How can this be achieved irrespective of the order of input source xml file??
ie. obj nodes with class attribute D should be first in order than E.
Expected Output XML:
<?xml version="1.0"?>
<Object>
<Data type="plan" name="testAom" id="10">
<obj class="D" version="1.0" distName="A-1/B-1/C-1/D-1" operation="NEW_create">
<p name="Active">1</p>
<p name="Type">CPU</p>
<p name="StDate">2013-07-27T00:00:00+00:00</p>
<p name="StpDate">2013-07-29T00:00:00+00:00</p>
</obj>
<obj class="E" version="1.0" distName="A-1/B-1/C-1/D-1/E-1" operation="NEW_create">
<p name="dayOfWeek">0</p>
<p name="interval">10</p>
</obj>
<obj class="D" version="1.0" distName="A-1/B-1/C-1/D-2" operation="delete">
<p name="Active">1</p>
<p name="Type">CPU</p>
<p name="StDate">2013-07-27T00:00:00+00:00</p>
<p name="StpDate">2013-07-29T00:00:00+00:00</p>
</obj><obj class="D" version="1.0" distName="A-1/B-1/C-1/D-2" operation="create">
<p name="Active">1</p>
<p name="Type">CPU</p>
<p name="StDate">2013-07-27T00:00:00+00:00</p>
<p name="StpDate">2013-07-29T00:00:00+00:00</p>
</obj>
<obj class="E" version="1.0" distName="A-1/B-1/C-1/D-2/E-1" operation="delete">
<p name="dayOfWeek">0</p>
<p name="interval">10</p>
</obj><obj class="E" version="1.0" distName="A-1/B-1/C-1/D-2/E-1" operation="create">
<p name="dayOfWeek">0</p>
<p name="interval">10</p>
</obj>
</Data>
</Object>
I may be missing something in your requirements, but if not, then an update is simply a delete and a create and can be done in a single template. I focused my solution on the action, not on the class. I think my stylesheet produces exactly what you asked to be produced, but it may not be doing what you want. I hope it helps.
t:\ftemp>type objects.xml
<?xml version="1.0" encoding="UTF-8"?>
<Object>
<Data type="plan" name="testAom" id="10">
<obj class="D" version="1.0" distName="A-1/B-1/C-1/D-1" operation="create" >
<p name="Active">1</p>
<p name="Type">CPU</p>
<p name="StDate">2013-07-27T00:00:00+00:00</p>
<p name="StpDate">2013-07-29T00:00:00+00:00</p>
</obj>
<obj class="E" version="1.0" distName="A-1/B-1/C-1/D-1/E-1" operation="create">
<p name="dayOfWeek">0</p>
<p name="interval">10</p>
</obj>
<obj class="E" version="1.0" distName="A-1/B-1/C-1/D-2/E-1" operation="update">
<p name="dayOfWeek">0</p>
<p name="interval">10</p>
</obj>
<obj class="D" version="1.0" distName="A-1/B-1/C-1/D-2" operation="update">
<p name="Active">1</p>
<p name="Type">CPU</p>
<p name="StDate">2013-07-27T00:00:00+00:00</p>
<p name="StpDate">2013-07-29T00:00:00+00:00</p>
</obj>
</Data>
</Object>
t:\ftemp>call xslt objects.xml objects.xsl
<?xml version="1.0" encoding="utf-8"?>
<Object>
<Data type="plan" name="testAom" id="10">
<obj class="D" version="1.0" distName="A-1/B-1/C-1/D-1" operation="New_create">
<p name="Active">1</p>
<p name="Type">CPU</p>
<p name="StDate">2013-07-27T00:00:00+00:00</p>
<p name="StpDate">2013-07-29T00:00:00+00:00</p>
</obj>
<obj class="E" version="1.0" distName="A-1/B-1/C-1/D-1/E-1" operation="New_create">
<p name="dayOfWeek">0</p>
<p name="interval">10</p>
</obj>
<obj class="D" version="1.0" distName="A-1/B-1/C-1/D-2" operation="delete">
<p name="Active">1</p>
<p name="Type">CPU</p>
<p name="StDate">2013-07-27T00:00:00+00:00</p>
<p name="StpDate">2013-07-29T00:00:00+00:00</p>
</obj>
<obj class="D" version="1.0" distName="A-1/B-1/C-1/D-2" operation="create">
<p name="Active">1</p>
<p name="Type">CPU</p>
<p name="StDate">2013-07-27T00:00:00+00:00</p>
<p name="StpDate">2013-07-29T00:00:00+00:00</p>
</obj>
<obj class="E" version="1.0" distName="A-1/B-1/C-1/D-2/E-1" operation="delete">
<p name="dayOfWeek">0</p>
<p name="interval">10</p>
</obj>
<obj class="E" version="1.0" distName="A-1/B-1/C-1/D-2/E-1" operation="create">
<p name="dayOfWeek">0</p>
<p name="interval">10</p>
</obj>
</Data>
</Object>
t:\ftemp>type objects.xsl
<?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"/>
<xsl:template match="Object/Data">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<!--results are in distName order-->
<xsl:apply-templates select="obj">
<xsl:sort select="#distName"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<!--for creation, only the attribute changes, nothing else-->
<xsl:template match="obj[#operation='create']">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:attribute name="operation">New_create</xsl:attribute>
<xsl:apply-templates select="*"/>
</xsl:copy>
</xsl:template>
<!--remove those marked for deletion-->
<xsl:template match="obj[#operation='delete']"/>
<!--remove and recreate those marked for update-->
<xsl:template match="obj[#operation='update']">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:attribute name="operation">delete</xsl:attribute>
<xsl:apply-templates select="*"/>
</xsl:copy>
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:attribute name="operation">create</xsl:attribute>
<xsl:apply-templates select="*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="#*|node()"><!--identity for all other nodes-->
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
t:\ftemp>rem Done!

XSLT 1.0 grouping childs when followed by a certain node

Input xml:
<entry>
<text>
<p>xyz</p>
<p>xyz</p>
<p>xyz</p>
<p>xyz</p>
<author>abc</author>
<p>xyz</p>
<p>xyz</p>
<p>xyz</p>
<author>abc</author>
</text>
</entry>
I'm using XSLT 1.0.
I would like to select all <p> elements until the next <author> element and group them (together with the next <author> element) under a new <div> element. So expected output look like this:
<entry>
<text>
<div>
<p>xyz</p>
<p>xyz</p>
<p>xyz</p>
<p>xyz</p>
<author>abc</author>
</div>
<div>
<p>xyz</p>
<p>xyz</p>
<p>xyz</p>
<author>abc</author>
</div>
</text>
</entry>
I tried this solution:
<xsl:template match="entry">
<entry>
<text>
<div>
<xsl:apply-templates select="child::node()[not(preceding-sibling::author)]"/>
</div>
</text>
</entry>
</xsl:template>
which works fine for the first group of <p> + <author>, but not for the next group(s).
I would appreciate any help.
You may group all elements before an author (preceding-sibling:* which are not author (name() != 'author') and have the current author as next following author
(generate-id( following-sibling::author[1]) = generate-id(current())):
preceding-sibling::*[ name() != 'author' and
generate-id( following-sibling::author[1]) = generate-id(current()) ]
Try something like this:
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*" />
<xsl:output method="xml" indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text">
<xsl:copy>
<xsl:apply-templates select="author" mode="adddiv"/>
</xsl:copy>
</xsl:template>
<xsl:template match="author" mode="adddiv" >
<!-- preceding siblings not author -->
<xsl:variable name="fs" select="preceding-sibling::*[ name() != 'author' and
generate-id( following-sibling::author[1]
) = generate-id(current()) ]" />
<div >
<xsl:apply-templates select="$fs | ." />
</div>
</xsl:template>
</xsl:stylesheet>
Which will generate the following output:
<entry>
<text>
<div>
<p>xyz</p>
<p>xyz</p>
<p>xyz</p>
<p>xyz</p>
<author>abc</author>
</div>
<div>
<p>xyz</p>
<p>xyz</p>
<p>xyz</p>
<author>abc</author>
</div>
</text>
</entry>

Apply a template between two specific nodes in XSLT

I had a problem in xsl:for-each-group and it was very nicely solved in here. Now I have some other problem. I have like this as input.
<?xml version="1.0" encoding="UTF-8"?>
<body>
<p name ="section">this is section</p>
<p name="h-title" other="main">Introduction</p>
<p name="h1-title " other="other-h1">XSLT and XQuery</p>
<p name="h2-title" other=" other-h2">XSLT</p>
<p name="">
<p1 name="bold"> XSLT is used to write stylesheets.</p1>
</p>
<p name="h2-title " name="other-h2">XQuery</p>
<p name="">
<p1 name="bold"> XQuery is used to query XML databases.</p1>
</p>
<p name="h3-title" name="other-h3">XQuery and stylesheets</p>
<p name="">
<p1 name="bold"> XQuery is used to query XML databases.</p1>
</p>
<p name ="section">this is section</p>
<p name="h1-title " other="other-h1">XSLT and XQuery</p>
<p name="h2-title " other=" other-h2">XSLT</p>
<p name ="section">this is section</section>
<p name="h1-title " other="other-h1">XSLT and XQuery</p>
<p name="h2-title " other=" other-h2">XSLT</p>
</body>
Now my wanted output is this
<?xml version="1.0" encoding="UTF-8"?>
<body>
<p name="h-title " other="main">Introduction</p>
<section>
<p name ="section">this is section</p>
<h1>
<p name="h1-title " other="other-h1"> XSLT and XQuery </p>
<h2>
<p name="h2-title " other="other-h2">XSLT</p>
<p name="">
<p1 name="bold">XSLT is used to write stylesheets.
</p1>
</p>
</h2>
<h2>
<p name="h2-title " other="other-h2"> XQuery is used to query XMLdatabases
</p>
<p name="">
<p name="bold"> XQuery is used to query XML databases.</p>
</p>
<h3>
<p name="h3-title " name="other-h3">XQuery and stylesheets</p>
<p name="">
<p1 name="bold"> XQuery is used to query XML databases.</p1>
</p>
</h3>
</h2>
</h1>
</section>
<section>
<p name ="section">this is section</p>
<h1>
<p name="h1-title " other="other-h1">XSLT and XQuery</p>
<h2>
<p name="h2"-title other=" other-h2">XSLT</p>
</h2>
</h1>
</section>
<section>
<p name ="section">this is section</p>
<h1>
<p name="h1-title " other="other-h1">XSLT and XQuery</p>
<h2>
<p name="h2"-title other=" other-h2">XSLT</p>
</h2>
</h1>
</section>
</body>
My used stylesheet(not working properly)
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="xs mf">
<xsl:param name="prefix" as="xs:string" select="'h'"/>
<xsl:param name="suffix" as="xs:string" select="'-title'"/>
<xsl:output method="html" version="4.0" indent="yes"/>
<xsl:function name="mf:group" as="node()*">
<xsl:param name="items" as="node()*"/>
<xsl:param name="level" as="xs:integer"/>
<xsl:for-each-group select="$items" group-starting-with="p[#name = concat($prefix,$level, $suffix)]">
<xsl:choose>
<xsl:when test="not(self::p[#name = concat($prefix, $level, $suffix)])">
<xsl:apply-templates select="current-group()"/>
</xsl:when>
<xsl:otherwise>
<xsl:element name="h{$level}">
<xsl:apply-templates select="."/>
<xsl:sequence select="mf:group(current-group() except ., $level + 1)"/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:function>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* , node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="body" name ="myTemplate">
<xsl:copy>
<xsl:sequence select="mf:group(*, 1)"/>
</xsl:copy>
</xsl:template>
<xsl:template match="body[#name='section']">
<section>
<xsl:call-template name="myTemplate"/>
</section>
</xsl:template>
</xsl:stylesheet>
But this is not correct. Things like <p name ="section">this is section</p> appear widely. not only that, there are few others like this. If someone please show me how to handle with section I will be able to do that for others too. Please tell me how to do this correctly.
ADDED
<body>
<intro>
<p></p>
<p></p>
</intro>
<section>
<para>
</para>
<h1></h2>
<h2></h2>
</section>
<section>
<para>
</para>
<h1></h2>
<h2></h2>
</section>
<sumary>
</summary>
</body>
what I did
<xsl:for-each-group select="*" group-starting-with="p[#name = 'intro']">
<intro>
<xsl:apply-templates select="current()"/>
</intro>
</xsl:for-each-group>
I think you mainly want another grouping step; the stylesheet
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="xs mf">
<xsl:param name="prefix" as="xs:string" select="'h'"/>
<xsl:param name="suffix" as="xs:string" select="'-title'"/>
<xsl:output method="html" version="4.0" indent="yes"/>
<xsl:function name="mf:group" as="node()*">
<xsl:param name="items" as="node()*"/>
<xsl:param name="level" as="xs:integer"/>
<xsl:for-each-group select="$items" group-starting-with="p[#name = concat($prefix, $level, $suffix)]">
<xsl:choose>
<xsl:when test="not(self::p[#name = concat($prefix, $level, $suffix)])">
<xsl:apply-templates select="current-group()"/>
</xsl:when>
<xsl:otherwise>
<xsl:element name="h{$level}">
<xsl:apply-templates select="."/>
<xsl:sequence select="mf:group(current-group() except ., $level + 1)"/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:function>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* , node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="body">
<xsl:copy>
<xsl:for-each-group select="*" group-starting-with="p[#name = 'section']">
<section>
<xsl:sequence select="mf:group(current-group(), 1)"/>
</section>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
transforms the corrected input
<?xml version="1.0" encoding="UTF-8"?>
<body>
<p name ="section">this is section</p>
<p name="h-title" other="main">Introduction</p>
<p name="h1-title" other="other-h1">XSLT and XQuery</p>
<p name="h2-title" other=" other-h2">XSLT</p>
<p name="">
<p1 name="bold"> XSLT is used to write stylesheets.</p1>
</p>
<p name="h2-title" other="other-h2">XQuery</p>
<p name="">
<p1 name="bold"> XQuery is used to query XML databases.</p1>
</p>
<p name="h3-title" other="other-h3">XQuery and stylesheets</p>
<p name="">
<p1 name="bold"> XQuery is used to query XML databases.</p1>
</p>
<p name ="section">this is section</p>
<p name="h1-title" other="other-h1">XSLT and XQuery</p>
<p name="h2-title" other=" other-h2">XSLT</p>
<p name ="section">this is section</p>
<p name="h1-title" other="other-h1">XSLT and XQuery</p>
<p name="h2-title" other=" other-h2">XSLT</p>
</body>
into the result
<body>
<section>
<p name="section">this is section</p>
<p name="h-title" other="main">Introduction</p>
<h1>
<p name="h1-title" other="other-h1">XSLT and XQuery</p>
<h2>
<p name="h2-title" other=" other-h2">XSLT</p>
<p name="">
<p1 name="bold"> XSLT is used to write stylesheets.</p1>
</p>
</h2>
<h2>
<p name="h2-title" other="other-h2">XQuery</p>
<p name="">
<p1 name="bold"> XQuery is used to query XML databases.</p1>
</p>
<h3>
<p name="h3-title" other="other-h3">XQuery and stylesheets</p>
<p name="">
<p1 name="bold"> XQuery is used to query XML databases.</p1>
</p>
</h3>
</h2>
</h1>
</section>
<section>
<p name="section">this is section</p>
<h1>
<p name="h1-title" other="other-h1">XSLT and XQuery</p>
<h2>
<p name="h2-title" other=" other-h2">XSLT</p>
</h2>
</h1>
</section>
<section>
<p name="section">this is section</p>
<h1>
<p name="h1-title" other="other-h1">XSLT and XQuery</p>
<h2>
<p name="h2-title" other=" other-h2">XSLT</p>
</h2>
</h1>
</section>
</body>
That has the structure you posted I think, with the exception of the <p name="h-title" other="main">Introduction</p> element being inside a section while your posted example moved it to the top. I am not sure what are the rules for doing that so I have not tried to implement that. Please clarify whether you simply want to move that single element to the top and not apply the grouping to it or whether there are more complex rules to exempt certain elements.
[edit]In case you simply want to move all p[#name = 't-title'] to the top and not group them then the following adaption of above stylesheet should do the job:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="xs mf">
<xsl:param name="prefix" as="xs:string" select="'h'"/>
<xsl:param name="suffix" as="xs:string" select="'-title'"/>
<xsl:output method="html" version="4.0" indent="yes"/>
<xsl:function name="mf:group" as="node()*">
<xsl:param name="items" as="node()*"/>
<xsl:param name="level" as="xs:integer"/>
<xsl:for-each-group select="$items" group-starting-with="p[#name = concat($prefix, $level, $suffix)]">
<xsl:choose>
<xsl:when test="not(self::p[#name = concat($prefix, $level, $suffix)])">
<xsl:apply-templates select="current-group()"/>
</xsl:when>
<xsl:otherwise>
<xsl:element name="h{$level}">
<xsl:apply-templates select="."/>
<xsl:sequence select="mf:group(current-group() except ., $level + 1)"/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:function>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* , node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="body">
<xsl:copy>
<xsl:apply-templates select="p[#name = 'h-title']"/>
<xsl:for-each-group select="* except p[#name = 'h-title']" group-starting-with="p[#name = 'section']">
<section>
<xsl:sequence select="mf:group(current-group(), 1)"/>
</section>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>