RE: [xsl] Processing Recursive Groups

Subject: RE: [xsl] Processing Recursive Groups
From: "Michael Kay" <mike@xxxxxxxxxxxx>
Date: Wed, 25 Jul 2007 23:00:09 +0100
Some good news: there are a couple of examples in my book of code that
checks for cycles. The bad news is that they have bugs.

Testing whether a group refers directly to itself isn't good enough, you
need to test for cycles such as A referring to B and B referring to A. You
can't do this with a simple check on the ancestor axis, even if you get the
brackets right. Basically, when your template calls itself recursively, it
has to pass a parameter containing the name of the referencing group; on
each recursive call you need to append another name to the list supplied
when you were called, and then to check for cycles you need to check that
your own name is not anywhere on the list of callers.

Michael Kay
http://www.saxonica.com/

> -----Original Message-----
> From: Wasiq Shaikh [mailto:wasiq911@xxxxxxxxxxx]
> Sent: 25 July 2007 20:32
> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> Subject: [xsl] Processing Recursive Groups
>
> Hi,
>
> I'm trying to process groups within groups. Basically, if an
> XSD element refers to a group with <xsd:group ref="X"/> , I
> would like to expand this to include the actual group (rather
> than a reference to it).
>
> Im able to do this without any problem, however, there's a
> snag (as always).
> I have some group declarations that contain references to
> itself. My basic script obviously will give a stack overflow
> as it keeps substituting the same group over and over again.
>
> <xsd:group name="X">
>    ...
>    <xsd:group ref="X"/> <!-- KEEPS SUBSTITUTING = NO GOOD!
> --> </xsd:group>
>
> So my script starts off like this:
>
> <xsl:key name="allGroups" match="xsd:group[string(@name)]"
> use="@name"/>
>
> When it comes time to process group references within
> elements I have something like this to take care of the recursion:
>
>       ...
>       <xsl:for-each select="xsd:group">
>          <xsl:if test="string(@ref)">
>             <xsl:choose>
>                <xsl:when
> test="not[ancestor::xsd:group[@name=current()/@ref]]">
>                   <xsl:for-each
> select="key('allGroups',string(@ref))">
>                      <xsl:apply-templates select="*"/>
>                   </xsl:for-each>
>                </xsl:when>
>                <xsl:otherwise>
>                   <xsl:element name="group">
>                      <xsl:attribute name="ref">
>                         <xsl:value-of select="@ref"/>
>                      </xsl:attribute>
>                   </xsl:element>
>                </xsl:otherwise>
>             </xsl:choose>
>          </xsl:if>
>       </xsl:for-each>
>       ....
>
> BUT, this doesn't work. I'm pretty sure the "when" statement
> isn't doing it's job properly. For example, if you come
> across a group reference in an
> element:
>
> <xsd:element name="blah">
>    <xsd:group ref="X"/>
> </xsd:element>
>
> And a group defined with a reference to itself:
>
> <xsd:group name="X">
>    <xsd:element name="a">
>       <xsd:group ref="X"/>
>    </xsd:element>
>    <xsd:group ref="Y/>
> </xsd:group>
>
> <xsd:group name="Y">
>    <xsd:element name="b"/>
> </xsd:group>
>
> The end result should look like:
>
> <element name="blah">
>    <element name="a">
>       <group ref="X"/>
>    </element>
>    <element name="b"/>
> </element>
>
> Shouldn't my script substitute group X in the element, and
> not substitute itself when it sees that its ancestor is
> itself, and continue substituting group Y (in group X) ??
>
> I hope this makes sense. If there is a technique out there
> that can take care of this then I can aslo apply that
> technique to complexTypes that define elements refering to
> the same complexType.
>
> Thanks for any help. Greatly appreciate it!
>
> Wasiq Shaikh
>
> _________________________________________________________________
> Windows Live Hotmail is the next generation of MSN Hotmail. 
> Its fast, simple, and safer than ever and best of all  its
> still free. Try it today!
> www.newhotmail.ca?icid=WLHMENCA146

Current Thread