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> </xsl:text>
<xsl:comment> See http://docbook.org/docbook-ng/ </xsl:comment>
<xsl:text> </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) > 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) > 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 > 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"/>
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>/;
}
<?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>
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><</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><</xsl:text>
- <a href="#{@name}">
- <xsl:value-of select="key('defs', @name)/rng:element/@name"/>
- </a>
- <xsl:text>></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><</xsl:text>
+ <a href="#{@name}">
+ <xsl:value-of select="key('defs', @name)/rng:element/@name"/>
+ </a>
+ <xsl:text>></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">
<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>
<!-- ====================================================================== -->
<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>
<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> </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> </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> </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> </xsl:text>
+ </xsl:if>
</xsl:if>
- </xsl:if>
- </xsl:for-each>
+ </xsl:for-each>
+ </xsl:if>
</xsl:template>
</xsl:stylesheet>
--- /dev/null
+#!/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";
+ }
+}
+