[prev in list] [next in list] [prev in thread] [next in thread] 

List:       xsl-list
Subject:    Re: [xsl] Recursion
From:       "Imsieke, Gerrit, le-tex" <gerrit.imsieke () le-tex ! de>
Date:       2012-05-28 11:38:03
Message-ID: 4FC3639B.3090401 () le-tex ! de
[Download RAW message or body]

In general, keeping book of the files that you have already seen is a 
good idea. But you should use a sequence of file names, or better of 
absolute URIs.

Then it’s advisable to use parameter tunneling, just in case that there 
are intermediate elements between xml1 and includes.

And it is usually a good idea to use XSLT’s template matching / 
apply-templates mechanism instead of for-each/call-template 
(particularly if there’s other content on the same level as 'includes'.

–Gerrit


<xsl:stylesheet
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:xs="http://www.w3.org/2001/XMLSchema"
   version="2.0"
   exclude-result-prefixes="xs"
   >

   <xsl:output method="xml" indent="yes" />

   <!-- If there is other content than xml1 and includes, reproduce it
        with an Identity template:
   <xsl:template match="@* | *">
     <xsl:copy>
       <xsl:apply-templates select="@* | node()" mode="#current"/>
     </xsl:copy>
   </xsl:template>

   <xsl:template match="xml1">
     <!-- Use tunneling (particularly useful when there are intermediate
          elements): -->
     <xsl:param name="seen" as="xs:string*" tunnel="yes"/>
     <xsl:copy>
       <xsl:attribute name="xml:base" select="base-uri(.)" />
       <xsl:apply-templates>
         <xsl:with-param name="seen" select="($seen, base-uri(.))" 
tunnel="yes" />
       </xsl:apply-templates>
     </xsl:copy>
   </xsl:template>

   <!-- Use template matching instead of for-each and call-template: -->
   <xsl:template match="includes" as="element(*)?">
     <xsl:param name="seen" as="xs:string*" tunnel="yes"/>
     <xsl:variable name="file" select="document(.)" 
as="document-node(element(*))" />
     <xsl:choose>
       <xsl:when test="base-uri($file) = $seen">
         <xsl:message>Already seen: <xsl:sequence 
select="base-uri($file)" />
         </xsl:message>
       </xsl:when>
       <xsl:otherwise>
         <xsl:apply-templates select="$file" />
       </xsl:otherwise>
     </xsl:choose>
   </xsl:template>

</xsl:stylesheet>


Sample output (added some bogus content to some files and renamed 
file1.1.1xml to file1.1.1.xml):

$ saxon -xsl:test.xsl main.xml
Already seen: 
file:/C:/cygwin/home/gerrit/XSLT-trivia/mulberry-xsl-list/2012-05-28_vasucv@gmail.com/file1.xml
 <?xml version="1.0" encoding="UTF-8"?>
<xml1 
xml:base="file:/C:/cygwin/home/gerrit/XSLT-trivia/mulberry-xsl-list/2012-05-28_vasucv@gmail.com/main.xml">
  <xml1 
xml:base="file:/C:/cygwin/home/gerrit/XSLT-trivia/mulberry-xsl-list/2012-05-28_vasucv@gmail.com/file1.xml">
  <xml1 
xml:base="file:/C:/cygwin/home/gerrit/XSLT-trivia/mulberry-xsl-list/2012-05-28_vasucv@gmail.com/file1.1.xml">
  <xml1 
xml:base="file:/C:/cygwin/home/gerrit/XSLT-trivia/mulberry-xsl-list/2012-05-28_vasucv@gmail.com/file1.1.1.xml">1.1.1
 </xml1>

       </xml1>
       <xml1 
xml:base="file:/C:/cygwin/home/gerrit/XSLT-trivia/mulberry-xsl-list/2012-05-28_vasucv@gmail.com/file1.2.xml">1.2
 </xml1>
    </xml1>
     <xml1 
xml:base="file:/C:/cygwin/home/gerrit/XSLT-trivia/mulberry-xsl-list/2012-05-28_vasucv@gmail.com/file2.xml">
  <xml1 
xml:base="file:/C:/cygwin/home/gerrit/XSLT-trivia/mulberry-xsl-list/2012-05-28_vasucv@gmail.com/file2.1.xml">2.1
 </xml1>
       <xml1 
xml:base="file:/C:/cygwin/home/gerrit/XSLT-trivia/mulberry-xsl-list/2012-05-28_vasucv@gmail.com/file2.2.xml">2.2
 </xml1>
    </xml1>
</xml1>



On 2012-05-28 12:58, Vasu Chakkera wrote:
> Guys,
> 
> I had this issue, which I solved, but thought someone here could
> probably recreate with some better ideas?? I did not refractor this..
> so , I am sure the code can be refractored or rearranged/ beautified
> .. But I am wanting to see if there is a completely different
> approach...
> 
> 
> The problem is as folllows..
> 
> XSLT is written for an XSD. This XSD may include another XSD and that
> may include more XSDs and so on and so forth,. This can end up
> becoming a huge tree.
> Some where, one of the XSDs can actually refer to another XSD which
> could have been already in the tree. So a normall thought process is
> that your XSLT will fail because it will end up into the infinite
> recursion ( circular reference).. So I wrote this XSLT to process such
> a tree...  I have simulated this one with XMLS with nodes that are
> called<includes>  //
> 
> Main XML :
> =======
> <xml1>
> <includes>file1.xml</includes>
> <includes>file2.xml</includes>
> </xml1>
> 
> file1.xml
> =======
> <xml1>
> <includes>file1.1.xml</includes>
> <includes>file1.2.xml</includes>
> </xml1>
> 
> file2.xml
> =======
> <xml1>
> <includes>file2.1.xml</includes>
> <includes>file2.2.xml</includes>
> </xml1>
> file1.1.xml
> =======
> <xml1>
> <includes>file1.1.1xml</includes>
> <includes>file1.xml
> <!-- this one is bad circular reference -->
> </includes>
> </xml1>
> 
> and so on...
> 
> The XSLT is
> ========
> 
> <?xml version="1.0" encoding="UTF-8"?>
> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
> <xsl:template match="xml1">
> <xsl:call-template name="get-include">
> <xsl:with-param name="init" select="0"/>
> </xsl:call-template>
> </xsl:template>
> <xsl:template name="get-include">
> <xsl:param name="document-name"/>
> <xsl:param name="init"/>
> <xsl:param name="include-tree"/>
> <xsl:choose>
> <xsl:when test="$init = 1">
> <xsl:for-each select="document($document-name)//includes">
> <xsl:variable name="doc-name" select="."/>
> <xsl:value-of select="."/>
> <xsl:choose>
> <xsl:when test="contains($include-tree,$doc-name)">
> <xsl:text>: This file is ignored :
> Circular Reference</xsl:text>
> <xsl:text>&#xa;</xsl:text>
> </xsl:when>
> <xsl:otherwise>
> <xsl:text>,</xsl:text>
> <xsl:call-template name="get-include">
> <xsl:with-param name="document-name"
> select="$doc-name"/>
> <xsl:with-param name="init" select="1"/>
> <xsl:with-param name="include-tree"
> 
> select="concat($include-tree,'/',$doc-name,'/')"/>
> </xsl:call-template>
> </xsl:otherwise>
> </xsl:choose>
> <xsl:text>&#xa;</xsl:text>
> </xsl:for-each>
> </xsl:when>
> <xsl:otherwise>
> <xsl:for-each select="//includes">
> <xsl:text>  &#xa;</xsl:text>
> <xsl:variable name="doc-name" select="."/>
> <xsl:value-of select="."/>
> <xsl:call-template name="get-include">
> <xsl:with-param name="document-name" select="."/>
> <xsl:with-param name="init" select="1"/>
> <xsl:with-param name="include-tree"
> select="concat($include-tree,'/',$doc-name)"/>
> </xsl:call-template>
> </xsl:for-each>
> </xsl:otherwise>
> </xsl:choose>
> </xsl:template>
> 
> </xsl:stylesheet>
> 
> Any Ideas??
> 
> Vasu Chakkera
> 
> --~------------------------------------------------------------------
> XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
> To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
> or e-mail:<mailto:xsl-list-unsubscribe@lists.mulberrytech.com>
> --~--
> 

-- 
Gerrit Imsieke
Geschäftsführer / Managing Director
le-tex publishing services GmbH
Weissenfelser Str. 84, 04229 Leipzig, Germany
Phone +49 341 355356 110, Fax +49 341 355356 510
gerrit.imsieke@le-tex.de, http://www.le-tex.de

Registergericht / Commercial Register: Amtsgericht Leipzig
Registernummer / Registration Number: HRB 24930

Geschäftsführer: Gerrit Imsieke, Svea Jelonek,
Thomas Schmidt, Dr. Reinhard Vöckler

--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe@lists.mulberrytech.com>
--~--


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic