RE: [xsl] FW: Stopping recursion

Subject: RE: [xsl] FW: Stopping recursion
From: "Michael Kay" <mike@xxxxxxxxxxxx>
Date: Tue, 22 Nov 2005 11:21:07 -0000
There are a few problems with this stylesheet - for example I don't think it
handles a no-namespace schema, or model groups, or types derived by
extension, or perhaps quite a few other things. I'm also not sure whether
the test test=".//@namespace='http://www.w3.org/1999/xlink'" is doing the
right thing: this seems designed to catch element and attribute wildcards,
but I would have thought you also wanted to catch XLink attributes declared
explicitly.

However, to stick to the question you are asking: I think you need to
separate the functionality into two parts: a template that determines
whether an element directly-or-indirectly allows XLink attributes, and a
template that adds an xml:base attribute. The logic should be "if this
element declaration directly-or-indirectly allows XLink attributes, then add
an xml:base attribute", where the logic for testing each element declaration
returns a yes/no result but does not produce a modified element declaration
as output.

This logic will visit the same element many times, which of course has
performance implications. An easy but non-standard answer to that is Saxon
memo functions. A more portable answer is to pass parameters on your
recursive calls indicating the elements already visited: perhaps two lists,
one for those known to allow XLink attributes, another for those known not
to.

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


> -----Original Message-----
> From: Mark Seaborne [mailto:mseaborne@xxxxxxxxxxxxxxxxx] 
> Sent: 22 November 2005 11:00
> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> Subject: [xsl] FW: Stopping recursion
> 
> Hi,
> 
> I have a 1.0 stylesheet that takes a WXS schema and adds 
> xml:base to certain
> complex type definitions. The rule for inclusion of the 
> attribute is that
> the complex type must either include directly, or have a descendent in
> another complex type that includes the XLink namespace.
> 
> So the stylesheet recurses through each complex type and 
> tests to see if
> they contain anything belonging to the XLink namespace. If the type is
> itself a complex type the template is called again to check 
> to see if that
> one has any elements within the XLink namespace, and so on. 
> If the XLink
> namespace is found then <xsd:attribute ref="xml:base"/> is output.
> 
> My problem is that once the XLink namespace is found I would like the
> recursion to stop, mainly because if the namespace is found 
> in more than one
> descendent element/attribute declaration the attribute is 
> added multiple
> times. 
> 
> I suspect that either my approach is totally wrong, or this 
> is a common
> enough problem that there is a design pattern I can use to achieve the
> effect I want, but I haven't hit on the key words to find it. So any
> pointers would be gratefully received.
> 
> This is the template causing the problem:
> 
> <xsl:template match="xsd:element" mode="findXLink">
>    <xsl:choose>
>    <!-- if the element is declared locally (has a type attribute_ -->
>       <xsl:when test="@type">
>         <!-- remove the namespace prefix from the qname -->
>         <xsl:variable name="myType" 
> select="substring-after(@type, ':')"/>
>         <xsl:for-each 
> select="/xsd:schema/xsd:complexType[@name = $myType]">
>         <xsl:choose>
>         <!-- if the complex type definition includes anything 
> in the XLink
> namespace output the xml:base attribute -->
>           <xsl:when 
> test=".//@namespace='http://www.w3.org/1999/xlink'">
>             <xsd:attribute ref="xml:base"/>
>           </xsl:when>
>        <!-- otherwise apply this template to all of the 
> elements declared
> within the complex type -->
>           <xsl:otherwise>
>              <xsl:apply-templates select=".//xsd:element" 
> mode="findXLink"/>
>           </xsl:otherwise>
>         </xsl:choose>
>       </xsl:for-each>
>     </xsl:when>
>     <!-- otherwise assume that the element references a 
> globally declared
> element, so look for that -->
>     <xsl:otherwise>
>       <xsl:variable name="myName" 
> select="substring-after(@ref, ':')"/>
>       <xsl:apply-templates select="//xsd:element[@name = $myName]"
> mode="findXLink"/>
>      </xsl:otherwise>
>    </xsl:choose>
> </xsl:template>
> 
> All the best
> 
> Mark
> The information in this e-mail is sent in confidence for the 
> addressee only and may be legally privileged. Unauthorised 
> recipients must preserve this confidentiality and should 
> please advise the sender immediately of the error in 
> transmission and then delete this e-mail. If you are not the 
> intended recipient, any disclosure, copying, distribution or 
> any action taken in reliance on its content is prohibited and 
> may be unlawful.
> 
> Origo Services Limited accepts no responsibility for any loss 
> or damage resulting directly or indirectly from the use of 
> this e-mail or the contents.  It is your responsibility to 
> scan for viruses.  Origo Services Limited reserves the right 
> to monitor e-mails sent to or from addresses under its 
> control.  When you reply to this e-mail, you are consenting 
> to Origo Services Limited monitoring the content of the 
> e-mails you send to or receive from Origo Services Limited.  
> If this e-mail is non-business related Origo Services Limited 
> is not liable for any opinions expressed by the sender.  The 
> contents of this e-mail are protected by copyright.  All 
> rights reserved.
> 
> 
> 
> Origo Services Limited is a company incorporated in Scotland 
> (company number 115061) having its registered office at 4th 
> floor, Saltire Court, 20 Castle Terrace, Edinburgh EH1 2EN.

Current Thread