]> granicus.if.org Git - docbook-dsssl/commitdiff
Lots and lots and lots of changes
authorNorman Walsh <ndw@nwalsh.com>
Sat, 6 Oct 2001 13:39:05 +0000 (13:39 +0000)
committerNorman Walsh <ndw@nwalsh.com>
Sat, 6 Oct 2001 13:39:05 +0000 (13:39 +0000)
17 files changed:
litprog/.cvsignore
litprog/.stylesheets/fo.xsl [new file with mode: 0644]
litprog/.stylesheets/html.xsl [new file with mode: 0644]
litprog/Makefile
litprog/bootstrap-tangle.xsl
litprog/example/.cvsignore [new file with mode: 0644]
litprog/example/Makefile [new file with mode: 0644]
litprog/example/doc.xsl [new file with mode: 0644]
litprog/example/doc.xweb [new file with mode: 0644]
litprog/example/fib.xweb [new file with mode: 0644]
litprog/example/prettyprint.pl [new file with mode: 0644]
litprog/fo/.cvsignore [new file with mode: 0644]
litprog/fo/Makefile [new file with mode: 0644]
litprog/html/Makefile
litprog/html/ldocbook.xweb
litprog/tangle.xweb
litprog/weave.xweb

index ef6a50e1f7cec6ef80d146f2902f093644861712..cce1f48eaa0281adc3a7f03e9f63b5eab0c6466c 100644 (file)
@@ -1,10 +1,9 @@
-wdocbook.xml
 wdocbook.xsl
-wdocbook.html
 weave.xml
 weave.xsl
 weave.html
 tangle.xml
 tangle.xsl
 tangle.html
+xtangle.xsl
 
diff --git a/litprog/.stylesheets/fo.xsl b/litprog/.stylesheets/fo.xsl
new file mode 100644 (file)
index 0000000..d8ed8ff
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:fo="http://www.w3.org/1999/XSL/Format"
+                version="1.0">
+
+<xsl:import href="../../xsl/fo/docbook.xsl"/>
+
+<xsl:param name="page.margin.outer" select="'1in'"/>
+<xsl:param name="title.margin.left" select="'-0pt'"/>
+
+<xsl:template match="revhistory" mode="titlepage.mode"/>
+
+<xsl:template match="affiliation" mode="titlepage.mode">
+  <fo:block font-weight="normal" font-size="12pt">
+    <xsl:apply-templates mode="titlepage.mode"/>
+  </fo:block>
+</xsl:template>
+
+<xsl:template match="phrase[@condition='online']"/>
+
+</xsl:stylesheet>
diff --git a/litprog/.stylesheets/html.xsl b/litprog/.stylesheets/html.xsl
new file mode 100644 (file)
index 0000000..01ecb4b
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="1.0">
+
+<xsl:import href="../../xsl/html/docbook.xsl"/>
+
+<xsl:output method="html"/>
+
+<xsl:param name="html.stylesheet" select="'paper.css'"/>
+
+<xsl:template match="revhistory" mode="titlepage.mode"/>
+
+</xsl:stylesheet>
index 90a2b7d221372506f16a745b04c3ba16a0cabd0b..c9f84079d5463f50ab405c8c64fa52895295879e 100644 (file)
@@ -1,46 +1,65 @@
 include ../cvstools/Makefile.incl
 
-all: tangle.xsl weave.xsl wdocbook.xsl
+all: tangle.xsl weave.xsl wdocbook.xsl xtangle.xsl
        $(MAKE) -C html
+       $(MAKE) -C example
 
-xml: tangle.xml weave.xml wdocbook.xml
+xml: tangle.xml weave.xml
+       $(MAKE) -C html xml
+       $(MAKE) -C example xml
 
-html: xml tangle.html weave.html wdocbook.html
+html: xml tangle.html weave.html
+       $(MAKE) -C html html
+       $(MAKE) -C example html
 
-tangle.html: tangle.xml html/ldocbook.xsl
+%.html: %.xml html/ldocbook.xsl
        $(XSLT) $< html/ldocbook.xsl $@
 
-tangle.xml: tangle.xweb wdocbook.xsl
-       $(XSLT) $< wdocbook.xsl $@
+%.fo: %.xml fo/ldocbook.xsl
+       $(XSLT) $< fo/ldocbook.xsl $@
+
+%.pdf: %.fo
+       xep $< $@
+       rm -f $@
 
 # Can this rule be improved? Ideally bootstrap-tangle should only be
 # required if tangle.xsl doesn't exist. If it exists but is out-of-date
 # it can rebuild itself.
-tangle.xsl: tangle.xweb bootstrap-tangle.xsl
-       $(XSLT) $< bootstrap-tangle.xsl .temp.xsl
-       $(XSLT) $< .temp.xsl tangle.xsl
-       rm -f .temp.xsl
+xtangle.xsl: tangle.xweb bootstrap-tangle.xsl
+       $(XSLT) $< bootstrap-tangle.xsl .boot.tangle.xsl
+       $(XSLT) $< .boot.tangle.xsl $@ top=xtop
+       rm -f .boot.tangle.xsl
+
+tangle.xsl: tangle.xweb xtangle.xsl
+       $(XSLT) $< xtangle.xsl $@
+
+tangle.xml: tangle.xweb wdocbook.xsl
+       $(XSLT) $< wdocbook.xsl $@
 
-weave.html: weave.xml html/ldocbook.xsl
-       $(XSLT)  $< html/ldocbook.xsl $@
+weave.xsl: weave.xweb xtangle.xsl
+       $(XSLT)  $< xtangle.xsl $@
 
 weave.xml: weave.xweb wdocbook.xsl
        $(XSLT)  $< wdocbook.xsl $@
        xjparse $@
 
-weave.xsl: weave.xweb tangle.xsl
-       $(XSLT)  $< tangle.xsl $@
+wdocbook.xsl: weave.xweb xtangle.xsl weave.xsl
+       $(XSLT) $< xtangle.xsl $@ top=wdocbook
 
-wdocbook.html: wdocbook.xml wdocbook.xsl
-       $(XSLT) $< wdocbook.xsl $@
+realclean: clean
+       rm -f xtangle.xsl
+       rm -f weave.xsl wdocbook.xsl
+       rm -f tangle.xsl
+       $(MAKE) -C html realclean
+       $(MAKE) -C fo realclean
+       $(MAKE) -C example realclean
+
+clean:
+       rm -f weave.{xml,html,fo,pdf}
+       rm -f tangle.{xml,html,fo,pdf}
+       $(MAKE) -C html clean
+       $(MAKE) -C fo clean
+       $(MAKE) -C example clean
 
-wdocbook.xml: wdocbook.xweb wdocbook.xsl
-       $(XSLT) $< wdocbook.xsl $@
 
-wdocbook.xsl: wdocbook.xweb tangle.xsl
-       $(XSLT) $< tangle.xsl $@
 
-clean:
-       rm -f weave.{xsl,xml,html}
-       rm -f tangle.{xsl,xml,html}
-       rm -f wdocbook.{xsl,xml,html}
index 9820a53d5d108a72b03f44e63cf01296a8fc8d29..2b90180901bee2734345cdd2d23d087838fe9784 100644 (file)
 
 <xsl:output method="xml"/>
 
+<xsl:param name="top" select="'xtop'"/>
+
 <xsl:template match="/">
-  <xsl:apply-templates select="//src:topfragment"/>
+  <xsl:apply-templates select="//src:fragment[@id=$top]"/>
 </xsl:template>
 
 <xsl:template match="text()"/>
   <xsl:apply-templates/>
 </xsl:template>
 
-<xsl:template match="src:topfragment">
-  <xsl:apply-templates mode="copy"/>
-</xsl:template>
-
 <xsl:template match="src:fragment">
   <xsl:apply-templates mode="copy"/>
 </xsl:template>
diff --git a/litprog/example/.cvsignore b/litprog/example/.cvsignore
new file mode 100644 (file)
index 0000000..98bca1f
--- /dev/null
@@ -0,0 +1,8 @@
+doc.html
+doc.xml
+doc.xpp
+doc.xsd
+fib.html
+fib.pl
+fib.xml
+fib.xpp
diff --git a/litprog/example/Makefile b/litprog/example/Makefile
new file mode 100644 (file)
index 0000000..268e1c5
--- /dev/null
@@ -0,0 +1,45 @@
+include ../../cvstools/Makefile.incl
+
+all: fib.pl doc.xsd fib.xpp doc.xpp
+
+html: doc.html fib.html
+
+xml: doc.xml fib.xml
+
+doc.html: doc.xml
+       $(XSLT) $< doc.xsl $@
+
+doc.xml: doc.xweb
+       $(XSLT) $< ../wdocbook.xsl $@
+
+doc.xsd: doc.xweb
+       $(XSLT) $< ../xtangle.xsl $@
+
+doc.xpp: doc.xweb prettyprint.pl
+       perl prettyprint.pl $< > $@
+
+fib.html: fib.xml
+       $(XSLT) $< ../html/ldocbook.xsl $@
+
+fib.fo: fib.xml
+       $(XSLT) $< ../fo/ldocbook.xsl $@
+
+fib.pdf: fib.fo
+       xep $< $@
+
+fib.pl: fib.xweb
+       $(XSLT) $< ../tangle.xsl $@
+
+fib.xml: fib.xweb
+       $(XSLT) $< ../wdocbook.xsl $@
+
+fib.xpp: fib.xweb prettyprint.pl
+       perl prettyprint.pl $< > $@
+
+realclean:
+       rm -f doc.{xsd,xpp}
+       rm -f fib.{pl,xpp}
+
+clean:
+       rm -f doc.{html,xml,fo,pdf}
+       rm -f fib.{html,xml,fo,pdf}
diff --git a/litprog/example/doc.xsl b/litprog/example/doc.xsl
new file mode 100644 (file)
index 0000000..f70b625
--- /dev/null
@@ -0,0 +1,65 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:src="http://nwalsh.com/xmlns/litprog/fragment"
+                xmlns:h="http://www.w3.org/TR/xhtml-basic"
+                exclude-result-prefixes="h"
+                version="1.0">
+
+<xsl:output method="html"/>
+
+<xsl:template match="*">
+  <xsl:element name="{name(.)}" namespace="{namespace-uri(.)}">
+    <xsl:copy-of select="@*"/>
+    <xsl:apply-templates/>
+  </xsl:element>
+</xsl:template>
+
+<xsl:template match="src:fragment" priority="2">
+  <table border="1" width="100%" summary="Source Fragment">
+    <tr>
+      <td>
+        <a name="{@id}"/>
+        <b>
+          <xsl:apply-templates select="." mode="label.markup"/>
+        </b>
+      </td>
+    </tr>
+    <tr>
+      <td>
+        <pre>
+          <xsl:apply-templates/>
+        </pre>
+      </td>
+    </tr>
+  </table>
+</xsl:template>
+
+<xsl:template match="src:fragref" priority="2">
+  <xsl:variable name="linkend" select="@linkend"/>
+  <a href="#{$linkend}">
+    <xsl:apply-templates select="//*[@id = $linkend]" mode="label.markup"/>
+    <xsl:text> </xsl:text>
+    <xsl:apply-templates select="//*[@id = $linkend]" mode="title.markup"/>
+  </a>
+</xsl:template>
+
+<xsl:template match="src:fragment" mode="label.markup">
+  <xsl:text>&#xA7;</xsl:text>
+  <xsl:number from="/" level="any"/>
+  <xsl:text>.</xsl:text>
+</xsl:template>
+
+<xsl:template match="src:fragment" mode="title.markup">
+  <xsl:variable name="div" select="ancestor::h:div[1]"/>
+  <xsl:if test="$div">
+    <xsl:variable name="title" select="($div/h:h1[1]
+                                       |$div/h:h2[1]
+                                       |$div/h:h3[1]
+                                       |$div/h:h4[1]
+                                       |$div/h:h5[1]
+                                       |$div/h:h6[1])[1]"/>
+    <xsl:value-of select="$title"/>
+  </xsl:if>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/litprog/example/doc.xweb b/litprog/example/doc.xweb
new file mode 100644 (file)
index 0000000..8e081ed
--- /dev/null
@@ -0,0 +1,102 @@
+<html xmlns="http://www.w3.org/TR/xhtml-basic"
+      xmlns:xs='http://www.w3.org/2001/XMLSchema'
+      xmlns:src="http://nwalsh.com/xmlns/litprog/fragment"
+      xmlns:ex='urn:publicid:-:Norman+Walsh:Schema Example:EN'>
+<head>
+<title>Document Schema</title>
+</head>
+
+<div>
+<h1>A Simple Document W3C XML Schema</h1>
+
+<p>This schema defines elements in the
+<tt>urn:publicid:-:Norman+Walsh:Schema Example:EN</tt> namespace.</p>
+
+<p>This schema defines several complex types and several elements that
+are instances of those types.</p>
+
+<src:fragment id="top" mundane-result-prefixes="ex xs">
+<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'
+           xmlns:ex='urn:publicid:-:Norman+Walsh:Schema Example:EN'
+           targetNamespace='urn:publicid:-:Norman+Walsh:Schema Example:EN'
+           elementFormDefault='qualified'>
+  <src:fragref linkend="types"/>
+  <src:fragref linkend="elements"/>
+</xs:schema>
+</src:fragment>
+</div>
+
+<div>
+<h1><a name="types"/>The Complex Types</h1>
+
+<p>There are three complex types in this schema: <tt>doc</tt>,
+<tt>title</tt>, and <tt>para</tt>.</p>
+
+<src:fragment id="types">
+  <src:fragref linkend="doc.type"/>
+  <src:fragref linkend="title.type"/>
+  <src:fragref linkend="para.type"/>
+</src:fragment>
+
+<div>
+<h2>The <tt>doc</tt> Type</h2>
+
+<src:fragment id="doc.type">
+  <xs:complexType name='doc'>
+    <xs:sequence>
+      <xs:element ref="ex:title" minOccurs='0' maxOccurs='1'/>
+      <xs:choice minOccurs='1' maxOccurs='unbounded'>
+        <xs:element ref='ex:para'/>
+      </xs:choice>
+    </xs:sequence>
+  </xs:complexType>
+</src:fragment>
+</div>
+
+<div>
+<h2>The <tt>title</tt> Type</h2>
+
+<src:fragment id="title.type">
+  <xs:complexType name='title' mixed="true">
+    <src:fragref linkend="role.attrib"/>
+    <xs:anyAttribute namespace="##other" processContents="lax"/>
+  </xs:complexType>
+</src:fragment>
+
+<div>
+<h2>The <tt>role</tt> Attribute</h2>
+
+<p>The role attribute is an optional string.</p>
+
+<src:fragment id="role.attrib">
+    <xs:attribute name="role" type="xs:string"/>
+</src:fragment>
+</div>
+</div>
+
+<div>
+
+<h2>The <tt>para</tt> Type</h2>
+
+<src:fragment id="para.type">
+  <xs:complexType name='para' mixed="true">
+    <src:fragref linkend="role.attrib"/>
+    <xs:anyAttribute namespace="##other" processContents="lax"/>
+  </xs:complexType>
+</src:fragment>
+</div>
+</div>
+
+<div>
+<h1>The Elements</h1>
+
+<p>This schema defines one element of each <a href="#types">complex
+type</a>.</p>
+
+<src:fragment id="elements">
+  <xs:element name="doc" type="ex:doc"/>
+  <xs:element name="para" type="ex:para"/>
+  <xs:element name="title" type="ex:title"/>
+</src:fragment>
+</div>
+</html>
\ No newline at end of file
diff --git a/litprog/example/fib.xweb b/litprog/example/fib.xweb
new file mode 100644 (file)
index 0000000..b5a5aae
--- /dev/null
@@ -0,0 +1,91 @@
+<article xmlns:src="http://nwalsh.com/xmlns/litprog/fragment"
+         xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<articleinfo>
+<title>Calculating Members of the Fibonacci Series</title>
+<author>
+  <firstname>Norman</firstname>
+  <surname>Walsh</surname>
+</author>
+</articleinfo>
+
+<para>This trivial document describes a simple, recursive
+implementation of the Fibonacci series in Perl. The principal
+motivation for this document is to demonstrate the use of Literate XML.
+</para>
+
+<section><title>The <function>fib</function> Function</title>
+
+<para>The heart of this program is the recursive function that
+calculates the members of the Fibonacci series.</para>
+
+<para>The first and second members of the Fibonnacci series are
+<quote>1</quote>; all other values are calculated recursively.</para>
+
+<src:fragment id="sub.fib">
+sub fib {
+    my $n = shift;
+
+    if ($n &lt;= 2) {
+        return 1;
+    } else {
+        return <src:fragref linkend="sub.fib.recursion"/>
+    }
+}
+</src:fragment>
+
+<section><title>Recursive Definition</title>
+
+<para>The Fibonacci series begins: 1 1 2 3 5 8 13... Each member of
+the series, after the first two, is the sum of the preceding two
+members.</para>
+
+<para>This can be implemented recursively by calculating the preceding
+two members of the series and returning their sum:</para>
+
+<src:fragment id="sub.fib.recursion">
+&amp;fib($n-2) + &amp;fib($n-1);
+</src:fragment>
+
+</section>
+</section>
+
+<section><title>Preamble</title>
+
+<para>The program preamble simply establishes a default location for
+the Perl executable and informs the interpreter that we want to use
+the strict pragma.</para>
+
+<src:fragment id="preamble">
+#!/usr/bin/perl -w
+
+use strict;
+</src:fragment>
+</section>
+
+<section><title>Argument Checking</title>
+
+<para>This program expects its argument on the command line and it expects
+that argument to be an unsigned decimal integer.</para>
+
+<src:fragment id="argcheck">
+my $num = shift @ARGV || die;
+
+die "Not a number: $num\n" if $num !~ /^\d+$/;
+</src:fragment>
+</section>
+
+<section><title>The Program</title>
+
+<para>The program prints out the Fibonacci number requested:</para>
+
+<src:fragment id="top">
+<src:fragref linkend="preamble"/>
+<src:fragref linkend="argcheck"/>
+
+print "Fib($num) = ", &amp;fib($num), "\n";
+
+<src:fragref linkend="sub.fib"/>
+</src:fragment>
+</section>
+
+</article>
diff --git a/litprog/example/prettyprint.pl b/litprog/example/prettyprint.pl
new file mode 100644 (file)
index 0000000..5ddbeca
--- /dev/null
@@ -0,0 +1,120 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+my $file = shift @ARGV || die "Usage: $0 file.xml\n";
+
+open (F, $file);
+read (F, $_, -s $file);
+close (F);
+
+print "<programlisting>";
+
+if (/<!DOCTYPE/) {
+    &prettyprint($`);
+    $_ = $& . $';
+
+    if (/<!DOCTYPE\s*\S+\s*\[.*?\]>/s) {
+       print &charescape($&);
+       &prettyprint($');
+    } elsif (/<!DOCTYPE.*>/) {
+       print &charescape($&);
+       &prettyprint($');
+    } else {
+       die "Unparseable !DOCTYPE declaration.\n";
+    }
+} else {
+    &prettyprint($_);
+}
+
+print "</programlisting>\n";
+
+sub prettyprint {
+    local $_ = shift;
+
+    while (/<(.*?)>/s) {
+       my $post = $';
+       $_ = $1;
+
+       print &escape($`);
+
+       if (/^\?(.*)\?$/s) {
+           print &pi($1);
+       } elsif (/^\!--(.*)--$/s) {
+           print &comment($1);
+       } elsif (/^\/(.*)$/s) {
+           print &endtag($1);
+       } else {
+           print &starttag($_);
+       }
+
+       $_ = $post;
+    }
+
+    print &escape($_);
+}
+
+sub escape {
+    local $_ = shift;
+    my $ret = "";
+
+    while (/&(\S+?);/) {
+       my $pre = $`;
+       my $ent = $1;
+       my $post = $';
+
+       $ret .= &charescape($pre);
+       if ($ent =~ /^\#/) {
+           $ret .= &sgmltag('numcharref', $ent);
+       } else {
+           $ret .= &sgmltag('genentity', $ent);
+       }
+
+       $_ = $post;
+    }
+
+    return $ret . &charescape($_);
+}
+
+sub charescape {
+    local $_ = shift;
+
+    s/&/&amp;/sg;
+    s/</&lt;/sg;
+    s/>/&gt;/sg;
+
+    return $_;
+}
+
+sub sgmltag {
+    my $class = shift;
+    my $content = shift;
+
+#    my $tagname = "???";
+#    $tagname = $1 if $content =~ s/^(\S+)/$1/s;
+#    $tagname =~ s/:/-/sg;
+
+    return "<sgmltag class=\"$class\">$content</sgmltag>"
+}
+
+sub pi {
+    return &sgmltag('xmlpi', $_[0]);
+}
+
+sub comment {
+    return &sgmltag('sgmlcomment', $_[0]);
+}
+
+sub starttag {
+    my $content = shift;
+
+    if ($content =~ /\/$/) {
+       return &sgmltag('emptytag', $`);
+    } else {
+       return &sgmltag('starttag', $content);
+    }
+}
+
+sub endtag {
+    return &sgmltag('endtag', $_[0]);
+}
diff --git a/litprog/fo/.cvsignore b/litprog/fo/.cvsignore
new file mode 100644 (file)
index 0000000..ac9bfae
--- /dev/null
@@ -0,0 +1 @@
+ldocbook.xsl
diff --git a/litprog/fo/Makefile b/litprog/fo/Makefile
new file mode 100644 (file)
index 0000000..ec19560
--- /dev/null
@@ -0,0 +1,18 @@
+include ../../cvstools/Makefile.incl
+
+all: ldocbook.xsl
+
+xml:
+       echo Nothing to do here, build xml in ../html instead
+
+html:
+       echo Nothing to do here, build html in ../html instead
+
+ldocbook.xsl: ../html/ldocbook.xweb ../xtangle.xsl
+       $(XSLT) $< ../xtangle.xsl $@ top=fo-top
+
+realclean: clean
+       rm -f ldocbook.xsl
+
+clean:
+       rm -f ldocbook.{html,xml}
index 6ea11a0ac7a2ac128cd5d06f15442d04076dd9fa..865ee88cb52a865d4227ca26a40c19edf80af4fa 100644 (file)
@@ -12,8 +12,12 @@ ldocbook.html: ldocbook.xml ldocbook.xsl
 ldocbook.xml: ldocbook.xweb ../wdocbook.xsl
        $(XSLT) $< ../wdocbook.xsl $@
 
-ldocbook.xsl: ldocbook.xweb ../tangle.xsl
-       $(XSLT) $< ../tangle.xsl $@
+ldocbook.xsl: ldocbook.xweb ../xtangle.xsl
+       $(XSLT) $< ../xtangle.xsl $@
+
+realclean: clean
+       rm -f ldocbook.xsl
 
 clean:
-       rm -f ldocbook.html ldocbook.xml ldocbook.xsl
+       rm -f ldocbook.html ldocbook.xml
+
index 2493ef883921327076ae8eb0a3ecb152a5c31f52..c84257af16de5c12c5ead334cf8c0514920da67e 100644 (file)
+<!DOCTYPE article [
+<!ENTITY xweb "<acronym>XWEB</acronym>">
+<!ENTITY lt    "&#38;#60;"> <!-- LESS-THAN SIGN -->
+<!ENTITY gt    "&#x003E;"> <!-- GREATER-THAN SIGN -->
+<!ENTITY amp   "&#38;#38;"> <!-- AMPERSAND -->
+]>
 <article xmlns:src="http://nwalsh.com/xmlns/litprog/fragment"
-         xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
-<title>Litprog.xsl</title>
+         xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+         xmlns:fo="http://www.w3.org/1999/XSL/Format">
+<articleinfo>
+<title>Literate DocBook XML Stylesheets</title>
+<subtitle>Part of
+<citetitle>Literate Programming in XML</citetitle></subtitle>
+<pubdate>05 Oct 2001</pubdate>
+<releaseinfo role="meta">
+$Id$
+</releaseinfo>
 
-<src:topfragment id="top" default-exclude-result-prefixes="xsl">
+<revhistory>
+<revision>
+<revnumber>0.1</revnumber>
+<date>05 Oct 2001</date>
+<authorinitials>ndw</authorinitials>
+<revremark>Initial draft.</revremark>
+</revision>
+</revhistory>
+
+<author><firstname>Norman</firstname><surname>Walsh</surname>
+</author>
+</articleinfo>
+
+<!-- ============================================================ -->
+
+<para>The <filename>ldocbook.xsl</filename> stylesheet transforms an
+&xweb; documentation file (a <quote>woven</quote> &xweb; document)
+into HTML documentation.</para>
+
+<para>This stylesheet assumes that fragments appear inside DocBook
+<sgmltag>section</sgmltag> elements. Some additional customization of
+the <src:fragref linkend="fragment-label"/> and
+<src:fragref linkend="fragment-title"/> will be required
+to support a different organization.</para>
+
+<section><title>The Stylesheets</title>
+
+<para>This document describes both the HTML and XSL Formatting Objects
+versions of the stylesheet.</para>
+
+<section><title>The HTML Stylesheet</title>
+
+<para>The stylesheet performs some initialization and establishes
+templates for the Literate Programming elements that can appear in
+the documentation. Most of the documentation elements will be
+DocBook elements handled by the imported stylesheet.</para>
+
+<src:fragment id="top" mundane-result-prefixes="xsl fo verb">
 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                 xmlns:src="http://nwalsh.com/xmlns/litprog/fragment"
                 xmlns:verb="com.nwalsh.saxon.Verbatim"
                 exclude-result-prefixes="verb src"
                 version="1.0">
-  <src:fragref linkend="rest"/>
+  <xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl"/>
+
+  <src:fragref linkend="init"/>
+  <src:fragref linkend="proc-html-fragment"/>
+  <src:fragref linkend="proc-html-fragref"/>
 </xsl:stylesheet>
-</src:topfragment>
+</src:fragment>
 
-<section><title>The Rest</title>
+</section>
+<section><title>The FO Stylesheet</title>
 
-<src:fragment id="rest">
-<xsl:import href="../xsl/html/docbook.xsl"/>
+<para>The stylesheet performs some initialization and establishes
+templates for the Literate Programming elements that can appear in
+the documentation. Most of the documentation elements will be
+DocBook elements handled by the imported stylesheet.</para>
+
+<src:fragment id="fo-top" mundane-result-prefixes="xsl fo verb">
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:fo="http://www.w3.org/1999/XSL/Format"
+                xmlns:src="http://nwalsh.com/xmlns/litprog/fragment"
+                xmlns:verb="com.nwalsh.saxon.Verbatim"
+                exclude-result-prefixes="verb src fo"
+                version="1.0">
+
+  <xsl:import href="http://docbook.sourceforge.net/release/xsl/current/fo/docbook.xsl"/>
+
+  <xsl:param name="page.margin.outer" select="'1in'"/>
+  <xsl:param name="title.margin.left" select="'-0pt'"/>
+
+  <src:fragref linkend="init"/>
+  <src:fragref linkend="proc-fo-fragment"/>
+  <src:fragref linkend="proc-fo-fragref"/>
+</xsl:stylesheet>
+</src:fragment>
+</section>
+
+<section><title>Initialization</title>
+
+<para>The stylesheet initializes the processor by loading its version
+information (stored in a separate file because it is shared by several
+stylesheets), importing the base DocBook stylesheet, setting some
+parameters, and setting up
+some internationalized text.</para>
+
+<src:fragment id="init">
+  <xsl:include href="../VERSION"/>
+
+  <xsl:template match="revhistory" mode="titlepage.mode"/>
+
+  <src:fragref linkend="param"/>
+  <src:fragref linkend="i18n"/>
+</src:fragment>
 
+<section><title>Parameters</title>
+
+<para>In DocBook Literate Programming documentation, we always number
+sections and verbatim environments.</para>
+
+<src:fragment id="param">
+<xsl:param name="section.autolabel" select="1"/>
+<xsl:param name="linenumbering.everyNth" select="5"/>
+<xsl:param name="linenumbering.separator" select="'| '"/>
+</src:fragment>
+</section>
+
+<section><title>Localization</title>
+
+<para>Localized text in the DocBook stylesheets makes use of an
+external document to determine the nature of, among other things,
+element titles and cross references.</para>
+
+<para>Cross references to <sgmltag>src:fragments</sgmltag> are not
+supported in the stock stylesheets (since there is no such element
+in DocBook).</para>
+
+<para>In order to make cross references work properly, we must provide
+an appropriate localization for <sgmltag>src:fragment</sgmltag> titles.
+We do this by pointing the <parameter>local.l10n.xml</parameter>
+<emphasis>at ourselves</emphasis> (at the stylesheet document).</para>
+
+<para>In our local localization document, we add an
+<sgmltag>l:i18n</sgmltag> element to provide the necessary context.</para>
+
+<para>If you want to support DocBook Literate Programming in other
+languages, this section will have to be updated.</para>
+
+<src:fragment id="i18n">
 <xsl:param name="local.l10n.xml" select="document('')"/>
 
 <l:i18n xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0">
     </l:context>
   </l:l10n>
 </l:i18n>
+</src:fragment>
+</section>
+</section>
+</section>
 
-<xsl:param name="section.autolabel" select="1"/>
-<xsl:param name="linenumbering.everyNth" select="'3'"/>
-<xsl:param name="linenumbering.separator" select="'|'"/>
+<section><title>Process HTML Fragments</title>
 
-<xsl:output method="html"/>
+<para>Fragments are output as verbatim environments with numbered lines,
+if possible. A table is used to make the listings stand out.</para>
 
+<src:fragment id="proc-html-fragment">
 <xsl:template match="src:fragment">
   <xsl:param name="suppress-numbers" select="'0'"/>
   <xsl:param name="linenumbering" select="'numbered'"/>
+
   <xsl:variable name="section" select="ancestor::section[1]"/>
+  <xsl:variable name="id" select="@id"/>
+  <xsl:variable name="referents"
+                select="//src:fragment[.//src:fragref[@linkend=$id]]"/>
 
+  <div class="src-fragment">
   <a name="{@id}"/>
   <table border="1" width="100%">
     <tr>
       <td>
         <p>
           <b>
-            <xsl:text>&#xA7;</xsl:text>
-            <xsl:apply-templates select="$section" mode="label.markup"/>
-            <xsl:number from="section"/>
+            <xsl:apply-templates select="." mode="label.markup"/>
           </b>
+          <xsl:if test="$referents">
+            <xsl:text>: </xsl:text>
+            <xsl:for-each select="$referents">
+              <xsl:if test="position() &gt; 1">, </xsl:if>
+              <a href="#{@id}">
+                <xsl:apply-templates select="." mode="label.markup"/>
+              </a>
+            </xsl:for-each>
+          </xsl:if>
         </p>
       </td>
     </tr>
       </td>
     </tr>
   </table>
+  </div>
 </xsl:template>
 
-<xsl:template match="src:fragref">
-  <xsl:variable name="targets" select="id(@linkend)"/>
-  <xsl:variable name="target" select="$targets[1]"/>
-  <xsl:variable name="refelem" select="local-name($target)"/>
+<src:fragref linkend="fragment-label"/>
+<src:fragref linkend="fragment-title"/>
+</src:fragment>
 
-  <xsl:call-template name="check.id.unique">
-    <xsl:with-param name="linkend" select="@linkend"/>
-  </xsl:call-template>
+<para>Fragment labels and titles must also be supported.</para>
 
-  <i><xsl:apply-templates/></i>
-  <xsl:text> (</xsl:text>
+<section><title>Fragment Labels</title>
 
-  <xsl:choose>
-    <xsl:when test="$refelem=''">
-      <xsl:message>
-       <xsl:text>XRef to nonexistent id: </xsl:text>
-       <xsl:value-of select="@linkend"/>
-      </xsl:message>
-      <xsl:text>???</xsl:text>
-    </xsl:when>
+<para>A fragment label consists of a section mark followed by the
+label of the current section and the number of the fragment within
+that section.</para>
 
-    <xsl:when test="$target/@xreflabel">
-      <a>
-        <xsl:attribute name="href">
-          <xsl:call-template name="href.target">
-            <xsl:with-param name="object" select="$target"/>
-          </xsl:call-template>
-        </xsl:attribute>
-        <xsl:call-template name="xref.xreflabel">
-          <xsl:with-param name="target" select="$target"/>
-        </xsl:call-template>
-      </a>
-    </xsl:when>
+<src:fragment id="fragment-label">
+<xsl:template match="src:fragment" mode="label.markup">
+  <xsl:variable name="section" select="ancestor::section[1]"/>
 
-    <xsl:otherwise>
-      <a>
-        <xsl:attribute name="href">
-          <xsl:call-template name="href.target">
-            <xsl:with-param name="object" select="$target"/>
-          </xsl:call-template>
-        </xsl:attribute>
+  <xsl:text>&#xA7;</xsl:text>
 
-        <xsl:apply-templates select="id(@linkend)" mode="xref-to-section"/>
-      </a>
+  <xsl:choose>
+    <xsl:when test="$section">
+      <xsl:variable name="section.label">
+        <xsl:apply-templates select="$section" mode="label.markup"/>
+      </xsl:variable>
+      <xsl:choose>
+        <xsl:when test="string($section.label) = ''">
+          <xsl:number from="section"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:copy-of select="$section.label"/>
+          <xsl:text>.</xsl:text>
+          <xsl:number from="section"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:number from="/"/>
     </xsl:otherwise>
   </xsl:choose>
-  <xsl:text>)</xsl:text>
 </xsl:template>
+</src:fragment>
+</section>
 
-<xsl:template match="src:fragment" mode="xref-to">
+<section><title>Fragment Titles</title>
+
+<para>A fragment title is the title of the section that contains it.
+</para>
+
+<src:fragment id="fragment-title">
+<xsl:template match="src:fragment" mode="title.markup">
   <xsl:variable name="section" select="ancestor::section[1]"/>
 
-  <i>
-    <xsl:text>&#xA7;</xsl:text>
-    <xsl:apply-templates select="$section" mode="label.markup"/>
-    <xsl:number from="section"/>
-    <xsl:text>. </xsl:text>
+  <xsl:if test="$section">
     <xsl:apply-templates select="$section" mode="title.markup"/>
-  </i>
+  </xsl:if>
+</xsl:template>
+</src:fragment>
+</section>
+</section>
+
+<section><title>Process FO Fragments</title>
+
+<para>Fragments are output as verbatim environments with numbered lines,
+if possible.</para>
+
+<src:fragment id="proc-fo-fragment">
+<xsl:template match="src:fragment">
+  <xsl:param name="suppress-numbers" select="'0'"/>
+  <xsl:param name="linenumbering" select="'numbered'"/>
+
+  <xsl:variable name="section" select="ancestor::section[1]"/>
+  <xsl:variable name="id" select="@id"/>
+  <xsl:variable name="referents"
+                select="//src:fragment[.//src:fragref[@linkend=$id]]"/>
+
+  <fo:block xsl:use-attribute-sets="formal.object.properties"
+            keep-together="always"
+            border-style="solid"
+            border-width="0pt"
+           border-before-width="0.25pt"
+           border-after-width="0.25pt">
+    <fo:block id="{@id}"
+              border-width="0pt"
+              border-style="solid"
+              border-after-width="0.25pt">
+      <fo:inline font-weight="bold">
+        <xsl:apply-templates select="." mode="label.markup"/>
+      </fo:inline>
+      <fo:inline>
+        <xsl:if test="$referents">
+          <xsl:text>: </xsl:text>
+          <xsl:for-each select="$referents">
+            <xsl:if test="position() &gt; 1">, </xsl:if>
+            <xsl:apply-templates select="." mode="label.markup"/>
+          </xsl:for-each>
+        </xsl:if>
+      </fo:inline>
+    </fo:block>
+
+    <fo:block wrap-option='no-wrap'
+              text-align='start'
+              white-space-collapse='false'
+              linefeed-treatment="preserve"
+              xsl:use-attribute-sets="monospace.verbatim.properties">
+      <xsl:variable name="rtf">
+        <xsl:apply-templates/>
+      </xsl:variable>
+
+      <xsl:choose>
+        <xsl:when test="$suppress-numbers = '0'
+                        and $linenumbering = 'numbered'
+                        and $use.extensions != '0'
+                        and $linenumbering.extension != '0'">
+          <xsl:call-template name="number.rtf.lines">
+            <xsl:with-param name="rtf" select="$rtf"/>
+          </xsl:call-template>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:copy-of select="$rtf"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </fo:block>
+  </fo:block>
+</xsl:template>
+
+<src:fragref linkend="fragment-label"/>
+<src:fragref linkend="fragment-title"/>
+</src:fragment>
+</section>
+
+<section><title>Process HTML Fragment References</title>
+
+<para>A fragment reference has exactly the same semantics as a DocBook
+<sgmltag>xref</sgmltag>.</para>
+
+<src:fragment id="proc-html-fragref">
+<xsl:template match="src:fragref">
+  <xsl:call-template name="xref"/>
 </xsl:template>
+<src:fragref linkend="fragref-html-xref-to"/>
+</src:fragment>
+
+<section><title>Fragment Cross-Reference Text</title>
 
-<xsl:template match="src:fragment" mode="xref-to-section">
+<para>Cross references to fragments produce the fragment label
+and title.</para>
+
+<src:fragment id="fragref-html-xref-to">
+<xsl:template match="src:fragment" mode="xref-to">
   <xsl:variable name="section" select="ancestor::section[1]"/>
 
   <i>
-    <xsl:text>&#xA7;</xsl:text>
-    <xsl:apply-templates select="$section" mode="label.markup"/>
-    <xsl:number from="section"/>
+    <xsl:apply-templates select="." mode="label.markup"/>
+    <xsl:text>. </xsl:text>
+    <xsl:apply-templates select="." mode="title.markup"/>
   </i>
 </xsl:template>
+</src:fragment>
+</section>
+</section>
 
-<xsl:template match="src:fragment" mode="title.markup">
-  <xsl:text>SRC:FRAGMENT TITLE</xsl:text>
+<section><title>Process FO Fragment References</title>
+
+<para>A fragment reference has exactly the same semantics as a DocBook
+<sgmltag>xref</sgmltag>.</para>
+
+<src:fragment id="proc-fo-fragref">
+<xsl:template match="src:fragref">
+  <xsl:call-template name="xref"/>
 </xsl:template>
+<src:fragref linkend="fragref-fo-xref-to"/>
+</src:fragment>
+
+<section><title>Fragment Cross-Reference Text</title>
 
+<para>Cross references to fragments produce the fragment label
+and title.</para>
+
+<src:fragment id="fragref-fo-xref-to">
+<xsl:template match="src:fragment" mode="xref-to">
+  <xsl:variable name="section" select="ancestor::section[1]"/>
+
+  <fo:inline font-style="italic">
+    <xsl:apply-templates select="." mode="label.markup"/>
+    <xsl:text>. </xsl:text>
+    <xsl:apply-templates select="." mode="title.markup"/>
+  </fo:inline>
+</xsl:template>
 </src:fragment>
 </section>
+</section>
 
 </article>
index bb70fe4e8782e8f57bf8fb67ebfae76fb73259f9..d905a77d5d16745af6b8bdc1f0d477bb7c016d40 100644 (file)
+<!DOCTYPE article [
+<!ENTITY xweb "<acronym>XWEB</acronym>">
+]>
 <article xmlns:src="http://nwalsh.com/xmlns/litprog/fragment"
          xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
-<title>Tangle.xsl</title>
+<articleinfo>
+<title>Tangle</title>
+<subtitle>Part of
+<citetitle>Literate Programming in XML</citetitle></subtitle>
+<pubdate>05 Oct 2001</pubdate>
+<releaseinfo role="meta">
+$Id$
+</releaseinfo>
 
-<src:topfragment id="top" default-exclude-result-prefixes="xsl">
-<src:passthrough>
-&lt;!DOCTYPE xsl:stylesheet [
-&lt;!ENTITY nl "&lt;xsl:text>&#xA;&lt;/xsl:text>">
-]>
-</src:passthrough>
+<revhistory>
+<revision>
+<revnumber>0.1</revnumber>
+<date>05 Oct 2001</date>
+<authorinitials>ndw</authorinitials>
+<revremark>Initial draft.</revremark>
+</revision>
+</revhistory>
+
+<author><firstname>Norman</firstname><surname>Walsh</surname>
+</author>
+</articleinfo>
+
+<!-- ============================================================ -->
+
+<para>The <filename>tangle.xsl</filename> stylesheet transforms an
+&xweb; document into a <quote>source code</quote> document. This
+is a relatively straightforward process: starting with the top fragment,
+all of the source fragments are simply stitched together, discarding any
+intervening documentation.</para>
+
+<para>The resulting <quote>tangled</quote> document is ready for use
+by the appropriate processor.</para>
+
+<section><title>The Stylesheet</title>
+
+<para>This &xweb; document contains the source for two stylesheets,
+<filename>tangle.xsl</filename> and <filename>xtangle.xsl</filename>.
+Both stylesheets produce tangled sources, the latter is a simple
+customization of the former for producing XML vocabularies.</para>
+
+<para>Each of these stylesheets performs some initialization, sets
+the output method appropriately, begins processing at the root template,
+and processes fragments, copying the content appropriately.</para>
+
+<section><title>The <filename>tangle.xsl</filename> Stylesheet</title>
+
+<para>The tangle stylesheet produces text output.</para>
+
+<src:fragment id="top" mundane-result-prefixes="xsl">
 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                 xmlns:src="http://nwalsh.com/xmlns/litprog/fragment"
                 exclude-result-prefixes="src"
                 version="1.0">
 
-  <xsl:include href="VERSION"/>
+  <src:fragref linkend="init"/>
+
+  <xsl:output method="text"/>
 
-  <src:fragref linkend="space"/>
-  <src:fragref linkend="output"/>
   <src:fragref linkend="root.template"/>
-  <src:fragref linkend="text"/>
-  <src:fragref linkend="default"/>
-  <src:fragref linkend="rest"/>
+  <src:fragref linkend="process-fragments"/>
+  <src:fragref linkend="copy-elements"/>
 </xsl:stylesheet>
-</src:topfragment>
+</src:fragment>
+</section>
 
-<section><title>Stuff</title>
+<section><title>The <filename>xtangle.xsl</filename> Stylesheet</title>
 
-<src:fragment id="space">
-<xsl:preserve-space elements="*"/>
+<para>The xtangle stylesheet produces XML output.</para>
+
+<src:fragment id="xtop" mundane-result-prefixes="xsl">
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:src="http://nwalsh.com/xmlns/litprog/fragment"
+                exclude-result-prefixes="src"
+                version="1.0">
+
+  <src:fragref linkend="init"/>
+
+  <xsl:output method="xml"/>
+
+  <src:fragref linkend="root.template"/>
+  <src:fragref linkend="process-fragments"/>
+  <src:fragref linkend="copy-elements"/>
+  <src:fragref linkend="copy-xml-constructs"/>
+</xsl:stylesheet>
 </src:fragment>
+</section>
+</section>
+
+<section><title>Initialization</title>
+
+<para>The stylesheet initializes the processor by loading its version
+information (stored in a separate file because it is shared by several
+stylesheets) and telling the processor to preserve whitespace on all
+input elements.</para>
+
+<para>The stylesheet also constructs a key for the ID values used on
+fragments. Because &xweb; documents do not have to be valid according
+to any particular DTD or Schema, the stylesheet cannot rely on having
+the IDs identified as type ID in the source document.</para>
+
+<src:fragment id="init">
+  <xsl:include href="VERSION"/>
+  <xsl:preserve-space elements="*"/>
+
+  <xsl:key name="fragment" match="src:fragment" use="@id"/>
+
+  <xsl:param name="top" select="'top'"/>
 
-<src:fragment id="output">
-<xsl:output method="xml"/>
 </src:fragment>
 
+</section>
+
+<section><title>The Root Template</title>
+
+<para>The root template begins processing at the root of the &xweb;
+document. It outputs a couple of informative comments and then
+directs the processor to transform the <sgmltag>src:fragment</sgmltag>
+element with the <varname>$top</varname> ID.</para>
+
+<para>Source code fragments in the &xweb; document are not required
+to be sequential, so it is necessary to distinguish one fragment
+as the primary starting point.</para>
+
 <src:fragment id="root.template">
 <xsl:template match="/">
-  <xsl:text>&#xA;</xsl:text>
-  <xsl:comment>
-    <xsl:text> This file was generated by tangle.xsl version </xsl:text>
-    <xsl:value-of select="$VERSION"/>
-    <xsl:text>. Do not edit! </xsl:text>
-  </xsl:comment>
-  <xsl:text>&#xA;</xsl:text>
-  <xsl:comment> See http://sourceforge.net/projects/docbook/ </xsl:comment>
-  <xsl:apply-templates select="//src:topfragment"/>
+  <xsl:apply-templates select="key('fragment', $top)"/>
 </xsl:template>
 </src:fragment>
+</section>
 
-<src:fragment id="text">
-<xsl:template match="text()"/>
-</src:fragment>
-
-<src:fragment id="default">
-<xsl:template match="*">
-  <xsl:apply-templates/>
-</xsl:template>
-</src:fragment>
+<section><title>Processing Fragments</title>
 
-<src:fragment id="rest">
-<xsl:template match="src:topfragment">
-  <xsl:apply-templates mode="copy"/>
-</xsl:template>
+<para>In order to <quote>tangle</quote> an &xweb; document, we need
+only copy the contents of the fragments to the result tree.
+Processing <sgmltag>src:fragment</sgmltag> elements is easy, simply copy
+their children:</para>
 
+<src:fragment id="process-fragments">
 <xsl:template match="src:fragment">
   <xsl:apply-templates mode="copy"/>
 </xsl:template>
+</src:fragment>
+</section>
 
-<xsl:template match="*" mode="copy">
-  <xsl:variable name="node" select="."/>
-  <xsl:element name="{name(.)}" namespace="{namespace-uri(.)}">
-    <xsl:for-each select="namespace::*">
-      <xsl:if test="string(.) != namespace-uri($node)">
-        <xsl:copy/>
-      </xsl:if>
-    </xsl:for-each>
-    <xsl:copy-of select="@*"/>
-    <xsl:apply-templates mode="copy"/>
-  </xsl:element>
-</xsl:template>
+<section><title>Copying Elements</title>
+
+<para>Copying elements to the result tree can be divided into four
+cases: <link linkend="s.copy-passthrough">copying passthrough elements</link>,
+<link linkend="s.copy-fragref">copying fragment references</link>, and
+<link linkend="s.copy-default">copying everything else</link>.</para>
+
+<src:fragment id="copy-elements">
+<src:fragref linkend="copy-passthrough"/>
+<src:fragref linkend="copy-fragref"/>
+<src:fragref linkend="copy-default"/>
+</src:fragment>
+
+<section id="s.copy-passthrough">
+<title>Copying <sgmltag>src:passthrough</sgmltag></title>
 
+<para>Passthrough elements contain text that is intended to appear
+literally in the result tree. We use XSLT
+<quote>disable-output-escaping</quote> to copy it without
+interpretation:</para>
+
+<src:fragment id="copy-passthrough">
 <xsl:template match="src:passthrough" mode="copy">
   <xsl:value-of disable-output-escaping="yes" select="."/>
 </xsl:template>
+</src:fragment>
+</section>
+
+<section id="s.copy-fragref">
+<title>Copying <sgmltag>src:fragref</sgmltag></title>
+
+<para>With a unique exception, copying fragment references is
+straightforward: find the fragment that is identified by the
+cross-reference and process it.
+</para>
+
+<para>The single exception arises only in the processing of
+<sgmltag>src:fragref</sgmltag> elements in the <sgmltag>weave.xweb</sgmltag>
+document. There is a single template in the <quote>weave</quote> program
+that needs to copy a literal <sgmltag>src:fragref</sgmltag> element to the
+result tree. That is the <emphasis>only</emphasis> time the
+<xref linkend="doe-fragref"/> branch is executed.
+</para>
 
+<src:fragment id="copy-fragref">
 <xsl:template match="src:fragref" mode="copy">
   <xsl:variable name="node" select="."/>
   <xsl:choose>
+    <src:fragref linkend="doe-fragref"/>
+    <src:fragref linkend="normal-fragref"/>
+  </xsl:choose>
+</xsl:template>
+</src:fragment>
+
+<section><title>Copying Normal Fragment References</title>
+
+<para>To copy a normal fragment reference, identify what the
+<sgmltag class="attribute">linkend</sgmltag> attribute points to,
+make sure it is valid, and process it.</para>
+
+<src:fragment id="normal-fragref">    <xsl:otherwise>
+      <xsl:variable name="fragment" select="key('fragment', @linkend)"/>
+      <src:fragref linkend="fragref-unique"/>
+      <src:fragref linkend="fragref-isfragment"/>
+      <xsl:apply-templates select="$fragment"/>
+    </xsl:otherwise></src:fragment>
+
+<section><title>Fragment is Unique</title>
+
+<para>Make sure that the <sgmltag class="attribute">linkend</sgmltag>
+attribute points to exactly one node in the source tree. It is an error
+if no element exists with that ID value or if more than one exists.</para>
+
+<src:fragment id="fragref-unique">      <xsl:if test="count($fragment) != 1">
+        <xsl:message terminate="yes">
+          <xsl:text>Link to fragment "</xsl:text>
+          <xsl:value-of select="@linkend"/>
+          <xsl:text>" does not uniquely identify a single fragment.</xsl:text>
+        </xsl:message>
+      </xsl:if></src:fragment>
+
+</section>
+
+<section><title>Fragment is a <sgmltag>src:fragment</sgmltag></title>
+
+<para>Make sure that the <sgmltag class="attribute">linkend</sgmltag>
+attribute points to a <sgmltag>src:fragment</sgmltag> element.</para>
+
+<para>FIXME: this code should test the namespace name of the $fragment</para>
+
+<src:fragment id="fragref-isfragment">
+<xsl:if test="local-name($fragment) != 'fragment'">
+  <xsl:message terminate="yes">
+    <xsl:text>Link "</xsl:text>
+    <xsl:value-of select="@linkend"/>
+    <xsl:text>" does not point to a src:fragment.</xsl:text>
+  </xsl:message>
+</xsl:if>
+</src:fragment>
+</section>
+</section>
+</section>
+
+<section><title>Copying Disable-Output-Escaping Fragment References</title>
+
+<para>A <sgmltag>src:fragref</sgmltag> that specifies
+<sgmltag class="attribute">disable-output-escaping</sgmltag> is treated
+essentially as if it was
+<link linkend="s.copy-default">any other element</link>. The only
+exception is that the
+<sgmltag class="attribute">disable-output-escaping</sgmltag> attribute
+is not copied.</para>
+
+<para>Because <application>tangle</application> and
+<application>weave</application> are XSLT stylesheets that process
+XSLT stylesheets, processing <sgmltag>src:fragref</sgmltag> poses
+a unique challenge.</para>
+
+<para>In ordinary <application>tangle</application> processing, they
+are expanded and replaced with the content of the fragment that they
+point to. But when <filename>weave.xweb</filename> is tangled, they
+must be copied through literally. The
+<sgmltag class="attribute">disable-output-escaping</sgmltag> attribute
+provides the hook that allows this.
+</para>
+
+<src:fragment id="doe-fragref">
     <xsl:when test="@disable-output-escaping='yes'">
-      <xsl:element name="{name(.)}" namespace="namespace-uri(.)">
-        <xsl:for-each select="namespace::*">
-          <xsl:if test="string(.) != namespace-uri($node)">
-            <xsl:copy/>
-          </xsl:if>
-        </xsl:for-each>
+      <xsl:element name="{name(.)}" namespace="{namespace-uri(.)}">
+        <src:fragref linkend="copy-namespaces"/>
         <xsl:for-each select="@*">
           <xsl:if test="not(name(.) = 'disable-output-escaping')">
             <xsl:copy/>
         </xsl:for-each>
         <xsl:apply-templates mode="copy"/>
       </xsl:element>
-    </xsl:when>
-    <xsl:otherwise>
-      <xsl:variable name="linkend" select="@linkend"/>
-      <xsl:variable name="fragment" select="//src:fragment[@id=$linkend]"/>
-      <xsl:apply-templates select="$fragment"/>
-    </xsl:otherwise>
-  </xsl:choose>
+    </xsl:when></src:fragment>
+</section>
+
+<section id="s.copy-default">
+<title>Copying Everything Else</title>
+
+<para>Everything else is copied verbatim. This is a five step process:
+</para>
+
+<orderedlist>
+<listitem><para>Save a copy of the context node in
+<literal>$node</literal> so that we can refer to it later from
+inside an <sgmltag>xsl:for-each</sgmltag>.</para>
+</listitem>
+<listitem><para>Construct a new node in the result tree with
+the same qualified name and namespace as the context node.</para>
+</listitem>
+<listitem><para>Copy the namespace nodes on the context node to the
+new node in the result tree. We must do this manually because the
+&xweb; file may have broken the content of this element into several
+separate fragments. Breaking things into separate fragments makes it
+impossible for the XSLT processor to always construct the right namespace
+nodes automatically.</para>
+</listitem>
+<listitem><para>Copy the attributes.
+</para></listitem>
+<listitem><para>Copy the children.
+</para></listitem>
+</orderedlist>
+
+<src:fragment id="copy-default">
+<xsl:template match="*" mode="copy">
+  <xsl:variable name="node" select="."/>
+  <xsl:element name="{name(.)}" namespace="{namespace-uri(.)}">
+    <src:fragref linkend="copy-namespaces"/>
+    <xsl:copy-of select="@*"/>
+    <xsl:apply-templates mode="copy"/>
+  </xsl:element>
+</xsl:template>
+</src:fragment>
+
+<para>For non-XML source docuements, this template will never match
+because there will be no XML elements in the source fragments.</para>
+
+<section><title>Copy Namespaces</title>
+
+<para>Copying the namespaces is a simple loop over the elements on
+the <literal>namespace</literal> axis, with one wrinkle.</para>
+
+<para>It is an error to copy a namespace node onto an element if a
+namespace node is already present for that namespace.  The fact that
+we're running this loop in a context where we've constructed the
+result node explicitly in the correct namespace means that attempting
+to copy that namespace node again will produce an error. We work
+around this problem by explicitly testing for that namespace and not
+copying it.
+</para>
+
+<src:fragment id="copy-namespaces">
+  <xsl:for-each select="namespace::*">
+    <xsl:if test="string(.) != namespace-uri($node)">
+      <xsl:copy/>
+    </xsl:if>
+  </xsl:for-each>
+</src:fragment>
+
+</section>
+</section>
+</section>
+
+<section><title>Copy XML Constructs</title>
+
+<para>In the <filename>xtangle.xsl</filename> stylesheet, we also want
+to preserve XML constructs (processing instructions and comments) that
+we encounter in the fragments.</para>
+
+<para>Note that many implementations of XSLT do not provide comments in
+the source document (they are discarded before building the tree), in which
+case the comments cannot be preserved.</para>
+
+<src:fragment id="copy-xml-constructs">
+<xsl:template match="processing-instruction()" mode="copy">
+  <xsl:processing-instruction name='{name(.)}'>
+    <xsl:value-of select="."/>
+  </xsl:processing-instruction>
 </xsl:template>
 
-<xsl:template match="src:comment" mode="copy">
+<xsl:template match="comment()" mode="copy">
   <xsl:comment>
     <xsl:value-of select="."/>
   </xsl:comment>
 </xsl:template>
 </src:fragment>
+
 </section>
+
 </article>
 
index 4ab4dfbf01e4672d4a8edceb9a9f3e6043b432f5..9be98082fd933b34fbb098653a026e9ade306fa1 100644 (file)
+<!DOCTYPE article [
+<!ENTITY xweb "<acronym>XWEB</acronym>">
+<!ENTITY lt    "&#38;#60;"> <!-- LESS-THAN SIGN -->
+<!ENTITY gt    "&#x003E;"> <!-- GREATER-THAN SIGN -->
+<!ENTITY amp   "&#38;#38;"> <!-- AMPERSAND -->
+]>
 <article xmlns:src="http://nwalsh.com/xmlns/litprog/fragment"
          xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
-<title>Weave.xsl</title>
+<articleinfo>
+<title>Weave</title>
+<subtitle>Part of
+<citetitle>Literate Programming in XML</citetitle></subtitle>
+<pubdate>05 Oct 2001</pubdate>
+<releaseinfo role="meta">
+$Id$
+</releaseinfo>
 
-<src:topfragment id="top" default-exclude-result-prefixes="xsl">
-<src:passthrough>
-&lt;!DOCTYPE xsl:stylesheet [
-&lt;!ENTITY nl "&lt;xsl:text>&#xA;&lt;/xsl:text>">
-]>
-</src:passthrough>
+<revhistory>
+<revision>
+<revnumber>0.1</revnumber>
+<date>05 Oct 2001</date>
+<authorinitials>ndw</authorinitials>
+<revremark>Initial draft.</revremark>
+</revision>
+</revhistory>
+
+<author><firstname>Norman</firstname><surname>Walsh</surname>
+</author>
+</articleinfo>
+
+<!-- ============================================================ -->
+
+<para>The <filename>weave.xsl</filename> stylesheet transforms an
+&xweb; document into a <quote>documentation</quote> document. This
+is accomplished by <quote>weaving</quote> the documentation from
+the &xweb; file with a pretty-printed version of the source code.</para>
+
+<para>The resulting document is ready to be processed by whatever
+down-stream publishing tools are appropriate.</para>
+
+<section><title>The Stylesheet</title>
+
+<para>The stylesheet performs some initialization, begins processing
+at the root of the &xweb; document, and processes fragments and
+elements. This stylesheet also requires some recursive templates that
+are stored at the end of the stylesheet.</para>
+
+<src:fragment id="top" mundane-result-prefixes="xsl">
 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                 xmlns:src="http://nwalsh.com/xmlns/litprog/fragment"
                 exclude-result-prefixes="xsl src xml"
                 version="1.0">
+  <src:fragref linkend="init"/>
+  <src:fragref linkend="root.template"/>
+  <src:fragref linkend="doc.content"/>
+  <src:fragref linkend="fragments"/>
+  <src:fragref linkend="copy-elements"/>
+  <src:fragref linkend="named-templates"/>
+</xsl:stylesheet>
+</src:fragment>
 
-  <xsl:include href="VERSION"/>
+<section><title>Initialization</title>
 
-  <src:fragref linkend="space"/>
+<para>The stylesheet initializes the processor by loading its version
+information (stored in a separate file because it is shared by several
+stylesheets), telling the processor to preserve whitespace on all
+input elements, setting the output method, and initializing
+the excluded result prefixes.</para>
+
+<para>The stylesheet also constructs a key for the ID values used on
+fragments. Because &xweb; documents do not have to be valid according
+to any particular DTD or Schema, the stylesheet cannot rely on having
+the IDs identified as type ID in the source document.</para>
+
+<src:fragment id="init">
+  <xsl:include href="VERSION"/>
+  <xsl:preserve-space elements="*"/>
+  <xsl:output method="xml"/>
   <src:fragref linkend="param.ex.result.prefixes"/>
-  <src:fragref linkend="root.template"/>
-  <src:fragref linkend="default.template"/>
-  <src:fragref linkend="topfragment"/>
-  <src:fragref linkend="fragment"/>
 
-  <src:fragref linkend="rest"/>
-</xsl:stylesheet>
-</src:topfragment>
+  <xsl:key name="fragment" match="src:fragment" use="@id"/>
 
-<section><title>Whitespace Control</title>
+  <xsl:param name="top" select="'top'"/>
+</src:fragment>
 
-<src:fragment id="space">
-<xsl:preserve-space elements="*"/>
+<section id="s.param.ex.result.prefixes">
+<title>Default Exclude Result Prefixes</title>
+
+<para>Generally, the namespace declarations for namespaces used by
+the source code portion of the &xweb; file are not needed in the
+<quote>woven</quote> documentation. To reduce the size of the documentation
+file, and to reduce the clutter of unnecessary declarations, you can
+specify prefixes that should be excluded.</para>
+
+<para>This is done as a parameter so that it can be adjusted dynamically,
+though it rarely needs to be. The initial value comes from the
+<sgmltag class="attribute">mundane-result-prefixes</sgmltag>
+attribute on the &xweb; file's top <sgmltag>src:fragment</sgmltag>.</para>
+
+<src:fragment id="param.ex.result.prefixes">
+<xsl:param name="mundane-result-prefixes"
+    select="key('fragment',$top)/@mundane-result-prefixes"/>
 </src:fragment>
 
+</section>
 </section>
 
-<section><title>Default Exclude Result Prefixes</title>
+<section><title>Named Templates</title>
 
-<src:fragment id="param.ex.result.prefixes">
-<xsl:param name="default-exclude-result-prefixes"
-           select="//src:topfragment/@default-exclude-result-prefixes"/>
+<para>Correctly copying elements requires the ability to calculate
+applicable namespaces and output the appropriate namespace psuedo-attributes
+and attributes. These templates accomplish those tasks.</para>
+
+<src:fragment id="named-templates">
+  <src:fragref linkend="count.applicable.namespaces"/>
+  <src:fragref linkend="output.applicable.namespaces"/>
+  <src:fragref linkend="output.applicable.attributes"/>
+  <src:fragref linkend="indent"/>
+  <src:fragref linkend="spaces"/>
+  <src:fragref linkend="trailing-space-chars"/>
 </src:fragment>
+</section>
 
 </section>
+
 <section><title>Root Template</title>
 
+<para>The root template begins processing at the root of the &xweb;
+document. It outputs a couple of informative comments and then
+processes the document.</para>
+
+<para>Source code fragments in the &xweb; document are not required
+to be sequential, we assume that they appear in the order in which
+they should be documented.</para>
+
 <src:fragment id="root.template">
 <xsl:template match="/">
   <xsl:text>&#xA;</xsl:text>
 </src:fragment>
 
 </section>
-<section><title>Default Template</title>
 
-<src:fragment id="default.template">
-<xsl:template match="*">
-  <xsl:variable name="node" select="."/>
-  <xsl:element name="{name(.)}" namespace="{namespace-uri(.)}">
-    <xsl:for-each select="namespace::*">
-      <xsl:if test="string(.) != namespace-uri($node)">
-        <xsl:copy/>
-      </xsl:if>
-    </xsl:for-each>
-    <xsl:copy-of select="@*"/>
-    <xsl:apply-templates/>
-  </xsl:element>
+<section><title>Fragments</title>
+
+<para>The goal when copying the source code fragments
+is to preserve the <sgmltag>src:fragment</sgmltag>
+elements in the documentation file (so that they can be formatted
+appropriately) but to escape all of the fragment content so that
+it appears simply as <quote>text</quote> in the documentation.</para>
+
+<para>For example, if the following fragment appears in the &xweb; file:
+</para>
+
+<screen>&lt;src:fragment id="foo"&gt;
+  &lt;emphasis&gt;some code&lt;/emphasis&gt;
+&lt;/src:fragment&gt;</screen>
+
+<para>the documentation must contain:</para>
+
+<screen>&lt;src:fragment id="foo"&gt;
+  &amp;lt;emphasis&amp;gt;some code&amp;lt;/emphasis&amp;gt;
+&lt;/src:fragment&gt;</screen>
+
+<para>The significance of this escaping is less obvious when the
+fragment contains non-XML code, but it is in fact still relevant.</para>
+
+<para>This task is accomplished by constructing a literal
+<sgmltag>src:fragment</sgmltag> element and then copying the content
+of the source document's <sgmltag>src:fragment</sgmltag> element
+in a mode that escapes all markup characters.</para>
+
+<src:fragment id="fragments">
+<xsl:template match="src:fragment">
+  <src:fragment id="{@id}">
+    <xsl:call-template name="copy-content"/>
+  </src:fragment>
+</xsl:template>
+
+<src:fragref linkend="copy-content"/>
+
+</src:fragment>
+
+<section><title>Copying Content</title>
+
+<para>The <quote><literal>copy-content</literal></quote> template
+could be as simple as:</para>
+
+<screen
+>&lt;xsl:apply-templates mode="copy"/&gt;</screen>
+
+<para>but we play one more trick for the convenience of &xweb; authors.
+</para>
+
+<para>It's convenient for authors to use newlines at the beginning
+and end of each program fragment, producing fragments that look like
+the one shown above. The problem is that white space is significant
+inside fragments, so the resulting documenation will contain a listing
+like this:</para>
+
+<screen>  1 |
+  2 |   &lt;emphasis&gt;some code&lt;/emphasis&gt;
+  3 |</screen>
+
+<para>The leading and trailing blank lines in this listing are distracting
+and almost certainly insignificant. Authors can avoid this problem by
+removing the offending newlines:</para>
+
+<screen>&lt;src:fragment id="foo"&gt;&lt;emphasis&gt;some code&lt;/emphasis&gt;&lt;/src:fragment&gt;</screen>
+
+<para>but this makes the source document more difficult to read and
+introduces tedious cut-and-paste problems. To avoid this problem, the
+<quote><literal>copy-content</literal></quote> template takes special
+pains to trim off one optional leading newline and one optional
+trailing newline. It does this by dealing with the first, last, and
+middle nodes of the <sgmltag>src:fragment</sgmltag> elements
+separately:</para>
+
+<src:fragment id="copy-content">
+<xsl:template name="copy-content">
+  <src:fragref linkend="cc-storevars"/>
+  <src:fragref linkend="cc-first-node"/>
+  <src:fragref linkend="cc-middle-nodes"/>
+  <src:fragref linkend="cc-last-node"/>
 </xsl:template>
 </src:fragment>
 
+<section><title>Convenience Variables</title>
+
+<para>For convenience, we store subexpressions containing the first,
+last, and all the middle nodes in variables.</para>
+
+<src:fragment id="cc-storevars">
+  <xsl:variable name="first-node"
+                select="node()[1]"/>
+  <xsl:variable name="middle-nodes"
+                select="node()[position() &gt; 1 and position() &lt; last()]"/>
+  <xsl:variable name="last-node"
+                select="node()[position() &gt; 1 and position() = last()]"/>
+</src:fragment>
+
 </section>
-<section><title>Fragments</title>
 
-<src:fragment id="topfragment">
-<xsl:template match="src:topfragment">
-  <src:fragment id="{@id}">
+<section><title>Handle First Node</title>
+
+<para>Handling the leading newline is conceptually a simple matter of
+looking at the first character on the line and skipping it if it is
+a newline. A slight complexity is introduced by the fact that if the
+fragment contains only a single text node, the first node is also the
+last node and we have to possibly trim off a trialing newline as well.
+We separate that out as a special case.
+</para>
+
+<src:fragment id="cc-first-node">
     <xsl:choose>
-      <xsl:when test="node()[1] = '&#xA;'">
-        <xsl:apply-templates select="node()[position()&gt;1 and position()&lt;last()]" mode="copy"/>
+      <src:fragref linkend="cc-only-node"/>
+      <src:fragref linkend="cc-leading-nl"/>
+      <src:fragref linkend="cc-no-leading-nl"/>
+    </xsl:choose>
+</src:fragment>
+
+<section><title>Handle A Fragment that Contains a Single Node</title>
+
+<para>If the <varname>$first-node</varname> is a text node and the
+fragment contains only a single child, then it is also the last node.</para>
+
+<para>In order to deal with a single text node child, we must address
+four cases: the node has both leading and trailing newlines, the node
+has only leading newlines, only trailing newlines, or no newlines at
+all.</para>
+
+<src:fragment id="cc-only-node">
+      <xsl:when test="$first-node = text() and count(node()) = 1">
+        <src:fragref linkend="cc-more-conv"/>
+        <xsl:choose>
+          <src:fragref linkend="cc-both"/>
+          <src:fragref linkend="cc-leading"/>
+          <src:fragref linkend="cc-trailing"/>
+          <src:fragref linkend="cc-none"/>
+        </xsl:choose>
       </xsl:when>
+</src:fragment>
+
+<section><title>More Convenience Variables</title>
+
+<para>For convenience, we calculate whether or not the node in question
+has leading and/or trailing newlines and store those results in variables.
+</para>
+
+<src:fragment id="cc-more-conv">
+        <xsl:variable name="leading-nl"
+                      select="substring($first-node, 1, 1) = '&#xA;'"/>
+        <xsl:variable name="trailing-nl"
+                      select="substring($first-node, string-length($first-node), 1) = '&#xA;'"/>
+</src:fragment>
+</section>
+
+<section><title>Handle a Single Node With Leading and Trailing Newlines</title>
+
+<para>If the node has both leading and trailing newlines, trim a character
+off each end.</para>
+
+<src:fragment id="cc-both">
+          <xsl:when test="$leading-nl and $trailing-nl">
+            <xsl:value-of select="substring($first-node, 2, string-length($first-node)-2)"/>
+          </xsl:when>
+</src:fragment>
+</section>
+
+<section><title>Handle a Single Node With Only Leading Newlines</title>
+
+<para>If the node has only leading newlines, trim off the first character.
+</para>
+
+<src:fragment id="cc-leading">
+          <xsl:when test="$leading-nl">
+            <xsl:value-of select="substring($first-node, 2)"/>
+          </xsl:when>
+</src:fragment>
+</section>
+
+<section><title>Handle a Single Node with Only Trailing Newlines</title>
+
+<para>If the node has only trailing newlines, trim off the last character.
+</para>
+
+<src:fragment id="cc-trailing">
+          <xsl:when test="$trailing-nl">
+            <xsl:value-of select="substring($first-node, 1, string-length($first-node)-1)"/>
+          </xsl:when>
+</src:fragment>
+</section>
+
+<section><title>Handle a Single Node with No Newlines</title>
+
+<para>Otherwise, the node has no newlines and it is simply printed.
+</para>
+
+<src:fragment id="cc-none">
+          <xsl:otherwise>
+            <xsl:value-of select="$first-node"/>
+          </xsl:otherwise>
+</src:fragment>
+</section>
+</section>
+
+<section><title>Handle a First Node with a Leading Newline</title>
+
+<para>If the first node is a text node and begins with a newline,
+trim off the first character.</para>
+
+<src:fragment id="cc-leading-nl">
+      <xsl:when test="$first-node = text() and substring($first-node, 1, 1) = '&#xA;'">
+        <xsl:value-of select="substring($first-node, 2)"/>
+      </xsl:when>
+</src:fragment>
+</section>
+
+<section><title>Handle a First Node without a Leading Newline</title>
+
+<para>Otherwise, the first node is not a text node or does not begin
+with a newline, so use the <quote>copy</quote> mode to copy it to
+the result tree.</para>
+
+<src:fragment id="cc-no-leading-nl">
       <xsl:otherwise>
-        <xsl:apply-templates select="node()[position()&lt;last()]" mode="copy"/>
+        <xsl:apply-templates select="$first-node" mode="copy"/>
       </xsl:otherwise>
-    </xsl:choose>
-  </src:fragment>
-</xsl:template>
 </src:fragment>
+</section>
+</section>
 
-<src:fragment id="fragment">
-<xsl:template match="src:fragment">
-  <src:fragment id="{@id}">
+<section><title>Handle Last Node</title>
+
+<para>Handling the last node is roughly analagous to handling the first
+node, except that we know this code is only evaluated if the last node
+is not also the first node.</para>
+
+<para>If the last node is a text node and ends with a newline, strip
+it off. Otherwise, just copy the content of the last node
+using the <quote>copy</quote> mode.
+</para>
+
+<src:fragment id="cc-last-node">
     <xsl:choose>
-      <xsl:when test="node()[1] = '&#xA;'">
-        <xsl:apply-templates select="node()[position()&gt;1]" mode="copy"/>
+      <xsl:when test="$last-node = text() and substring($last-node, string-length($last-node), 1) = '&#xA;'">
+        <xsl:value-of select="substring($last-node, 1, string-length($last-node)-1)"/>
       </xsl:when>
       <xsl:otherwise>
-        <xsl:apply-templates select="node()" mode="copy"/>
+        <xsl:apply-templates select="$last-node" mode="copy"/>
       </xsl:otherwise>
     </xsl:choose>
-  </src:fragment>
-</xsl:template>
 </src:fragment>
 
 </section>
-<section><title>Rest</title>
 
-<src:fragment id="rest">
+<section><title>Handle the Middle Nodes</title>
 
-<!-- ============================================================ -->
+<para>The middle nodes are easy, just copy them
+using the <quote>copy</quote> mode.</para>
+
+<src:fragment id="cc-middle-nodes">
+    <xsl:apply-templates select="$middle-nodes" mode="copy"/>
+</src:fragment>
+
+</section>
+</section>
+</section>
+
+<section><title>Fragment References</title>
 
-<xsl:template match="src:fragref">
-  <xsl:variable name="linkend" select="@linkend"/>
+<para>Fragment references, like fragments, are simply copied to the
+documentation file. The use of
+<sgmltag class="attribute">disable-output-escaping</sgmltag> is
+unique to this template (it instructs the <quote>tangle</quote>
+stylesheet to make a literal copy of the <sgmltag>src:fragref</sgmltag>,
+rather than expanding it, as it usually would).</para>
+
+<src:fragment id="fragref"><xsl:template match="src:fragref">
   <src:fragref linkend="{@linkend}" disable-output-escaping="yes">
     <xsl:apply-templates/>
   </src:fragref>
 </xsl:template>
+</src:fragment>
 
-<!-- ============================================================ -->
+<section><title>Copying Elements</title>
+
+<para>Copying elements to the result tree can be divided into four
+cases: <link linkend="s.copy-passthrough">copying passthrough elements</link>,
+<link linkend="s.copy-fragref">copying fragment references</link> and
+<link linkend="s.copy-default">copying everything else</link>.</para>
+
+<src:fragment id="copy-elements">
+<src:fragref linkend="copy-passthrough"/>
+<src:fragref linkend="copy-fragref"/>
+<src:fragref linkend="copy-default"/>
+</src:fragment>
+
+<section id="s.copy-passthrough">
+<title>Copying <sgmltag>src:passthrough</sgmltag></title>
+
+<para>Passthrough elements contain text that is intended to appear
+literally in the result tree. We simply copy it through.
+</para>
+
+<src:fragment id="copy-passthrough">
+<xsl:template match="src:passthrough" mode="copy" priority="3">
+  <xsl:apply-templates select="node()|@*" mode="copy"/>
+</xsl:template>
+</src:fragment>
+</section>
+
+<section id="s.copy-fragref">
+<title>Copying <sgmltag>src:fragref</sgmltag></title>
+
+<para>Because <application>tangle</application> and
+<application>weave</application> are XSLT stylesheets that process
+XSLT stylesheets, processing <sgmltag>src:fragref</sgmltag> poses
+a unique challenge.</para>
+
+<para>In ordinary <application>tangle</application> processing, they
+are expanded and replaced with the content of the fragment that they
+point to. But when <filename>weave.xweb</filename> is tangled, they
+must be copied through literally. The
+<sgmltag class="attribute">disable-output-escaping</sgmltag> attribute
+provides the hook that allows this.
+</para>
+
+<para>When we're weaving, if the
+<sgmltag class="attribute">disable-output-escaping</sgmltag> attribute
+is <quote>yes</quote>, the <sgmltag>src:fragref</sgmltag> is treated literally.
+When it isn't, the element is copied through literally.</para>
+
+<src:fragment id="copy-fragref">
+<xsl:template match="src:fragref" mode="copy" priority="3">
+  <xsl:choose>
+    <xsl:when test="@disable-output-escaping='yes'">
+      <xsl:text>&lt;src:fragref linkend="</xsl:text>
+      <xsl:value-of select="@linkend"/>
+      <xsl:text>"/&gt;</xsl:text>
+      <xsl:apply-templates mode="copy"/>
+      <xsl:text>&lt;/src:fragref&gt;</xsl:text>
+    </xsl:when>
+    <xsl:otherwise>
+      <src:fragref linkend="{@linkend}" disable-output-escaping="yes"/>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+</src:fragment>
+</section>
+
+<section id="s.copy-default">
+<title>Copying Everything Else</title>
+
+<para>There are two kinds of everything else: elements and other
+nodes.</para>
+
+<src:fragment id="copy-default">
+<src:fragref linkend="copy-default-elements"/>
+<src:fragref linkend="copy-default-nodes"/>
+</src:fragment>
+
+<para>This element template is quite complex, but it's goal is simple:
+to translate bona-fide elements in the source document into text in
+the result document. In other words, where the element
+<quote><literal>&lt;foo&gt;</literal></quote> occurs in the source
+document, the result document should contain
+<quote><literal>&amp;lt;foo&amp;gt;</literal></quote>.</para>
+
+<para>Three things make this tricky:</para>
+
+<orderedlist>
+<listitem><para>Elements in the source documents may have namespace
+nodes associated with them that are not explicitly declared on them.
+To the best of our ability, we must avoid copying these namespace
+nodes to the result tree.
+</para></listitem>
+<listitem><para>Attributes must be copied and formatted in some reasonable
+way in order to avoid excessively long lines in the documentation.
+</para></listitem>
+<listitem><para>Empty elements must be printed using the appropriate
+empty-element syntax. (It is simply impossible to determine what syntax
+was used in the source document, the best we can do is always use the
+empty-element syntax in the result as it is likely to be more common
+in the soruce.)
+</para></listitem>
+</orderedlist>
+
+<para>The plan of attack is:</para>
+
+<itemizedlist>
+<listitem><para>Calculate what namespaces should be excluded (by prefix).
+</para></listitem>
+<listitem><para>Calculate the applicable namespaces.
+</para></listitem>
+<listitem><para>Output the leading <quote>&lt;</quote> and the element
+name.
+</para></listitem>
+<listitem><para>Output the applicable namespaces.
+</para></listitem>
+<listitem><para>Output the attributes.
+</para></listitem>
+<listitem><para>If the element is not empty, finish the start tag,
+copy the element contents, and output and end tag. If the element is
+empty, finish the start tag with the empty-element syntax.
+</para></listitem>
+</itemizedlist>
+
+<src:fragment id="copy-default-elements">
+<xsl:template match="processing-instruction()" mode="copy" priority="2">
+  <xsl:text>&lt;?</xsl:text>
+  <xsl:value-of select="name(.)"/>
+  <xsl:value-of select="."/>
+  <xsl:text>?&gt;</xsl:text>
+</xsl:template>
+
+<xsl:template match="comment()" mode="copy" priority="2">
+  <xsl:text>&lt;!--</xsl:text>
+  <xsl:value-of select="."/>
+  <xsl:text>--&gt;</xsl:text>
+</xsl:template>
 
 <xsl:template match="*" mode="copy" priority="2">
-  <xsl:variable name="name" select="name(.)"/>
-  <xsl:variable name="prevtext" select="preceding-sibling::text()"/>
   <xsl:variable name="exclude">
-    <xsl:choose>
-      <xsl:when test="ancestor::src:fragment/@exclude-result-prefixes">
-        <xsl:value-of select="concat(' xml ',
-                              ancestor::src:fragment/@exclude-result-prefixes,
-                              ' ')"/>
-      </xsl:when>
-      <xsl:when test="ancestor::src:topfragment">
-        <xsl:value-of select="concat(' xml ',
-                              ancestor::src:top-fragment/@exclude-result-prefixes,
-                              ' ')"/>
-      </xsl:when>
-      <xsl:otherwise>
-        <xsl:value-of select="concat(' xml ',
-                              $default-exclude-result-prefixes,
-                              ' ')"/>
-      </xsl:otherwise>
-    </xsl:choose>
+    <src:fragref linkend="calculate-excluded-prefixes"/>
   </xsl:variable>
 
-  <xsl:text>&lt;</xsl:text>
-  <xsl:value-of select="name(.)"/>
-
   <xsl:variable name="applicable.namespaces">
     <xsl:call-template name="count.applicable.namespaces">
       <xsl:with-param name="namespaces" select="namespace::*"/>
     </xsl:call-template>
   </xsl:variable>
 
+  <xsl:text>&lt;</xsl:text>
+  <xsl:value-of select="name(.)"/>
+
   <xsl:if test="$applicable.namespaces &gt; 0">
     <xsl:call-template name="output.applicable.namespaces">
       <xsl:with-param name="namespaces" select="namespace::*"/>
     </xsl:call-template>
   </xsl:if>
 
-  <xsl:choose>
-    <xsl:when test="$applicable.namespaces &gt; 0">
-      <xsl:call-template name="output.applicable.attributes">
-        <xsl:with-param name="attributes" select="attribute::*"/>
-        <xsl:with-param name="first" select="'0'"/>
-      </xsl:call-template>
-    </xsl:when>
-    <xsl:otherwise>
-      <xsl:call-template name="output.applicable.attributes">
-        <xsl:with-param name="attributes" select="attribute::*"/>
-      </xsl:call-template>
-    </xsl:otherwise>
-  </xsl:choose>
+  <src:fragref linkend="output.attributes"/>
 
   <xsl:choose>
     <xsl:when test="node()">
     </xsl:otherwise>
   </xsl:choose>
 </xsl:template>
+</src:fragment>
 
-<xsl:template match="src:passthrough" mode="copy" priority="3">
-  <xsl:apply-templates select="node()|@*" mode="copy"/>
-</xsl:template>
+<para>The preceding template handles elements. Everything else is simply
+copied.</para>
 
-<xsl:template match="src:comment" mode="copy" priority="3">
-  <xsl:text>&lt;!--</xsl:text>
-    <xsl:apply-templates select="node()|@*" mode="copy"/>
-  <xsl:text>--&gt;</xsl:text>
+<src:fragment id="copy-default-nodes">
+<xsl:template match="node()|@*" mode="copy">
+  <xsl:copy>
+    <xsl:apply-templates select="@*|node()" mode="copy"/>
+  </xsl:copy>
 </xsl:template>
+</src:fragment>
 
-<xsl:template match="src:fragref" mode="copy" priority="3">
-  <xsl:variable name="linkend" select="@linkend"/>
+<section><title>Calculate Excluded Prefixes</title>
+
+<para>Calculating the excluded prefixes requires evaluating the following
+conditions:</para>
+
+<orderedlist>
+<listitem><para>If the element we are copying is inside a
+<sgmltag>src:fragment</sgmltag> element that specifies a set of
+<sgmltag class="attribute">exclude-result-prefixes</sgmltag>, use
+those prefixes.
+</para></listitem>
+<listitem><para>Otherwise, use the
+<varname>$mundane-result-prefixes</varname> we
+<link linkend="s.param.ex.result.prefixes">calculated earlier</link>.
+</para></listitem>
+</orderedlist>
+
+<para>Note that in every case we exclude the namespace associated
+with <quote><literal>xml</literal></quote>.</para>
+
+<src:fragment id="calculate-excluded-prefixes">
+    <xsl:choose>
+      <xsl:when test="ancestor::src:fragment/@exclude-result-prefixes">
+        <xsl:value-of select="concat(' xml ',
+                              ancestor::src:fragment/@exclude-result-prefixes,
+                              ' ')"/>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:value-of select="concat(' xml ',
+                              $mundane-result-prefixes,
+                              ' ')"/>
+      </xsl:otherwise>
+    </xsl:choose>
+</src:fragment>
+</section>
+
+<section><title>Output Attributes</title>
+
+<para>The mechanics of outputting the applicable attributes is
+described in <xref linkend="s.output.atts"/>. The
+only wrinkle here is that if we have already output
+<quote><literal>xmlns</literal></quote> declarations for namespaces,
+the first real attribute is not really the first thing that looks
+like an attribute in the result.</para>
+
+<src:fragment id="output.attributes">
   <xsl:choose>
-    <xsl:when test="@disable-output-escaping='yes'">
-      <xsl:text>&lt;src:fragref linkend="</xsl:text>
-      <xsl:value-of select="@linkend"/>
-      <xsl:text>"/&gt;</xsl:text>
-      <xsl:apply-templates mode="copy"/>
-      <xsl:text>&lt;/src:fragref&gt;</xsl:text>
+    <xsl:when test="$applicable.namespaces &gt; 0">
+      <xsl:call-template name="output.applicable.attributes">
+        <xsl:with-param name="attributes" select="attribute::*"/>
+        <xsl:with-param name="first" select="'0'"/>
+      </xsl:call-template>
     </xsl:when>
     <xsl:otherwise>
-      <xref linkend="{@linkend}"/>
+      <xsl:call-template name="output.applicable.attributes">
+        <xsl:with-param name="attributes" select="attribute::*"/>
+      </xsl:call-template>
     </xsl:otherwise>
   </xsl:choose>
-</xsl:template>
+</src:fragment>
+</section>
+</section>
+</section>
 
-<xsl:template name="indent">
-  <xsl:param name="name" select="name(.)"/>
-  <xsl:param name="prevtext" select="preceding-sibling::text()"/>
+<section><title>Count Applicable Namespaces</title>
 
-  <xsl:variable name="namelen" select="string-length($name)"/>
-  <xsl:call-template name="spaces">
-    <xsl:with-param name="count" select="$namelen + 1"/>
-  </xsl:call-template>
-</xsl:template>
+<para>The applicable namespaces are determined by walking recursively
+over the list of namespace nodes associated with an element.</para>
 
-<xsl:template name="spaces">
-  <xsl:param name="count" select="'0'"/>
-  <xsl:if test="$count &gt; 0">
-    <xsl:text> </xsl:text>
-    <xsl:call-template name="spaces">
-      <xsl:with-param name="count" select="$count - 1"/>
-    </xsl:call-template>
-  </xsl:if>
-</xsl:template>
+<para>For each namespace node, if it has a prefix that is in the list
+of excluded prefixes or if it is the Literate Programming namespace,
+it is not counted (because it will not be output). Otherwise, it is
+counted.</para>
 
+<para>The recursion bottoms out when the list of namespace nodes has
+been exhausted. The total number of counted namespaces is then
+returned.</para>
+
+<src:fragment id="count.applicable.namespaces">
 <xsl:template name="count.applicable.namespaces">
   <xsl:param name="namespaces" select="namespace::*"/>
   <xsl:param name="exclude-prefixes" select="''"/>
              select="'http://nwalsh.com/xmlns/litprog/fragment'"/>
   <xsl:param name="count" select="'0'"/>
 
-<!--
-  <xsl:message>
-    <xsl:text>ns: </xsl:text>
-    <xsl:value-of select="name(.)"/>
-    <xsl:text> </xsl:text>
-    <xsl:value-of select="$count"/>
-    <xsl:text> </xsl:text>
-    <xsl:value-of select="count($namespaces)"/>
-    <xsl:text> </xsl:text>
-    <xsl:value-of select="name($namespaces[1])"/>
-    <xsl:text>=</xsl:text>
-    <xsl:value-of select="$namespaces[1]"/>
-    <xsl:choose>
-      <xsl:when test="not(contains($exclude-prefixes, name($namespaces[1]))
-                      or ($namespaces[1] = $exclude-uri))"> 1</xsl:when>
-      <xsl:otherwise> 0</xsl:otherwise>
-    </xsl:choose>
-  </xsl:message>
--->
-
   <xsl:choose>
     <xsl:when test="count($namespaces) = 0">
       <xsl:value-of select="$count"/>
     </xsl:otherwise>
   </xsl:choose>
 </xsl:template>
+</src:fragment>
+</section>
+
+<section id="s.output.atts">
+<title>Output Applicable Attributes and Pseudo-Attributes</title>
+
+<para>Outputing the attributes (or namespace psuedo-attributes) is
+straightforward, the only tricky part is pretty-printing the resulting
+document.</para>
+
+<para>Pretty-printing has three cases:</para>
+
+<orderedlist>
+<listitem><para>Before outputting the very first
+attribute or psuedo-attribute, we want to output only a single space,
+to separate the result from the preceding element name.
+</para></listitem>
+<listitem><para>Before outputting any additional attribute or
+psuedo-attribute, we want to output a line-feed and then indent the
+result appropriately. This prevents the attributes and psuedo-attributes
+from appearing as one huge, long line in the result.
+</para></listitem>
+<listitem><para>If the element has no attributes or psuedo attributes,
+we don't want to output anything; we want the closing tag delimiter
+to appear immediately after the element name.
+</para></listitem>
+</orderedlist>
 
+<section><title>Output Applicable Namespaces</title>
+
+<para>The applicable namespaces are determined by walking recursively
+over the list of namespace nodes associated with an element.</para>
+
+<para>For each namespace node, if it has a prefix that is in the list
+of excluded prefixes or if it is the Literate Programming namespace,
+it is not output, otherwise, it is.</para>
+
+<para>The recursion bottoms out when the list of namespace nodes has
+been exhausted.</para>
+
+<src:fragment id="output.applicable.namespaces">
 <xsl:template name="output.applicable.namespaces">
   <xsl:param name="namespaces" select="namespace::*"/>
   <xsl:param name="exclude-prefixes" select="''"/>
              select="'http://nwalsh.com/xmlns/litprog/fragment'"/>
   <xsl:param name="first" select="'1'"/>
 
-<!--
-  <xsl:message>
-    <xsl:text>ons: </xsl:text>
-    <xsl:value-of select="name(.)"/>
-    <xsl:text> </xsl:text>
-    <xsl:value-of select="$first"/>
-    <xsl:text> </xsl:text>
-    <xsl:value-of select="count($namespaces)"/>
-    <xsl:text> </xsl:text>
-    <xsl:value-of select="name($namespaces[1])"/>
-    <xsl:text>=</xsl:text>
-    <xsl:value-of select="$namespaces[1]"/>
-    <xsl:choose>
-      <xsl:when test="not(contains($exclude-prefixes, name($namespaces[1]))
-                      or ($namespaces[1] = $exclude-uri))"> 1</xsl:when>
-      <xsl:otherwise> 0</xsl:otherwise>
-    </xsl:choose>
-  </xsl:message>
--->
-
   <xsl:choose>
-    <xsl:when test="count($namespaces) = 0"/>
+    <xsl:when test="count($namespaces) = 0">
+      <!-- do nothing -->
+    </xsl:when>
     <xsl:when test="not(contains($exclude-prefixes, name($namespaces[1]))
                         or ($namespaces[1] = $exclude-uri))">
-      <xsl:choose>
-        <xsl:when test="$first = 0">
-          <xsl:text>&#xA;</xsl:text>
-          <xsl:call-template name="indent"/>
-        </xsl:when>
-        <xsl:otherwise>
-          <xsl:text> </xsl:text>
-        </xsl:otherwise>
-      </xsl:choose>
+      <src:fragref linkend="indent-attribute"/>
       <xsl:text>xmlns</xsl:text>
       <xsl:if test="name($namespaces[1]) != ''">:</xsl:if>
       <xsl:value-of select="name($namespaces[1])"/>
     </xsl:otherwise>
   </xsl:choose>
 </xsl:template>
+</src:fragment>
 
-<xsl:template name="output.applicable.attributes">
-  <xsl:param name="attributes" select="attribute::*"/>
-  <xsl:param name="first" select="'1'"/>
+<section><title>Indent Attribute</title>
 
-<!--
-  <xsl:message>
-    <xsl:text>att: </xsl:text>
-    <xsl:value-of select="$first"/>
-    <xsl:value-of select="count($attributes)"/>
-    <xsl:value-of select="name($attributes[1])"/>
-  </xsl:message>
--->
+<para>If this is not the first attribute or pseudo-attribute, output a
+newline and then indent an appropriate amount. Otherwise, simply output
+a space.</para>
 
-  <xsl:choose>
-    <xsl:when test="count($attributes) = 0"/>
-    <xsl:otherwise>
+<src:fragment id="indent-attribute">
       <xsl:choose>
         <xsl:when test="$first = 0">
           <xsl:text>&#xA;</xsl:text>
           <xsl:text> </xsl:text>
         </xsl:otherwise>
       </xsl:choose>
+</src:fragment>
+
+<para>Indenting is accomplished by outputting a series of spaces. The
+number of spaces is determined by the length of the name of the current
+element plus two (one for the leading <quote>&lt;</quote> and one for
+the space that separates the name from the first attribute).</para>
+
+<src:fragment id="indent">
+<xsl:template name="indent">
+  <xsl:param name="name" select="name(.)"/>
+
+  <xsl:variable name="indent-spaces">
+    <xsl:call-template name="trailing-space-chars">
+      <xsl:with-param name="string" select="preceding-sibling::text()"/>
+    </xsl:call-template>
+  </xsl:variable>
+
+  <!-- +2 for the leading &lt; and the space after the name -->
+  <xsl:variable name="indentlen"
+               select="string-length($name) + $indent-spaces + 2"/>
+
+  <xsl:call-template name="spaces">
+    <xsl:with-param name="count" select="$indentlen"/>
+  </xsl:call-template>
+</xsl:template>
+</src:fragment>
+
+<para>Spaces is a recursive template that outputs a specified
+number of spaces.</para>
+
+<src:fragment id="spaces">
+<xsl:template name="spaces">
+  <xsl:param name="count" select="'0'"/>
+  <xsl:if test="$count &gt; 0">
+    <xsl:text> </xsl:text>
+    <xsl:call-template name="spaces">
+      <xsl:with-param name="count" select="$count - 1"/>
+    </xsl:call-template>
+  </xsl:if>
+</xsl:template>
+</src:fragment>
+
+<para>Given a string, this template walks it recursively counting
+and returning the number of trailing spaces.</para>
+
+<src:fragment id="trailing-space-chars">
+<xsl:template name="trailing-space-chars">
+  <xsl:param name="string" select="''"/>
+  <xsl:param name="count" select="0"/>
+
+  <xsl:choose>
+    <xsl:when test="$string = ''
+                    or substring($string,string-length($string),1) != ' '">
+      <xsl:value-of select="$count"/>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:call-template name="trailing-space-chars">
+        <xsl:with-param name="string" select="substring($string,1,string-length($string)-1)"/>
+        <xsl:with-param name="count" select="$count + 1"/>
+      </xsl:call-template>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+</src:fragment>
+
+</section>
+</section>
+
+<section><title>Output Applicable Attributes</title>
+
+<para>This template walks recursively over the attributes associated
+with a node and outputs each one of them in turn. (All attributes
+are applicable.)</para>
+
+<src:fragment id="output.applicable.attributes">
+<xsl:template name="output.applicable.attributes">
+  <xsl:param name="attributes" select="attribute::*"/>
+  <xsl:param name="first" select="'1'"/>
+
+  <xsl:choose>
+    <xsl:when test="count($attributes) = 0">
+      <!-- do nothing -->
+    </xsl:when>
+    <xsl:otherwise>
+      <src:fragref linkend="indent-attribute"/>
       <xsl:value-of select="name($attributes[1])"/>
       <xsl:text>="</xsl:text>
       <xsl:value-of select="$attributes[1]"/>
     </xsl:otherwise>
   </xsl:choose>
 </xsl:template>
+</src:fragment>
+</section>
+</section>
+</section>
 
-<xsl:template match="node()|@*" mode="copy">
-  <xsl:copy>
-    <xsl:apply-templates select="@*|node()" mode="copy"/>
-  </xsl:copy>
+<section><title>Other Content</title>
+
+<para>The remaining elements, processing instructions, and comments are
+part of the documentation and must simply be copied to the result:</para>
+
+<src:fragment id="doc.content">
+  <src:fragref linkend="default.template"/>
+  <src:fragref linkend="pis"/>
+  <src:fragref linkend="comments"/>
+</src:fragment>
+
+<section><title>Elements</title>
+
+<para>The default template handles copying elements.
+It is a five step process:
+</para>
+
+<orderedlist>
+<listitem><para>Save a copy of the context node in
+<literal>$node</literal> so that we can refer to it later from
+inside an <sgmltag>xsl:for-each</sgmltag>.</para>
+</listitem>
+<listitem><para>Construct a new node in the result tree with
+the same qualified name and namespace as the context node.</para>
+</listitem>
+<listitem><para>Copy the namespace nodes on the context node to the
+new node in the result tree. We must do this manually because the
+&xweb; file may have broken the content of this element into several
+separate fragments. Breaking things into separate fragments makes it
+impossible for the XSLT processor to always construct the right namespace
+nodes automatically.</para>
+</listitem>
+<listitem><para>Copy the attributes.
+</para></listitem>
+<listitem><para>Copy the children.
+</para></listitem>
+</orderedlist>
+
+<src:fragment id="default.template">
+<xsl:template match="*">
+  <xsl:variable name="node" select="."/>
+  <xsl:element name="{name(.)}" namespace="{namespace-uri(.)}">
+    <src:fragref linkend="copy-namespaces"/>
+    <xsl:copy-of select="@*"/>
+    <xsl:apply-templates/>
+  </xsl:element>
 </xsl:template>
+</src:fragment>
 
-<!-- ============================================================ -->
+<section><title>Copy Namespaces</title>
+
+<para>Copying the namespaces is a simple loop over the elements on
+the <literal>namespace</literal> axis, with one wrinkle.</para>
+
+<para>It is an error to copy a namespace node onto an element if a
+namespace node is already present for that namespace.  The fact that
+we're running this loop in a context where we've constructed the
+result node explicitly in the correct namespace means that attempting
+to copy that namespace node again will produce an error. We work
+around this problem by explicitly testing for that namespace and not
+copying it.
+</para>
+
+<src:fragment id="copy-namespaces">        <xsl:for-each select="namespace::*">
+          <xsl:if test="string(.) != namespace-uri($node)">
+            <xsl:copy/>
+          </xsl:if>
+        </xsl:for-each></src:fragment>
+</section>
+</section>
+
+<section><title>Processing Instructions</title>
+
+<para>Processing instructions are simply copied through.</para>
+
+<src:fragment id="pis">
+<xsl:template match="processing-instruction()">
+  <xsl:processing-instruction name="{name(.)}">
+    <xsl:value-of select="."/>
+  </xsl:processing-instruction>
+</xsl:template>
 </src:fragment>
+</section>
 
+<section><title>Comments</title>
+
+<para>Comments are simply copied through. Note, however, that many
+processors do not preserve comments in the source document, so this
+template may never be matched.</para>
+
+<src:fragment id="comments">
+<xsl:template match="comment()">
+  <xsl:comment>
+    <xsl:value-of select="."/>
+  </xsl:comment>
+</xsl:template>
+</src:fragment>
 </section>
+</section>
+
+<section><title>Weaving DocBook</title>
+
+<para>It's no secret (and probably no surprise) that I use DocBook for
+most of my document authoring. Web files are no exception, and I have
+DocBook customization layer that validates woven &xweb; documentation
+files.</para>
+
+<para>In order to validate my woven documentation, I need to make sure
+that the appropriate document type declaration is associated with the
+documents. This is a simple change to the <sgmltag>xsl:output</sgmltag>
+instruction.</para>
 
+<para>This stylesheet imports <filename>weave.xsl</filename> for the
+weaving functionality and simply sets the public and system identifiers.
+</para>
+
+<src:fragment id="wdocbook" mundane-result-prefixes="xsl">
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:src="http://nwalsh.com/xmlns/litprog/fragment"
+                exclude-result-prefixes="xsl src xml"
+                version="1.0">
+
+  <xsl:import href="weave.xsl"/>
+  <xsl:output method="xml"
+              doctype-public="-//DocBook Open Repository//DTD DocBook Literate Programming V0.0//EN"
+              doctype-system="http://docbook.sourceforge.net/release/litprog/current/dtd/ldocbook.dtd"/>
+</xsl:stylesheet>
+</src:fragment>
+</section>
 </article>