]> granicus.if.org Git - docbook-dsssl/commitdiff
Updated
authorNorman Walsh <ndw@nwalsh.com>
Tue, 6 Jan 2004 13:57:59 +0000 (13:57 +0000)
committerNorman Walsh <ndw@nwalsh.com>
Tue, 6 Jan 2004 13:57:59 +0000 (13:57 +0000)
docbook/relaxng/tools/augment.xsl
docbook/relaxng/tools/cleanup.pl
docbook/relaxng/tools/db4-upgrade.xsl
docbook/relaxng/tools/html.xsl
docbook/relaxng/tools/include.xsl
docbook/relaxng/tools/missing-defs.xsl
docbook/relaxng/tools/trimgrammar.pl [new file with mode: 0644]

index 466320f9ef212f85c919721b455abb469086bf09..5e86c0179a4ba6567b120bc7fc5c0f924342df65 100644 (file)
@@ -4,7 +4,8 @@
                 xmlns:rng="http://relaxng.org/ns/structure/1.0"
                 xmlns:ctrl="http://nwalsh.com/xmlns/schema-control/"
                xmlns:s="http://www.ascc.net/xml/schematron"
-                exclude-result-prefixes="exsl ctrl"
+               xmlns:db="http://docbook.org/docbook-ng/absinthe"
+                exclude-result-prefixes="exsl ctrl rng s db"
                 version="1.0">
 
   <xsl:output method="xml" encoding="utf-8" indent="yes"/>
 
   <xsl:variable name="exclusionsNS">
     <exclusions>
-      <xsl:apply-templates select="//ctrl:exclude"/>
+      <xsl:apply-templates select="//ctrl:exclude" mode="exclusions"/>
     </exclusions>
   </xsl:variable>
 
   <xsl:variable name="exclusions" select="exsl:node-set($exclusionsNS)/*"/>
 
+  <xsl:variable name="startNS">
+    <xsl:apply-templates select="//rng:start" mode="names"/>
+  </xsl:variable>
+
+  <xsl:variable name="start" select="exsl:node-set($startNS)/*"/>
+
   <xsl:template match="/">
     <xsl:apply-templates/>
   </xsl:template>
       <xsl:attribute name="datatypeLibrary">
        <xsl:value-of select="'http://www.w3.org/2001/XMLSchema-datatypes'"/>
       </xsl:attribute>
+
+      <!-- Make sure the ns is specified -->
+      <xsl:attribute name="ns">
+       <xsl:value-of select="'http://docbook.org/docbook-ng/absinthe'"/>
+      </xsl:attribute>
+
       <xsl:copy-of select="@*"/>
 
       <xsl:text>&#10;</xsl:text>
       <xsl:comment> See http://docbook.org/docbook-ng/ </xsl:comment>
       <xsl:text>&#10;</xsl:text>
 
-      <xsl:for-each select="*">
-       <xsl:choose>
-         <xsl:when test="self::rng:define and rng:element[@name]">
-           <xsl:variable name="name" select="@name"/>
-           <xsl:variable name="basename">
-             <xsl:choose>
-               <xsl:when test="starts-with(@name, 'db.')">
-                 <xsl:value-of select="substring-after(@name, 'db.')"/>
-               </xsl:when>
-               <xsl:otherwise>
-                 <xsl:value-of select="@name"/>
-               </xsl:otherwise>
-             </xsl:choose>
-           </xsl:variable>
-
-           <xsl:variable name="ctrl:common-attributes"
-                         select="(//ctrl:common-attributes[@element=$basename]
-                                  |//ctrl:common-attributes[@define=$name])[1]"/>
-           <xsl:variable name="ctrl:common-linking"
-                         select="(//ctrl:common-linking[@element=$basename]
-                                  |//ctrl:common-linking[@define=$name])[1]"/>
-           <xsl:variable name="ctrl:role"
-                         select="(//ctrl:role[@element=$basename]
-                                  |//ctrl:role[@define=$name])[1]"/>
-
-           <xsl:if test="not($ctrl:role/@suppress)">
-             <rng:define name="{$basename}.role.attrib">
-               <rng:optional>
-                 <rng:ref name="role.attribute"/>
-               </rng:optional>
-             </rng:define>
-           </xsl:if>
-
-           <rng:define name="local.{$basename}.attrib">
-             <rng:empty/>
-           </rng:define>
-
-           <rng:define name="{$basename}.attlist">
-             <xsl:choose>
-               <xsl:when test="$ctrl:common-attributes/@suppress">
-                 <!-- nop -->
-               </xsl:when>
-               <xsl:when test="$ctrl:common-attributes">
-                 <rng:ref name="{$ctrl:common-attributes/@attributes}"/>
-               </xsl:when>
-               <xsl:otherwise>
-                 <rng:ref name="common.attributes"/>
-               </xsl:otherwise>
-             </xsl:choose>
-
-             <xsl:choose>
-               <xsl:when test="$ctrl:common-linking/@suppress">
-                 <!-- nop -->
-               </xsl:when>
-               <xsl:when test="$ctrl:common-linking">
-                 <rng:ref name="{$ctrl:common-linking/@attributes}"/>
-               </xsl:when>
-               <xsl:when test="key('defs',concat($basename,'.linkend.attrib'))
-                               or key('defs',concat($basename,'.linkends.attrib'))">
-                 <!-- no common linking attributes -->
-               </xsl:when>
-               <xsl:otherwise>
-                 <rng:ref name="common.linking.attributes"/>
-               </xsl:otherwise>
-             </xsl:choose>
-
-             <xsl:if test="not($ctrl:role/@suppress)">
-               <rng:ref name="{$basename}.role.attrib"/>
-             </xsl:if>
-
-             <xsl:for-each select="/rng:grammar/rng:define[not(@combine)]">
-               <xsl:if test="string-length(@name) &gt; 7
-                              and starts-with(@name,concat($basename,'.'))
-                             and substring(@name, string-length(@name)-6)
-                                  = '.attrib'">
-                 <rng:ref name="{@name}"/>
-               </xsl:if>
-               <xsl:if test="string-length(@name) &gt; 8
-                              and starts-with(@name,concat($basename,'.'))
-                             and substring(@name, string-length(@name)-7)
-                                  = '.attribs'">
-                 <rng:ref name="{@name}"/>
-               </xsl:if>
-             </xsl:for-each>
-
-             <rng:ref name="local.{$basename}.attrib"/>
-           </rng:define>
-
-           <xsl:apply-templates select="."/>
-         </xsl:when>
-
-         <xsl:when test="self::ctrl:*">
-           <!-- suppress -->
-         </xsl:when>
-
-         <xsl:otherwise>
-           <xsl:apply-templates select="."/>
-         </xsl:otherwise>
-       </xsl:choose>
-      </xsl:for-each>
+      <rng:define name="version.attribute">
+       <rng:attribute name="version"/>
+      </rng:define>
+
+      <xsl:apply-templates/>
     </xsl:copy>
   </xsl:template>
 
          </xsl:message>
          -->
 
-         <s:rule context="{$name}">
-           <s:assert test="not(.//{name(.)})">
+         <s:rule context="db:{$name}">
+           <s:assert test="not(.//db:{name(.)})">
              <xsl:value-of select="name(.)"/>
              <xsl:text> must not occur in the descendants of </xsl:text>
              <xsl:value-of select="$name"/>
        </xsl:for-each>
       </xsl:for-each>
 
-      <rng:ref name="{$basename}.attlist"/>
-      <xsl:apply-templates/>
-    </xsl:copy>
-  </xsl:template>
-
-  <xsl:template match="rng:include">
-    <xsl:copy>
-      <xsl:copy-of select="@*"/>
-
-      <xsl:attribute name="href">
-        <xsl:value-of select="substring-before(@href, '.rnx')"/>
-        <xsl:text>.rng</xsl:text>
-      </xsl:attribute>
+      <xsl:variable name="isStart">
+       <xsl:value-of select="0"/>
+       <xsl:for-each select="$start">
+         <xsl:if test="local-name(.) = $name">1</xsl:if>
+       </xsl:for-each>
+      </xsl:variable>
+
+      <xsl:if test="$isStart &gt; 0">
+       <rng:optional>
+         <rng:ref name="version.attribute"/>
+       </rng:optional>
+       <s:rule context="/db:{$name}">
+         <s:assert test="@version">
+           <xsl:text>The root element must have a version attribute.</xsl:text>
+         </s:assert>
+       </s:rule>
+      </xsl:if>
 
       <xsl:apply-templates/>
     </xsl:copy>
   </xsl:template>
 
-  <xsl:template match="ctrl:exclude">
+  <xsl:template match="ctrl:exclude" mode="exclusions">
     <ctrl:exclusion>
       <ctrl:from>
        <xsl:apply-templates select="key('defs', @from)" mode="names"/>
index c203d75bdb602ffb2828768e8b6962e93282ffe7..70b5a31bc4b7fa3c0be2ae3d358e0f22c46392cc 100644 (file)
@@ -17,7 +17,8 @@ while (<>) {
     s/\s*xmlns:s=([\"\']).*?\1\s*//g;
 
     s/<(s:rule\s+.*?)>/<\1 xmlns:s=\"http:\/\/www.ascc.net\/xml\/schematron\">/g;
+    s/<(ctrl:\S+\s+.*?)(\/?>)/<\1 xmlns:ctrl=\"http:\/\/nwalsh.com\/xmlns\/schema-control\/\"\2/g;
 
     print $_;
-    print "\n" if /<\/define>/;
+    print "\n" if /<\/define>/ || /<ctrl:/ || /<\/start>/;
 }
index d4b251091f948135d4fb1fe9d4a2e4362bf8b5ee..8d7dde30bd850b663fdb6a33b14912801ae833bb 100644 (file)
@@ -1,5 +1,8 @@
 <?xml version="1.0"?>
 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:exsl="http://exslt.org/common"
+               xmlns:db = "http://docbook.org/docbook-ng/absinthe"
+                exclude-result-prefixes="exsl db"
                 version="1.0">
 
 <!-- ======================================================================
 <xsl:output method="xml" encoding="utf-8" indent="no"/>
 <xsl:preserve-space elements="*"/>
 
+<xsl:template match="/">
+  <xsl:variable name="converted">
+    <xsl:apply-templates/>
+  </xsl:variable>
+  <xsl:apply-templates select="exsl:node-set($converted)/*" mode="addNS"/>
+</xsl:template>
+
 <xsl:template match="bookinfo|chapterinfo|articleinfo|artheader|appendixinfo|blockinfo
                      |bibliographyinfo|glossaryinfo|indexinfo|setinfo|setindexinfo
                      |sect1info|sect2info|sect3info|sect4info|sect5info
 </xsl:template>
 
 <xsl:template match="sgmltag" priority="200">
-  <xmltag>
+  <tag>
     <xsl:call-template name="copy.attributes"/>
     <xsl:apply-templates/>
-  </xmltag>
+  </tag>
 </xsl:template>
 
 <xsl:template match="pubsnumber" priority="200">
 
 <!-- ====================================================================== -->
 
+<xsl:template match="*" mode="addNS">
+  <xsl:choose>
+    <xsl:when test="namespace-uri(.) = ''">
+      <xsl:element name="{local-name(.)}"
+                  namespace="http://docbook.org/docbook-ng/absinthe">
+       <xsl:if test="not(parent::*)">
+         <xsl:attribute name="version">absinthe</xsl:attribute>
+       </xsl:if>
+       <xsl:copy-of select="@*"/>
+       <xsl:apply-templates mode="addNS"/>
+      </xsl:element>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:copy>
+       <xsl:if test="not(parent::*)">
+         <xsl:attribute name="version">absinthe</xsl:attribute>
+       </xsl:if>
+       <xsl:copy-of select="@*"/>
+       <xsl:apply-templates mode="addNS"/>
+      </xsl:copy>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+<xsl:template match="comment()|processing-instruction()|text()" mode="addNS">
+  <xsl:copy/>
+</xsl:template>
+
 </xsl:stylesheet>
index a9bd9b28099886f1be7285ab3d157d7b90359157..0005168dd6e933e4927b25cae4e9071859f8e757 100644 (file)
@@ -3,7 +3,8 @@
                 xmlns:exsl="http://exslt.org/common"
                 xmlns:rng="http://relaxng.org/ns/structure/1.0"
                 xmlns:ctrl="http://nwalsh.com/xmlns/schema-control/"
-                exclude-result-prefixes="exsl ctrl"
+               xmlns:s="http://www.ascc.net/xml/schematron"
+                exclude-result-prefixes="exsl ctrl s rng"
                 version="1.0">
 
   <xsl:output method="html" encoding="utf-8" indent="yes"/>
     <li><em>text</em></li>
   </xsl:template>
 
+  <xsl:template match="rng:empty">
+    <li><em>EMPTY</em></li>
+  </xsl:template>
+
+  <xsl:template match="rng:notAllowed">
+    <li><em>not allowed</em></li>
+  </xsl:template>
+
   <xsl:template match="rng:element">
     <div class="element">
       <xsl:text>&lt;</xsl:text>
          </ul>
        </xsl:otherwise>
       </xsl:choose>
+
+      <xsl:if test="s:rule">
+       <p>Additional rules apply.</p>
+      </xsl:if>
     </div>
   </xsl:template>
 
+  <xsl:template match="s:*">
+    <!-- nop -->
+  </xsl:template>
+
   <xsl:template match="rng:attribute">
     <div class="attribute">
       <xsl:text>@</xsl:text>
   </xsl:template>
 
   <xsl:template match="rng:ref">
-    <xsl:if test="not(contains(@name,'attrib'))">
-      <li>
-       <xsl:choose>
-         <xsl:when test="key('defs', @name)/rng:element">
-           <xsl:text>&lt;</xsl:text>
-           <a href="#{@name}">
-             <xsl:value-of select="key('defs', @name)/rng:element/@name"/>
-           </a>
-           <xsl:text>&gt;</xsl:text>
-           <xsl:if test="parent::rng:optional">*</xsl:if>
-         </xsl:when>
-         <xsl:otherwise>
-           <a href="#{@name}">
-             <xsl:value-of select="@name"/>
-           </a>
-           <xsl:if test="parent::rng:optional">*</xsl:if>
-         </xsl:otherwise>
-       </xsl:choose>
-      </li>
-    </xsl:if>
+    <xsl:choose>
+      <xsl:when test="contains(@name,'attrib')">
+       <li>
+         <a href="#{@name}">
+           <xsl:value-of select="@name"/>
+         </a>
+         <xsl:if test="ancestor::rng:optional">*</xsl:if>
+       </li>
+      </xsl:when>
+      <xsl:otherwise>
+       <li>
+         <xsl:choose>
+           <xsl:when test="key('defs', @name)/rng:element">
+             <xsl:text>&lt;</xsl:text>
+             <a href="#{@name}">
+               <xsl:value-of select="key('defs', @name)/rng:element/@name"/>
+             </a>
+             <xsl:text>&gt;</xsl:text>
+             <xsl:if test="parent::rng:optional">*</xsl:if>
+           </xsl:when>
+           <xsl:otherwise>
+             <a href="#{@name}">
+               <xsl:value-of select="@name"/>
+             </a>
+             <xsl:if test="parent::rng:optional">*</xsl:if>
+           </xsl:otherwise>
+         </xsl:choose>
+       </li>
+      </xsl:otherwise>
+    </xsl:choose>
   </xsl:template>
 
   <xsl:template match="rng:optional">
index 847b8c953cd630074bd305ed55354040d94236f5..df14a88b4c3e4bf15b8141209b052532bcfd47aa 100644 (file)
 
   <xsl:key name="defs" match="rng:define" use="@name"/>
   <xsl:key name="combines" match="rng:define[@combine='choice']" use="@name"/>
+  <xsl:key name="overrides" match="rng:define[@override]" use="@name"/>
 
   <xsl:template match="/">
     <xsl:variable name="expanded">
       <xsl:apply-templates mode="include"/>
     </xsl:variable>
-    <xsl:message>Combining...</xsl:message>
-    <xsl:apply-templates select="exsl:node-set($expanded)/*" mode="combine"/>
+
+    <xsl:variable name="overridden">
+      <xsl:apply-templates select="exsl:node-set($expanded)/*" mode="override"/>
+    </xsl:variable>
+
+    <xsl:apply-templates select="exsl:node-set($overridden)/*" mode="combine"/>
   </xsl:template>
 
   <!-- ====================================================================== -->
@@ -26,6 +31,7 @@
     <xsl:message>Including <xsl:value-of select="@href"/></xsl:message>
     <xsl:variable name="doc" select="document(@href,.)"/>
     <xsl:apply-templates select="$doc/rng:grammar/*" mode="include"/>
+    <xsl:apply-templates mode="markOverride"/>
   </xsl:template>
 
   <xsl:template match="*" mode="include">
 
   <!-- ====================================================================== -->
 
+  <xsl:template match="*" mode="markOverride">
+    <xsl:copy>
+      <xsl:copy-of select="@*"/>
+      <xsl:if test="parent::rng:include">
+       <xsl:if test="not(self::rng:define)">
+         <xsl:message>
+           <xsl:text>Warning: only expecting rng:define children </xsl:text>
+           <xsl:text>of rng:include</xsl:text>
+         </xsl:message>
+       </xsl:if>
+       <xsl:attribute name="override">
+         <xsl:value-of select="parent::rng:include/@href"/>
+       </xsl:attribute>
+      </xsl:if>
+      <xsl:apply-templates mode="markOverride"/>
+    </xsl:copy>
+  </xsl:template>
+
+  <xsl:template match="comment()|processing-instruction()|text()" mode="markOverride">
+    <xsl:copy/>
+  </xsl:template>
+
+  <!-- ====================================================================== -->
+
   <xsl:template match="rng:define" mode="combine">
     <xsl:choose>
       <xsl:when test="@combine = 'choice'"/>
       <xsl:when test="@combine = 'interleave'">
        <!-- these are always attributes, right? -->
+       <xsl:message>
+         <xsl:text>Interleaving attributes for </xsl:text>
+         <xsl:value-of select="@name"/>
+       </xsl:message>
+
        <xsl:copy>
          <xsl:copy-of select="@*"/>
          <xsl:apply-templates mode="combine"/>
        <xsl:variable name="choices" select="key('combines', @name)"/>
        <xsl:choose>
          <xsl:when test="$choices">
+           <xsl:message>
+             <xsl:text>Combining definitions for </xsl:text>
+             <xsl:value-of select="@name"/>
+           </xsl:message>
+
+           <xsl:copy>
+             <xsl:copy-of select="@*"/>
+             <rng:choice>
+               <xsl:apply-templates mode="combine"/>
+               <xsl:apply-templates select="$choices/*" mode="combine"/>
+             </rng:choice>
+           </xsl:copy>
+         </xsl:when>
+         <xsl:otherwise>
+           <xsl:copy>
+             <xsl:copy-of select="@*"/>
+             <xsl:apply-templates mode="combine"/>
+           </xsl:copy>
+         </xsl:otherwise>
+       </xsl:choose>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template match="rng:start" mode="combine">
+    <xsl:choose>
+      <xsl:when test="@combine = 'choice'"/>
+      <xsl:when test="@combine">
+       <!-- what's this!? -->
+       <xsl:message>
+         <xsl:text>Warning: unexpected combine on rng:start</xsl:text>
+       </xsl:message>
+       <xsl:copy>
+         <xsl:copy-of select="@*"/>
+         <xsl:apply-templates mode="combine"/>
+       </xsl:copy>
+      </xsl:when>
+      <xsl:otherwise>
+       <xsl:variable name="choices" select="//rng:start[@combine='choice']"/>
+       <xsl:choose>
+         <xsl:when test="$choices">
+           <xsl:message>
+             <xsl:text>Combining start definitions</xsl:text>
+           </xsl:message>
+
            <xsl:copy>
              <xsl:copy-of select="@*"/>
              <rng:choice>
     <xsl:copy/>
   </xsl:template>
 
+  <!-- ====================================================================== -->
+
+  <xsl:template match="rng:define" mode="override">
+    <xsl:variable name="over" select="key('overrides', @name)"/>
+    <xsl:choose>
+      <xsl:when test="@override">
+       <xsl:copy>
+         <xsl:copy-of select="@*[name(.) != 'override']"/>
+         <xsl:apply-templates mode="override"/>
+       </xsl:copy>
+      </xsl:when>
+      <xsl:when test="$over">
+       <xsl:message>
+         <xsl:text>Suppressing original definition of </xsl:text>
+         <xsl:value-of select="@name"/>
+       </xsl:message>
+      </xsl:when>
+      <xsl:otherwise>
+       <xsl:copy>
+         <xsl:copy-of select="@*"/>
+         <xsl:apply-templates mode="override"/>
+       </xsl:copy>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template match="*" mode="override">
+    <xsl:copy>
+      <xsl:copy-of select="@*"/>
+      <xsl:apply-templates mode="override"/>
+    </xsl:copy>
+  </xsl:template>
+
+  <xsl:template match="comment()|processing-instruction()|text()" mode="override">
+    <xsl:copy/>
+  </xsl:template>
+
 </xsl:stylesheet>
index f751be7cb33931765c8bdcde382a8565560c81b0..bf72c2a77a4a3b8c9da7fa1584d02be03420ca71 100644 (file)
@@ -9,31 +9,38 @@
 
 <xsl:output method="text"/>
 
+<xsl:param name="check-defs" select="1"/>
+<xsl:param name="check-refs" select="1"/>
+
 <xsl:key name="defines" match="rng:define" use="@name"/>
 <xsl:key name="refs" match="rng:ref" use="@name"/>
 
 <xsl:template match="/">
-  <xsl:for-each select="//rng:ref">
-    <xsl:variable name="name" select="@name"/>
-    <xsl:if test="not(preceding::rng:ref[@name=$name])">
-      <xsl:if test="not(key('defines', $name))">
-        <xsl:text>Missing define: </xsl:text>
-        <xsl:value-of select="$name"/>
-        <xsl:text>&#10;</xsl:text>
+  <xsl:if test="$check-defs != 0">
+    <xsl:for-each select="//rng:ref">
+      <xsl:variable name="name" select="@name"/>
+      <xsl:if test="not(preceding::rng:ref[@name=$name])">
+       <xsl:if test="not(key('defines', $name))">
+         <xsl:text>Missing define: </xsl:text>
+         <xsl:value-of select="$name"/>
+         <xsl:text>&#10;</xsl:text>
+       </xsl:if>
       </xsl:if>
-    </xsl:if>
-  </xsl:for-each>
+    </xsl:for-each>
+  </xsl:if>
 
-  <xsl:for-each select="//rng:define">
-    <xsl:variable name="name" select="@name"/>
-    <xsl:if test="not(preceding::rng:define[@name=$name])">
-      <xsl:if test="not(key('refs', $name)) and not(rng:element)">
-        <xsl:text>Unreferenced: </xsl:text>
-        <xsl:value-of select="$name"/>
-        <xsl:text>&#10;</xsl:text>
+  <xsl:if test="$check-refs != 0">
+    <xsl:for-each select="//rng:define">
+      <xsl:variable name="name" select="@name"/>
+      <xsl:if test="not(preceding::rng:define[@name=$name])">
+       <xsl:if test="not(key('refs', $name)) and not(rng:element)">
+         <xsl:text>Unreferenced: </xsl:text>
+         <xsl:value-of select="$name"/>
+         <xsl:text>&#10;</xsl:text>
+       </xsl:if>
       </xsl:if>
-    </xsl:if>
-  </xsl:for-each>
+    </xsl:for-each>
+  </xsl:if>
 </xsl:template>
 
 </xsl:stylesheet>
diff --git a/docbook/relaxng/tools/trimgrammar.pl b/docbook/relaxng/tools/trimgrammar.pl
new file mode 100644 (file)
index 0000000..65ec77d
--- /dev/null
@@ -0,0 +1,153 @@
+#!/bin/perl -- # -*- Perl -*-
+
+use strict;
+use XML::DOM;
+use Getopt::Std;
+use vars qw($opt_o $opt_v $opt_r);
+
+my $usage = "Usage: $0 [-v] [-r] [-o file] file\n";
+
+die $usage if ! getopts('o:v');
+
+my $output = $opt_o || "-";
+my $verbose = $opt_v;
+my $showRecurse = $opt_r;
+
+my $xmlfile = shift @ARGV || die "Usage: $0 xmlfile\n";
+
+my $parser = new XML::DOM::Parser (NoExpand => 0);
+my $xmldoc = $parser->parsefile($xmlfile);
+my $root   = $xmldoc->getDocumentElement();
+
+my %patterns = ();
+
+findPatterns($root);
+
+my $start = $patterns{"*start"};
+delete $patterns{"*start"};
+
+my @pats = keys %patterns;
+my $totPat = $#pats + 1;
+
+print STDERR "There are $#pats patterns in $xmlfile.\n";
+
+my %used = ();
+
+recurse($start ,1);
+
+@pats = keys %used;
+my $usedPat = $#pats + 1;
+
+print STDERR "Discarding ", $totPat-$usedPat, " unused patterns in $xmlfile.\n";
+
+if ($verbose) {
+    foreach my $pat (sort keys %patterns) {
+       if (!$used{$pat}) {
+           print STDERR "\t$pat\n";
+       }
+    }
+}
+
+open (SAVEOUT, ">&STDOUT");
+close (STDOUT);
+open (STDOUT, ">$output");
+printXML($root);
+close (STDOUT);
+open (STDOUT, ">&SAVEOUT");
+
+exit 0;
+
+sub findPatterns {
+    my $element = shift;
+
+    my $child = $element->getFirstChild();
+
+    while ($child) {
+       if ($child->getNodeType() == XML::DOM::ELEMENT_NODE) {
+           if ($child->getTagName() eq 'define') {
+               $patterns{$child->getAttribute('name')} = $child;
+           } elsif ($child->getTagName() eq 'start') {
+               $patterns{"*start"} = $child;
+           }
+       }
+
+       $child = $child->getNextSibling();
+    }
+}
+
+sub recurse {
+    my $node = shift;
+    my $depth = shift || 0;
+    my $child = $node->getFirstChild();
+
+#    print "X", " " x $depth, $node->getTagName();
+#    print " (", $node->getAttribute('name'), ")\n";
+
+    while ($child) {
+       if ($child->getNodeType() == XML::DOM::ELEMENT_NODE) {
+           if ($child->getTagName() eq 'define') {
+               my $name = $child->getAttribute('name');
+               if (! exists $used{$name}) {
+                   $used{$name} = 1;
+                   print "D", " " x $depth, $name, "\n" if $showRecurse;
+                   recurse($patterns{$name},$depth+1);
+               }
+           } elsif ($child->getTagName() eq 'ref') {
+               my $name = $child->getAttribute('name');
+               if (! exists $used{$name}) {
+                   $used{$name} = 1;
+                   print "R", " " x $depth, $name, "\n" if $showRecurse;
+                   recurse($patterns{$name},$depth+1);
+               }
+           } else {
+               recurse($child, $depth);
+           }
+       }
+
+       $child = $child->getNextSibling();
+    }
+}
+
+sub printXML {
+    my $node = shift;
+
+    if ($node->getNodeType() == XML::DOM::ELEMENT_NODE) {
+       if ($node->getTagName ne 'define'
+           || $used{$node->getAttribute('name')}) {
+           my $child = $node->getFirstChild();
+           my $attrs = $node->getAttributes();
+
+           print "<";
+           print $node->getTagName();
+
+           for (my $count = 0; $count < $attrs->getLength(); $count++) {
+               my $attr = $attrs->item($count);
+               my $name = $attr->getName();
+               my $value = $attr->getValue();
+               print " $name=\"$value\"";
+           }
+
+           if ($child) {
+               print ">";
+               while ($child) {
+                   printXML($child);
+                   $child = $child->getNextSibling();
+               }
+               print "</";
+               print $node->getTagName();
+               print ">";
+           } else {
+               print "/>";
+           }
+       }
+    } elsif ($node->getNodeType() == XML::DOM::TEXT_NODE) {
+       print $node->getData();
+    } elsif ($node->getNodeType() == XML::DOM::COMMENT_NODE) {
+       print "<!--", $node->getData(), "-->";
+    } elsif ($node->getNodeType() == XML::DOM::PROCESSING_INSTRUCTION_NODE) {
+       print "<?", $node->getTarget(), " ", $node->getData(), "?>";
+    } else {
+       die "Unexpected node type: ", $node->getNodeType(), "\n";
+    }
+}
+