Wednesday 12 September 2018

Convert simple XML structure to Nested Structure

Input:-
<body>
    <p class="title">Article Title</p>
    <p class="Authors">abc, pqr and xyz</p>
    <p class="intro">here is introdution text......</p>        
    <p class="head1">1: Heading level 1</p>
    <p>some text here</p>
    <p>some text here</p>
    <p class="head2">1.1: Heading  level 2</p>
    <p>some text here</p>
    <p>some text here</p>        
    <p class="head3">1.1.1: Heading  level 3</p>
    <p>some text here</p>
    <p>some text here</p>        
    <p class="head1">2: Heading level 1</p>
    <p class="head2">2.1: Heading  level 2</p>
    <p>some text here</p>
    <p>some text here</p>        
    <p class="head3">2.1.1: Heading  level 3</p>
    <p>some text here</p>
    <p>some text here</p>        
    <p class="head3">2.1.2: Heading  level 3</p>
    <p>some text here</p>
    <p>some text here</p>        
</body>
Expected Output:
<?xml version="1.0" encoding="UTF-8"?> <body>    <section name="head1">       <title>1: Heading level 1</title>       <paras>          <p>some text here</p>          <p>some text here</p>       </paras>       <section name="head2">          <title>1.1: Heading  level 2</title>          <paras>             <p>some text here</p>             <p>some text here</p>          </paras>          <section name="head3">             <title>1.1.1: Heading  level 3</title>             <paras>                <p>some text here</p>                <p>some text here</p>             </paras>          </section>       </section>    </section>    <section name="head1">       <title>2: Heading level 1</title>       <section name="head2">          <title>2.1: Heading  level 2</title>          <paras>             <p>some text here</p>             <p>some text here</p>          </paras>          <section name="head3">             <title>2.1.1: Heading  level 3</title>             <paras>                <p>some text here</p>                <p>some text here</p>             </paras>          </section>          <section name="head3">             <title>2.1.2: Heading  level 3</title>             <paras>                <p>some text here</p>                <p>some text here</p>             </paras>          </section>       </section>    </section> </body>
XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"     xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:vish="http://www.marklogicgd.blogspot.in/vish"     exclude-result-prefixes="xs vish" version="2.0">         <xsl:output indent="yes"/>         <xsl:template match="node()|@*">         <xsl:copy>             <xsl:apply-templates/>         </xsl:copy>     </xsl:template>         <xsl:function name="vish:group" as="element(section)*">         <xsl:param name="entries" as="element(p)*"/>         <xsl:param name="level" as="xs:integer"/>         <xsl:for-each-group select="$entries"             group-starting-with="p[@class = concat('head',$level)]">             <xsl:variable name="P_ID" select="generate-id(.)"/>             <section name="{@class}">                 <title>                     <xsl:value-of select="."/>                 </title>                 <xsl:if test="following-sibling::p[1][not(@class)]">                     <paras>                         <xsl:apply-templates                             select="following-sibling::p[not(@class)][generate-id(preceding-sibling::p[@class][1]) = $P_ID]"                         />                     </paras>                 </xsl:if>                                 <xsl:sequence select="vish:group(current-group() except ., ($level + 1))"/>             </section>         </xsl:for-each-group>     </xsl:function>         <xsl:template match="body">         <xsl:copy>             <xsl:sequence select="vish:group(p[contains(@class,'head')], 1)"/>         </xsl:copy>     </xsl:template> </xsl:stylesheet>