<?xml version="1.0" encoding="utf-8"?>
<!-- This file was generated by weave.xsl version 0.00+. Do not edit! -->
<!-- See http://sourceforge.net/projects/docbook/ -->
<!DOCTYPE article
  PUBLIC "-//DocBook Open Repository//DTD DocBook Literate Programming V0.0//EN" "http://docbook.sourceforge.net/release/litprog/current/dtd/ldocbook.dtd">
<article xmlns:src="http://nwalsh.com/xmlns/litprog/fragment" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<articleinfo>
<title>Tangle</title>
<subtitle>Part of
<citetitle>Literate Programming in XML</citetitle></subtitle>
<pubdate>05 Oct 2001</pubdate>
<releaseinfo role="meta">
$Id: tangle.xweb,v 1.3 2001/10/06 13:39:05 nwalsh Exp $
</releaseinfo>

<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
<acronym>XWEB</acronym> 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 <acronym>XWEB</acronym> 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">&lt;xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                exclude-result-prefixes="src"
                version="1.0"&gt;

  <src:fragref linkend="init"/>

  &lt;xsl:output xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
              method="text"/&gt;

  <src:fragref linkend="root.template"/>
  <src:fragref linkend="process-fragments"/>
  <src:fragref linkend="copy-elements"/>
&lt;/xsl:stylesheet&gt;</src:fragment>
</section>

<section><title>The <filename>xtangle.xsl</filename> Stylesheet</title>

<para>The xtangle stylesheet produces XML output.</para>

<src:fragment id="xtop">&lt;xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                exclude-result-prefixes="src"
                version="1.0"&gt;

  <src:fragref linkend="init"/>

  &lt;xsl:output xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
              method="xml"/&gt;

  <src:fragref linkend="root.template"/>
  <src:fragref linkend="process-fragments"/>
  <src:fragref linkend="copy-elements"/>
  <src:fragref linkend="copy-xml-constructs"/>
&lt;/xsl:stylesheet&gt;</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 <acronym>XWEB</acronym> 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">  &lt;xsl:include href="VERSION"/&gt;
  &lt;xsl:preserve-space elements="*"/&gt;

  &lt;xsl:key name="fragment"
           match="src:fragment"
           use="@id"/&gt;

  &lt;xsl:param name="top"
             select="'top'"/&gt;
</src:fragment>

</section>

<section><title>The Root Template</title>

<para>The root template begins processing at the root of the <acronym>XWEB</acronym>
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 <acronym>XWEB</acronym> 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">&lt;xsl:template match="/"&gt;
  &lt;xsl:apply-templates select="key('fragment', $top)"/&gt;
&lt;/xsl:template&gt;</src:fragment>
</section>

<section><title>Processing Fragments</title>

<para>In order to <quote>tangle</quote> an <acronym>XWEB</acronym> 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">&lt;xsl:template match="src:fragment"&gt;
  &lt;xsl:apply-templates mode="copy"/&gt;
&lt;/xsl:template&gt;</src:fragment>
</section>

<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">&lt;xsl:template match="src:passthrough"
              mode="copy"&gt;
  &lt;xsl:value-of disable-output-escaping="yes"
                select="."/&gt;
&lt;/xsl:template&gt;</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">&lt;xsl:template match="src:fragref"
              mode="copy"&gt;
  &lt;xsl:variable name="node"
                select="."/&gt;
  &lt;xsl:choose&gt;
    <src:fragref linkend="doe-fragref"/>
    <src:fragref linkend="normal-fragref"/>
  &lt;/xsl:choose&gt;
&lt;/xsl:template&gt;</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">    &lt;xsl:otherwise&gt;
      &lt;xsl:variable name="fragment"
                    select="key('fragment', @linkend)"/&gt;
      <src:fragref linkend="fragref-unique"/>
      <src:fragref linkend="fragref-isfragment"/>
      &lt;xsl:apply-templates select="$fragment"/&gt;
    &lt;/xsl:otherwise&gt;</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">      &lt;xsl:if test="count($fragment) != 1"&gt;
        &lt;xsl:message terminate="yes"&gt;
          &lt;xsl:text&gt;Link to fragment "&lt;/xsl:text&gt;
          &lt;xsl:value-of select="@linkend"/&gt;
          &lt;xsl:text&gt;" does not uniquely identify a single fragment.&lt;/xsl:text&gt;
        &lt;/xsl:message&gt;
      &lt;/xsl:if&gt;</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">&lt;xsl:if test="local-name($fragment) != 'fragment'"&gt;
  &lt;xsl:message terminate="yes"&gt;
    &lt;xsl:text&gt;Link "&lt;/xsl:text&gt;
    &lt;xsl:value-of select="@linkend"/&gt;
    &lt;xsl:text&gt;" does not point to a src:fragment.&lt;/xsl:text&gt;
  &lt;/xsl:message&gt;
&lt;/xsl:if&gt;</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">    &lt;xsl:when test="@disable-output-escaping='yes'"&gt;
      &lt;xsl:element name="{name(.)}"
                   namespace="{namespace-uri(.)}"&gt;
        <src:fragref linkend="copy-namespaces"/>
        &lt;xsl:for-each select="@*"&gt;
          &lt;xsl:if test="not(name(.) = 'disable-output-escaping')"&gt;
            &lt;xsl:copy/&gt;
          &lt;/xsl:if&gt;
        &lt;/xsl:for-each&gt;
        &lt;xsl:apply-templates mode="copy"/&gt;
      &lt;/xsl:element&gt;
    &lt;/xsl:when&gt;</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
<acronym>XWEB</acronym> 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">&lt;xsl:template match="*"
              mode="copy"&gt;
  &lt;xsl:variable name="node"
                select="."/&gt;
  &lt;xsl:element name="{name(.)}"
               namespace="{namespace-uri(.)}"&gt;
    <src:fragref linkend="copy-namespaces"/>
    &lt;xsl:copy-of select="@*"/&gt;
    &lt;xsl:apply-templates mode="copy"/&gt;
  &lt;/xsl:element&gt;
&lt;/xsl:template&gt;</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">  &lt;xsl:for-each select="namespace::*"&gt;
    &lt;xsl:if test="string(.) != namespace-uri($node)"&gt;
      &lt;xsl:copy/&gt;
    &lt;/xsl:if&gt;
  &lt;/xsl:for-each&gt;</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">&lt;xsl:template match="processing-instruction()"
              mode="copy"&gt;
  &lt;xsl:processing-instruction name="{name(.)}"&gt;
    &lt;xsl:value-of select="."/&gt;
  &lt;/xsl:processing-instruction&gt;
&lt;/xsl:template&gt;

&lt;xsl:template match="comment()"
              mode="copy"&gt;
  &lt;xsl:comment&gt;
    &lt;xsl:value-of select="."/&gt;
  &lt;/xsl:comment&gt;
&lt;/xsl:template&gt;</src:fragment>

</section>

</article>