xsl-list
[Top] [All Lists]

RE: [xsl] Processing Recursive Groups

2007-07-26 05:42:33
That's interesting Michael. I never thought of that scenario. But I feel kind of dumb using the wrong brackets!! (i guess it happens to us all, once in a while).

I apologize to David for not including more code information. I'm fairly new to the list and I just figured nobody wanted to see the rest of the XSLT, only the problem parts. My XSLT is fairly long so here's some more good stuff.

The input file is an XSD. I cannot post the input file as it is against company policy. But viewing my input shouldn't really make a difference since an XSD is highly structured and does not have any room for customization. The script should work with any XSD. I use XalanJ 2.7/XPath 1.0.

By the way, I fixed my stupid mistake with the brackets and it worked the way I originally intended (but it doesn't handle what Mike stated). And from my previous thread about generating custom ID's from parent nodes, I was able to find the exact solution using Jeni's code snippet here:

http://www.biglist.com/lists/xsl-list/archives/200107/msg01783.html

  <!-- Declare indexes for different sections of the schema -->
<xsl:key name="allTopElements" match="/*/xsd:element" use="concat(@name,' ',@type,' ',@ref)"/> <xsl:key name="allTypes" match="xsd:simpleType[string(@name)] | xsd:complexType[string(@name)]" use="@name"/>
  <xsl:key name="allGroups" match="xsd:group[string(@name)]" use="@name"/>
<xsl:key name="allAttributeGroups" match="xsd:attributeGroup[string(@name)]" use="@name"/>

  <!-- Begin processing from root -->
  <xsl:template match="/">
     <xsl:element name="Metadata">
        <xsl:element name="Elements">
           <xsl:for-each select="/*/xsd:element">
              <xsl:sort select="@name"/>
              <xsl:apply-templates select="."/>
           </xsl:for-each>
        </xsl:element>
     </xsl:element>
  </xsl:template>

  <!-- Process an element if encounted -->
  <xsl:template match="xsd:element[string(@name) or string(@ref)]">
     <xsl:call-template name="processElement"/>
  </xsl:template>

  <!-- Continue processing after encountering sequences and choices -->
  <xsl:template match="xsd:all | xsd:sequence | xsd:choice">
     <xsl:apply-templates select="*"/>
  </xsl:template>

  <xsl:template match="node() | @*"/>

  <!-- Process and format elements -->
  <xsl:template name="processElement">
     <xsl:element name="element">
        <xsl:if test="@name">
           <xsl:attribute name="name">
              <xsl:value-of select="@name"/>
           </xsl:attribute>
        </xsl:if>
        <xsl:if test="string(@type)">
           <xsl:attribute name="type">
              <xsl:value-of select="@type"/>
           </xsl:attribute>
        </xsl:if>
        <xsl:if test="string(@ref)">
           <xsl:attribute name="ref">
              <xsl:value-of select="@ref"/>
           </xsl:attribute>
        </xsl:if>
        <!-- Process anonymous type definitions, if any -->
        <xsl:for-each select="xsd:simpleType | xsd:complexType">
           <xsl:call-template name="processType"/>
        </xsl:for-each>
     </xsl:element>
  </xsl:template>

<!-- Process both anonymous and declared type definitions, and handle extensions -->
  <xsl:template name="processType">
     <xsl:variable name="extension" select="*/xsd:extension"/>
     <xsl:for-each select="$extension">
        <xsl:attribute name="type">
           <xsl:value-of select="@base"/>
        </xsl:attribute>
        <xsl:attribute name="extended">true</xsl:attribute>
        <xsl:if test="node()">
           <xsl:element name="extended">
              <xsl:call-template name="processAllChildren"/>
           </xsl:element>
        </xsl:if>
     </xsl:for-each>
     <xsl:call-template name="processAllChildren"/>
  </xsl:template>

  <!-- Process all children under any element, type, or group -->
  <xsl:template name="processAllChildren">
     <xsl:call-template name="processAttributes"/>
     <xsl:for-each select="xsd:attributeGroup">
        <xsl:if test="string(@ref)">
           <xsl:for-each select="key('allAttributeGroups',string(@ref))">
              <xsl:call-template name="processAttributes"/>
           </xsl:for-each>
        </xsl:if>
     </xsl:for-each>
     <xsl:for-each select="xsd:group">
        <xsl:if test="string(@ref)">
           <xsl:choose>
<xsl:when test="not(ancestor::xsd:group[(_at_)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>
     <xsl:apply-templates select="*"/>
  </xsl:template>

  <!-- Process all attributes and parse comments -->
  <xsl:template name="processAttributes">
<!-- This is some attribute processing which is kind of long but efficient, necessary, and simple -->
      <xsl:call-template name="processComments"/>
  </xsl:template>

  <!-- Parses comments -->
  <xsl:template name="processComments">
<!-- This section parses comments in the actual <!-- comment tags (not annotation tags). It uses a bunch of string processing. Simple, long, yet efficient -->
  </xsl:template>

Wasiq Shaikh


----Original Message Follows----

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/

_________________________________________________________________
Windows Live Hotmail gives you the control you need to help you keep your e-mail private, safe and secure. See for yourself! www.newhotmail.ca?icid=WLHMENCA147


--~------------------------------------------------------------------
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(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--

<Prev in Thread] Current Thread [Next in Thread>