[XQuery Talk Mailing List Archive Home] [By Date] [By Thread] [By Subject] [By Author] [Recent Entries] [Reply To This Message]

Re: XQuery issue regarding creating table of contents(TOC) dynamically.

G. Ken Holman gkholman at CraneSoftwrights.com
Thu Jan 7 09:06:34 PST 2010


  Re: XQuery issue regarding creating table of
 contents(TOC) dynamically.
At 2010-01-07 11:28 +0530, anuj kumar wrote:
>I have an xml of the form
>...
>A change in the designator(Designators may be in alpha, numeric, 
>roman, alpha-numeric,
>etc bounded or unbounded by brackets) format must be used as basis 
>for identifying the primary level.

I've implemented this so you can use regular expressions to determine 
the level indications.

>Designators in sequence or series must be treated as primary level 
>text of the same level. For example:
>(a)-first level
>(b)-first level
>(c)-first level
>
>I have to create the following output xml out of the above input xml:
>...
>Pleae advise, how to do this?

You don't share with us what you have tried and what has not worked for you.

I have a complete solution below.  I found it easier to think first 
in XSLT because of the grouping facilities that are available, and 
then to just transliterate that into XQuery for a pure-XQuery solution.

Note that readers may find it interesting to have to do the following 
in XQuery:

   (<tree>{elements-expression}</tree>)/*

... in order to create a sibling relationship between a copy of nodes 
so that the recursive use of the following-sibling axis would not 
access the original nodes.  Simply referencing the nodes isn't 
sufficient because the nodes retain their original location in the 
original tree.

I hope this helps.

. . . . . . . . . . . . Ken


T:\ftemp>type anuj.xml
<doc>
   <p>(a)- first level </p>
   <p>(1)- second level</p>
   <p>(2)- second level</p>
   <p>(A)- third level</p>
   <p>(B)- third level</p>
   <p>(3)- second level</p>
   <p>(b)- first level</p>
</doc>
T:\ftemp>call xslt2 anuj.xml anuj.xsl
<?xml version="1.0" encoding="UTF-8"?>
<doc>
    <parent>
       <title>(a)- first level </title>
       <child>
          <title>(1)- second level</title>
       </child>
       <child>
          <title>(2)- second level</title>
          <child>
             <title>(A)- third level</title>
          </child>
          <child>
             <title>(B)- third level</title>
          </child>
       </child>
       <child>
          <title>(3)- second level</title>
       </child>
    </parent>
    <parent>
       <title>(b)- first level</title>
    </parent>
</doc>
T:\ftemp>call xquery anuj.xq
<?xml version="1.0" encoding="UTF-8"?>
<doc>
    <parent>
       <title>(a)- first level </title>
       <child>
          <title>(1)- second level</title>
       </child>
       <child>
          <title>(2)- second level</title>
          <child>
             <title>(A)- third level</title>
          </child>
          <child>
             <title>(B)- third level</title>
          </child>
       </child>
       <child>
          <title>(3)- second level</title>
       </child>
    </parent>
    <parent>
       <title>(b)- first level</title>
    </parent>
</doc>
T:\ftemp>type anuj.xsl
<?xml version="1.0" encoding="US-ASCII"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                 version="2.0">

<xsl:output indent="yes"/>

<xsl:variable name="patterns" as="element(patterns)">
   <patterns>
     <pattern>^\([a-z]\)</pattern>
     <pattern>^\([\d+]\)</pattern>
     <pattern>^\([A-Z]\)</pattern>
   </patterns>
</xsl:variable>

<xsl:template match="doc">
   <doc>
     <xsl:call-template name="parent">
       <xsl:with-param name="population" select="p"/>
       <xsl:with-param name="pattern" select="$patterns/pattern[1]"/>
       <xsl:with-param name="relationship" select="'parent'"/>
     </xsl:call-template>
   </doc>
</xsl:template>

<xsl:template name="parent">
   <xsl:param name="population"/>
   <xsl:param name="pattern"/>
   <xsl:param name="relationship"/>
   <xsl:if test="$population">
     <!--only do something if there is something to do-->
     <xsl:choose>
       <xsl:when test="not($pattern)">
         <!--no more depth-->
         <xsl:for-each select="$population">
           <xsl:element name="{$relationship}">
             <title><xsl:copy-of select="node()"/></title>
           </xsl:element>
         </xsl:for-each>
       </xsl:when>
       <xsl:otherwise>
         <!--process next level of depth-->
         <xsl:for-each-group select="$population"
                             group-starting-with="*[matches(.,$pattern)]">
           <xsl:element name="{$relationship}">
             <title><xsl:copy-of select="node()"/></title>
             <xsl:call-template name="parent">
               <xsl:with-param name="population"
                               select="current-group()[position()>1]"/>
               <xsl:with-param name="pattern"
                               select="$pattern/following-sibling::*[1]"/>
               <xsl:with-param name="relationship" select="'child'"/>
             </xsl:call-template>
           </xsl:element>
         </xsl:for-each-group>
       </xsl:otherwise>
     </xsl:choose>
   </xsl:if>
</xsl:template>

</xsl:stylesheet>

T:\ftemp>type anuj.xq
declare namespace a = "urn:X-anuj";

declare variable $patterns as element(patterns) :=
   <patterns>
     <pattern>^\([a-z]\)</pattern>
     <pattern>^\([\d+]\)</pattern>
     <pattern>^\([A-Z]\)</pattern>
   </patterns>;

declare function a:parent( $population, $pattern, $relationship )
{
   if( $population )
   then
     (: only do something if there is something to do :)
     if( not($pattern) )
     then
       (: no more depth :)
       for $each in $population return
         element {$relationship} {<title>{$each/node()}</title>}
     else
       (: process next level of depth :)
       for $level in $population[matches(.,$pattern)]
       return
         element {$relationship}
         {
           <title>{$level/node()}</title>,
           a:parent( (<tree>
                       {$level/following-sibling::* except
                        $level/following-sibling::*[matches(.,$pattern)][1]/
                                               (self::* | 
following-sibling::* )
                       }
                      </tree>)/* (:create a new tree of children:),
                      $pattern/following-sibling::*[1] (:the next pattern:),
                      'child' )
         }
   else ()
};

<doc>{a:parent( doc('anuj.xml')/doc/p, $patterns/pattern[1], 'parent' )}</doc>


T:\ftemp>rem Done!


--
UBL and Code List training:      Copenhagen, Denmark 2010-02-08/10
XSLT/XQuery/XPath training after http://XMLPrague.cz 2010-03-15/19
XSLT/XQuery/XPath training:   San Carlos, California 2010-04-26/30
Vote for your XML training:   http://www.CraneSoftwrights.com/q/i/
Crane Softwrights Ltd.          http://www.CraneSoftwrights.com/q/
Training tools: Comprehensive interactive XSLT/XPath 1.0/2.0 video
Video lesson:    http://www.youtube.com/watch?v=PrNjJCh7Ppg&fmt=18
Video overview:  http://www.youtube.com/watch?v=VTiodiij6gE&fmt=18
G. Ken Holman                 mailto:http://x-query.com/mailman/listinfo/talk
Male Cancer Awareness Nov'07  http://www.CraneSoftwrights.com/q/bc
Legal business disclaimers:  http://www.CraneSoftwrights.com/legal



PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2011 All Rights Reserved.