[xsl] SGML Inclusions and infinitive recursion (in XSLT)

Subject: [xsl] SGML Inclusions and infinitive recursion (in XSLT)
From: Don Smith <dsmith_lockesmith@xxxxxxxxx>
Date: Mon, 5 Oct 2009 15:50:58 -0700 (PDT)
Just when you thought you'd never answer another question about SGML inclusions. . .

I'm working with the XML files produced by Norm Walsh's tool DTDParse. These files represent an SGML or XML DTD. In my case, it's SGML DTDs.

I've written a transformation that produces an HTML view of the DTD. It's quite handy, but there's one thing I can't quite get to work and I really need to resolve this issue: inclusions.

Here's a snippet of the kind of output in the XML file I'm working with:

<dtd>

 <element name="HEAD" stagm="O" etagm="O" content-type="element">
  <content-model-expanded>
   <and-group>
    <element-name name="TITLE"/>
    <element-name name="ISINDEX" occurrence="?"/>
    <element-name name="BASE" occurrence="?"/>
   </and-group>
  </content-model-expanded>
  <content-model>
   <sequence-group>
    <parament-name name="head.content"/>
   </sequence-group>
  </content-model>
  <inclusions>
   <or-group>
    <element-name name="SCRIPT"/>
    <element-name name="STYLE"/>
    <element-name name="META"/>
    <element-name name="LINK"/>
    <element-name name="OBJECT"/>
   </or-group>
  </inclusions>
 </element>
 <!-- one such element for every element declared in the DTD -->
</dtd>

What I want to do is produce, for every element, not only what it's declared content model is (in DTDParse's output file, the content of <content-model-expanded>), but also of any inclusions that apply to the element. And that's where the problem is.

If I recall SGML inclusions correctly, an inclusion declared on an element applies to all child elements all the way to the bottom of the relevant part of the document tree.

As I understand it, what I need to do is find the parent element(s) of a given element, and see if they have any inclusions; if so, output them. Then, find the parents of that element (or elements) and do the same. And so on. So far I've only done this using <xsl:for-each> and simply moved from one element to its parent(s) and so on:

<xsl:template name="trace_ancestor_inclusions">
 <xsl:param name="element_name" />
  <!-- this changes the context to each parent element of the original element -->
  <xsl:for-each select="parent::dtd/element[content-model-expanded/descendant::element-name[@name=$element_name]]">
  <xsl:variable name="new_element_name" select="@name" />
    <p style="padding-left: 20px;">Ancestor Element: <xsl:value-of select="$new_element_name"/><xsl:text> </xsl:text>
      <xsl:for-each select="inclusions/*">				
	<xsl:text>( </xsl:text><xsl:apply-templates select="." /><xsl:text> )</xsl:text>
      </xsl:for-each>
    </p>	
   <xsl:call-template name="trace_ancestor_inclusions">
     <xsl:with-param name="element_name" select="$new_element_name" />
   </xsl:call-template>			
  </xsl:for-each>			
</xsl:template>

It seems that what I need is a test around the call-template at the end of the template to test whether I've already encountered a given element and bypass it. If someone could show me what that logic would be, I would be most appreciative.

Thanks,

Don

Current Thread