<slides>
<slidesinfo>
  <title>Extreme DocBook</title>
  <authorgroup>
    <author><firstname>Norman</firstname><surname>Walsh</surname>
        <affiliation>
          <jobtitle>XML Standards Architect</jobtitle>
          <orgname>Sun Microsystems, Inc.</orgname>
        </affiliation>
        <email>Norman.Walsh@Sun.COM</email>
    </author>
  </authorgroup>
  <confgroup>
    <conftitle>Extreme Markup Languages 2004</conftitle>
    <confdates>01-06 August 2004</confdates>
  </confgroup>
  <releaseinfo role="version">Version 1.0</releaseinfo>
  <releaseinfo role="cvs">$Id: slides.xml,v 1.6 2004/08/02 21:41:54 ndw Exp $</releaseinfo>
  <copyright><year>2004</year>
             <holder>Sun Microsystems, Inc.</holder></copyright>
</slidesinfo>

<foil>
<title>Table of Contents</title>

<para>This presentation explores some of the design choices made in
recasting DocBook from an XML DTD to a RELAX NG Grammar.
</para>
<?slides-toc ?>
<para/> <-- required -->

</foil>

<foilgroup>
<title>What is DocBook?</title>

<foil>
<title>What is DocBook?</title>
<itemizedlist>
<listitem><para>DocBook is an XML vocabulary for writing
documentation. It is particularly well-suited to books and papers
about computer hardware and software, though it is by no means limited
to them.
</para></listitem>
<listitem>
<para>It has been subset down to something that resembles HTML.</para>
</listitem>
<listitem>
<para>It has been extended to do things as different as websites and, well,
presentations like <ulink url="slides.xml">this one</ulink>.
</para>
</listitem>
<--
<listitem><para>This presentation explores some of the design choices made in
recasting DocBook from an XML DTD to a RELAX NG Grammar.
</para></listitem>
-->

</itemizedlist>
</foil>

<foil>
<title>A DocBook Document</title>
<programlisting format="linespecific"><book>
<bookinfo>
<title>A Book Title</title>
<author>
  <firstname>John</firstname>
  <surname>Doe</surname>
</author>
</bookinfo>
<chapter>
<title>The First Chapter</title>
<para>Some <emphasis>text</emphasis>.</para>
</chapter>
</book>
</programlisting>
</foil>

</foilgroup>

<foilgroup>
<title>History and Purpose</title>

<foil>
<title>DocBook History</title>
<itemizedlist>
<listitem>
<para>DocBook has been actively maintained for more than a decade.</para>
</listitem>
<listitem>
<para>It has always been developed by a committee of some sort.
It is now maintained by an OASIS Technical Committee.</para>
</listitem>
<listitem>
<para>DocBook was an SGML DTD for many years, it is now principally an XML DTD.
</para>
</listitem>
</itemizedlist>
</foil>

<foil>
<title>DocBook’s Purpose</title>
<itemizedlist>
<listitem>
<para>DocBook is mostly hand authored. Unlike SOAP envelopes, purchase orders,
and XML/RPC invocations, humans write DocBook.</para>
</listitem>
<listitem>
<para>It’s mostly read by humans. DocBook documents, aren’t usually consumed
by unmarshalling processes building object graphs.</para>
</listitem>
<listitem>
<para>DocBook contains a lot of mixed content. Very few have “simple content,”
dates, numbers, etc.</para>
</listitem>
</itemizedlist>
</foil>

<foil>
<title>Who’s Responsible for DocBook?</title>

<itemizedlist>
<listitem>
<para>Current committee members:
<simplelist type="inline">
<member>Paul Grosso</member>
<member>Adam Di Carlo</member>
<member>Mark Johnson</member>
<member>Dick Hamilton</member>
<member>Larry Rowland</member>
<member>Nancy Harrison</member>
<member>Gary Cornelius</member>
<member>Jirka Kosek</member>
<member>Michael Smith</member>
<member>Robert Stayton</member>
<member>Steven Cogorno</member>
<member>Scott Hudson</member>
<member>Norman Walsh</member>
</simplelist>
</para>
</listitem>
<listitem>
<para>Selected “alumni”:
<simplelist type="inline">
<member>Terry Allen</member>
<member>Jon Bosak</member>
<member>Dale Dougherty</member>
<member>Ralph Ferris</member>
<member>Dave Hollander</member>
<member>Eve Maler</member>
<member>Murray Maloney</member>
<member>Conleth O'Connell</member>
<member>Mike Rogers</member>
<member>Jean Tappan</member>
</simplelist>
</para>
</listitem>
</itemizedlist>
</foil>

<foil>
<title>DocBook Development</title>

<itemizedlist>
<listitem>
<para>There have been about 15 releases in roughly ten years.
</para>
</listitem>
<listitem>
<para>Four of those releases have been “major” releases.
</para>
</listitem>
<listitem>
<para>That means we’ve added new stuff about ¾ of the time!
</para>
</listitem>
</itemizedlist>
</foil>

</foilgroup>

<foilgroup>
<title>State of the Art</title>

<foil>
<title>DocBook Growth</title>

<para>“DocBook is like a pearl, it grows by accretion.”</para>

<mediaobject>
<imageobject>
<imagedata fileref="plot.png"/>
</imageobject>
<textobject><phrase>Plot of element and entity growth by version</phrase></textobject>
</mediaobject>
</foil>

<foil>
<title>A DocBook DTD Fragment</title>
<programlisting format="linespecific"><!ENTITY % chapter.module "INCLUDE">
<![%chapter.module;[
<!ENTITY % local.chapter.attrib "">
<!ENTITY % chapter.role.attrib "%role.attrib;">

<!ENTITY % chapter.element "INCLUDE">
<![%chapter.element;[
<!ELEMENT chapter %ho; (beginpage?,
                    chapterinfo?,
                    (%bookcomponent.title.content;),
                    (%nav.class;)*,
                    tocchap?,
                    (%bookcomponent.content;),
                    (%nav.class;)*)
		%ubiq.inclusion;>
<!--end of chapter.element-->]]>

<!ENTITY % chapter.attlist "INCLUDE">
<![%chapter.attlist;[
<!ATTLIST chapter
		%label.attrib;
		%status.attrib;
		%common.attrib;
		%chapter.role.attrib;
		%local.chapter.attrib;
>
<!--end of chapter.attlist-->]]>
<!--end of chapter.module-->]]></programlisting>
</foil>

<foil>
<title>Growing Pains</title>
<itemizedlist>
<listitem>
<para>Growth by accretion has resulted
in some content models that are at best odd and at worst broken in pretty
obvious ways.
</para>
</listitem>
<listitem>
<para>Ten years of incremental growth has also changed the scale of
DocBook. Designing a schema of roughly 400 elements is different than
designing a schema of roughly 100. Logically extending decisions that
looked regular and consistent when DocBook had 100 elements has not always
resulted in a design that continues to look regular and consistent.
</para>
</listitem>
</itemizedlist>
</foil>

<foil>
<title>DocBook DTD Shortcomings</title>

<itemizedlist>
<listitem>
<para>The DTD fails to capture some significant constraints, for example, that
elements like <sgmltag>article</sgmltag> must have a title. 
</para>
</listitem>
<listitem>
<para>DocBook predates the web. It aches for a more web-friendly approach
to linking.</para>
</listitem>
<listitem>
<para>Originally designed as an exchange DTD, it has largely become an
<emphasis>authoring</emphasis> DTD. Exchange and authoring aren’t opposing design
centers, but they are different.</para>
</listitem>
<listitem>
<para>While DocBook is a shining example of parameter entity customization,
parameter entity customization is fiendishly hard.</para>
</listitem>
</itemizedlist>
</foil>

<foil>
<title>Design Goals</title>

<para>The result of recasting DocBook should…</para>

<orderedlist inheritnum="ignore" continuation="restarts">
<listitem>
<para>“feel like” DocBook.
</para>
</listitem>
<listitem>
<para>enforce as many constraints as possible in the schema.
</para>
</listitem>
<listitem>
<para>clean up the content models.
</para>
</listitem>
<listitem>
<para>give users the flexibility to extend or subset the schema in an easy
and straightforward way.
</para>
</listitem>
<listitem>
<para>be able to generate XML DTD and W3C XML Schema versions of DocBook.
</para>
</listitem>
</orderedlist>
</foil>

</foilgroup>
<foilgroup>
<title>DTD vs. RELAX NG</title>

<--
<foil>
<title>Inlines and Blocks</title>

<itemizedlist>
<listitem>
<para>This is the meat of most documents.</para>
</listitem>
<listitem>
<para>This is where customizers want to make the most changes.</para>
</listitem>
<listitem>
<para>Maintaining determinism makes the parameter entity structure quite baroque.</para>
</listitem>
</itemizedlist>
</foil>

<foil>
<title>Baroque Parameter Entities</title>

<programlisting><![CDATA[
<!ENTITY % local.linespecific.class "">
<!ENTITY % linespecific.class
           "literallayout|programlisting ...
            %local.linespecific.class;">

<!ENTITY % local.figure.mix "">
<!ENTITY % figure.mix
           "%linespecific.class; |%synop.class;
           |%informal.class;     |%ndxterm.class;
           |beginpage %local.figure.mix;">

<!ELEMENT figure %ho; (blockinfo?,
           (%formalobject.title.content;),
           (%figure.mix; | %link.char.class;)+)>]]></programlisting>
</foil>
-->


<foil>
<title>Uniform Info Elements</title>

<itemizedlist>
<listitem>
<para>DocBook V4.x has <sgmltag>setinfo</sgmltag>,
<sgmltag>bookinfo</sgmltag>, <sgmltag>chapterinfo</sgmltag>,
<sgmltag>appendixinfo</sgmltag>, <sgmltag>sectioninfo</sgmltag>, etc.
</para>
</listitem>
<listitem>
<para>Many people think it would be nicer if we just had one <sgmltag>info</sgmltag>
element.</para>
</listitem>
<listitem>
<para>In RELAX NG, we can have different patterns that each define an element
named <sgmltag>info</sgmltag>.</para>
</listitem>
</itemizedlist>
</foil>

<foil>
<title>Uniform Info Elements (Code)</title>

<programlisting format="linespecific">book.info = element info { ... }
chapter.info = element info { ... }

book = element book { book.info, ... }
chapter = element chapter { chapter.info, ... }
</programlisting>
</foil>

<foil>
<title>Info Elements in More Contexts</title>

<itemizedlist>
<listitem>
<para>It (might) be nice to have <sgmltag>info</sgmltag> elements in more
contexts: <code><para><info>...</info>Some text.</para></code></para>
</listitem>
<listitem>
<para>In DTDs, we’d have to say <code>(#PCATA|...|info|...)*</code> which
would allow: <code><para>Some<info>...</info> text.</para></code></para>
</listitem>
<listitem>
<para>In RELAX NG, we can say: <code>(info?, (text|...)*)</code> which
has the semantic we want.</para>
</listitem>
</itemizedlist>
</foil>

<foil>
<title>Required Titles (Valid)</title>

<para>Some elements must have titles, but they can appear in one place or another:</para>

<programlisting format="linespecific"><article>
<title>Some Article Title</title>
<para>Some content.</para>
</article>

<article>
<articleinfo>
<title>Some Article Title</title>
<author><firstname>Jane</firstname>
<surname>Doe</surname></author>
</articleinfo>
<para>Some content.</para>
</article></programlisting>
</foil>

<foil>
<title>Required Titles (Invalid)</title>

<para>I said “in one place <emphasis>or</emphasis> another”:</para>

<programlisting format="linespecific"><article>
<para>Some content without a title.</para>
</article>

<article>
<title>Is This the Title?</title>
<articleinfo>
<title>Or Is This?</title>
</articleinfo>
<para>Some content.</para>
</article></programlisting>
</foil>

<foil>
<title>Required Titles</title>

<programlisting format="linespecific">
title         = title? & titleabbrev? & subtitle?
titlerequired = title  & titleabbrev? & subtitle?

info.titleforbidden = (author|...)
info.titlerequired  = (titlerequired, (author|...)

element article { 
   (titlerequired, info.titleforbidden)
   | info.titlerequired,
   ...
}</programlisting>

<para>This isn’t <emphasis>exactly</emphasis> the same semantic.</para>
</foil>

<foil>
<title>Co-Constraints</title>

<programlisting format="linespecific">biblio.class-enum.attribute =
   attribute class {
      "doi"
    | "isbn"
    | "issn"
    | "libraryofcongress"
    | "pubnumber"
    | "uri" }?

biblio.class-other.attributes =
   attribute class { "other" }?,
   attribute otherclass { xsd:NMTOKEN }

biblio.class.attrib =
   (biblio.class-enum.attribute
    | biblio.class-other.attributes)
</programlisting>
</foil>

<foil>
<title>Untangling Tables</title>
<itemizedlist>
<listitem>
<para>DocBook uses CALS Tables. In DocBook V4.3, we added HTML Tables.
</para>
</listitem>
<listitem>
<para>CALS and HTML tables have overlapping elements with different content
models.
</para>
</listitem>
<listitem>
<para>CALS and HTML tables have attributes with the same name and
<emphasis>intentionally</emphasis> disjoint values.
</para>
</listitem>
<listitem>
<para>In DTDs, we just make a union...</para>
</listitem>
</itemizedlist>
</foil>

<foil>
<title>Untangling Tables</title>
<programlisting format="linespecific">
<!ELEMENT table ((thead?, tfoot?, (tbody|tr+))
                 | tgroup)>

<!ATTLIST table
        frame   (  above  | all  | below |...
                 ... | void | vsides) #IMPLIED
>

<!ELEMENT tbody (tr+ | row+)></programlisting>
</foil>

<foil>
<title>Untangling Tables</title>
<programlisting format="linespecific">html.table =
   element table {
      attribute frame {
         "void"
       | "above"
       | "below"
       | "hsides"
       | "vsides"
       | "lhs"
       | "rhs"
       | "box"
       | "border" }?,
      ((html.thead?, html.tfoot?, html.tbody)
       | html.tr)
   }

html.tbody =
   element tbody { html.tr+ }</programlisting>
</foil>

<foil>
<title>Untangling Tables</title>
<programlisting format="linespecific">cals.table =
   element table {
      attribute frame {
         "all"
       | "bottom"
       | "none"
       | "sides"
       | "top"
       | "topbot" }?,
      cals.tgroup
   }

cals.tbody =
   element tbody { cals.row+ }</programlisting>
</foil>

<foil>
<title>Untangling Tables</title>
<programlisting format="linespecific">table = html.table | cals.table</programlisting>

<para>This allows any HTML table or any CALS table, but no invalid
mixture of the two models.</para>
</foil>

<foil>
<title>Real Datatyping</title>

<para>A small number of elements and attributes benefit from real datatypes.</para>

<itemizedlist>
<listitem>
<para><sgmltag>date</sgmltag>, <sgmltag>pubdate</sgmltag>, etc. are real
dates (maybe).
</para>
</listitem>
<listitem>
<para><sgmltag class="attribute">startinglinenumber</sgmltag> is an integer.
</para>
</listitem>
<listitem>
<para><sgmltag class="attribute">cols</sgmltag> on <sgmltag>tgroup</sgmltag> is
a positive integer.
</para>
</listitem>
</itemizedlist>
</foil>

<foil>
<title>Extra-Grammatical Constraints</title>
<para>Grammar based validation technologies (like RELAX NG) and rule
based validation technologies (like Schematron) are naturally
complimentary. Mixing them allows us to play to the strengths of each
without stretching either to enforce constraints that they aren’t
readily designed to enforce.</para>
</foil>

<foil>
<title>Extra-Grammatical Constraints</title>
<itemizedlist>
<listitem>
<para>Exclusions. (High on my list of features for a future version of RELAX NG.)
</para>
</listitem>

<listitem>
<para>A version attribute on the root element.
</para>
</listitem>

<listitem>
<para>Enforcing implicit constraints. (In a segmented list, the number of segments
in each list item has to be the same as the number of titles specified.)
</para>
</listitem>

<listitem>
<para>Enforcing referential integrity constraints. (A cross-reference on a
<sgmltag>footnoteref</sgmltag> must point to a <sgmltag>footnote</sgmltag>.)
</para>
</listitem>
</itemizedlist>
</foil>

<foil>
<title>RELAX NG + Schematron</title>

<programlisting format="linespecific">db.book =
  [
    s:rule [
      context = "/db:book"
      s:assert [
        test = "@version"
        "The root element must have a version attribute."
      ]
    ]
  ]
  element book {
    book.attlist,
    book.info,
    (navigation.components | components | divisions)+
  }</programlisting>

<para>There are validators that will enforce both sets of constraints.</para>
</foil>

<foil>
<title>Customization</title>

<itemizedlist>
<listitem>
<para>The ability to customize DocBook is <emphasis>critically</emphasis> important.
</para>
</listitem>

<listitem>
<para>Many users subset DocBook.
</para>
</listitem>

<listitem>
<para>Many users extend DocBook.
</para>
</listitem>

<listitem>
<para>To be successful, these operations must be (at least) as easy as DTD
customization, preferably easier.
</para>
</listitem>
</itemizedlist>
</foil>

<foil>
<title>Removing Procedures from the DTD</title>

<programlisting format="linespecific"><!-- DocBook XML V4.3 No Procedures Subset -->

<!ENTITY % ebnf.block.hook "">
<!ENTITY % local.compound.class "">
<!ENTITY % compound.class
		"msgset|sidebar|qandaset
                 %ebnf.block.hook;
                 %local.compound.class;">

<!ENTITY % procedure.content.module "IGNORE">
<!ENTITY % task.content.module "IGNORE">
<!ENTITY % sidebar.element "IGNORE">
<!ENTITY % qandaset.element "IGNORE">
<!ENTITY % qandadiv.element "IGNORE">
<!ENTITY % question.element "IGNORE">
<!ENTITY % answer.element "IGNORE">
<!ENTITY % revdescription.element "IGNORE">
<!ENTITY % caution.element "IGNORE">
<!ENTITY % important.element "IGNORE">
<!ENTITY % note.element "IGNORE">
<!ENTITY % tip.element "IGNORE">
<!ENTITY % warning.element "IGNORE">

<!ENTITY % docbook.dtd PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
                       "http://docbook.org/xml/4.3/docbookx.dtd">
%docbook.dtd;

<!ENTITY % my.sidebar.mix
		"%list.class;		|%admon.class;
		|%linespecific.class;	|%synop.class;
		|%para.class;		|%informal.class;
		|%formal.class;
		|%genobj.class;
		|%ndxterm.class;        |beginpage
		%local.sidebar.mix;">

<!ELEMENT sidebar (sidebarinfo?,
                   (%formalobject.title.content;)?,
                   (%my.sidebar.mix;)+)>

<!ENTITY % my.qandaset.mix
		"%list.class;           |%admon.class;
		|%linespecific.class;	|%synop.class;
		|%para.class;		|%informal.class;
		|%formal.class;
		|%genobj.class;
		|%ndxterm.class;
		%local.qandaset.mix;">

<!ELEMENT qandaset (blockinfo?, (%formalobject.title.content;)?,
			(%my.qandaset.mix;)*,
                        (qandadiv+|qandaentry+))>

<!ELEMENT qandadiv (blockinfo?, (%formalobject.title.content;)?,
			(%my.qandaset.mix;)*,
			(qandadiv+|qandaentry+))>

<!ELEMENT question (label?, (%my.qandaset.mix;)+)>

<!ELEMENT answer (label?, (%my.qandaset.mix;)*, qandaentry*)>

<!ENTITY % my.revdescription.mix
		"%list.class;		|%admon.class;
		|%linespecific.class;	|%synop.class;
		|%para.class;		|%informal.class;
		|%formal.class;
		|%genobj.class;
		|%ndxterm.class;
		%local.revdescription.mix;">

<!ELEMENT revdescription ((%my.revdescription.mix;)+)>

<!ENTITY % my.admon.mix
		"%list.class;
		|%linespecific.class;	|%synop.class;
		|%para.class;		|%informal.class;
		|%formal.class;		|sidebar
		|anchor|bridgehead|remark
		|%ndxterm.class;        |beginpage
		%local.admon.mix;">

<!ELEMENT caution (title?, (%my.admon.mix;)+)
                      %admon.exclusion;>

<!ELEMENT important (title?, (%my.admon.mix;)+)
                      %admon.exclusion;>

<!ELEMENT note (title?, (%my.admon.mix;)+)
                      %admon.exclusion;>

<!ELEMENT tip (title?, (%my.admon.mix;)+)
                      %admon.exclusion;>

<!ELEMENT warning (title?, (%my.admon.mix;)+)
                      %admon.exclusion;></programlisting>

</foil>

<foil>
<title>Removing Procedures from the RELAX NG Schema</title>

<programlisting format="linespecific"># DocBook NG "Bourbon" No Procedures Subset

namespace db = "http://docbook.org/docbook-ng"
default namespace = "http://docbook.org/docbook-ng"

include "docbook.rnc" {
   db.procedure = notAllowed
}
</programlisting>
</foil>

<foil>
<title>Adding Exercises</title>

<programlisting format="linespecific"># DocBook NG "Bourbon" Exercises Extension

namespace db = "http://docbook.org/docbook-ng"
default namespace = "http://docbook.org/docbook-ng"

include "docbook.rnc" {
   extension.blocks |= exercise   
}

exercise = element exercise { db.title, all.blocks+ }</programlisting>

</foil>

<foil>
<title>Converting to NG</title>

<itemizedlist>
<listitem>
<para>XSLT can convert DocBook V4.x to DocBook NG. The conversion stylesheet
is about 1000 lines long and contains roughly 45 templates.
</para>
</listitem>

<listitem>
<para>It successfully converts about 94% of the DocBook test cases I have on
hand for stylesheet testing.
</para>
</listitem>

<listitem>
<para>It doesn’t convert elements that use entity attributes. It also doesn’t
convert old style <sgmltag>toc</sgmltag> markup.
</para>
</listitem>

<listitem>
<para>It can’t convert tests that use block elements in inline contexts.
</para>
</listitem>

<listitem>
<para>Those cases (such as allowing <sgmltag>cmdsynopsis</sgmltag> inside a
<sgmltag>glossterm</sgmltag>) demonstrate that the existing parameter entity
structure is simply wrong in some places.
</para>
</listitem>
</itemizedlist>
</foil>

</foilgroup>
<foilgroup>
<title>Compatibility</title>

<foil>
<title>Creating XML Schemas</title>
<para>Use <command moreinfo="none">trang</command>:</para>

<programlisting format="linespecific">  <xs:element name="book">
    <xs:complexType>
      <xs:sequence>
        <xs:group ref="db:db.book.info"/>
        <xs:choice maxOccurs="unbounded">
          <xs:group ref="db:db.navigation.components"/>
          <xs:element ref="db:db.components"/>
          <xs:element ref="db:db.divisions"/>
        </xs:choice>
      </xs:sequence>
      <xs:attributeGroup ref="db:db.book.attlist"/>
    </xs:complexType>
  </xs:element></programlisting>

<para>(Approximates the RELAX NG patterns for MathML/SVG extensions because of
wildecard limitations.)</para>
</foil>

<foil>
<title>Creating DTDs</title>

<itemizedlist>
<listitem>
<para>Trang can’t.
</para>
</listitem>
<listitem>
<para>One possible solution: declarative markup in the schema and XSLT.
</para>
</listitem>
<listitem>
<para>Another solution: flatten aggressively and reconstitute.
</para>
</listitem>
</itemizedlist>
</foil>
</foilgroup>

<foilgroup>
<title>Conclusions</title>

<foil>
<title>Other Approaches</title>

<itemizedlist>
<listitem>
<para>It might be technically possible to achieve some of the goals using
DTDs simply by refactoring the parameter entities (again).
</para>
</listitem>
<listitem>
<para>W3C XML Schema would be better than DTDs.</para>
  <itemizedlist>
  <listitem>
  <para>I’m not sure the abstraction is right for schemas with lots of mixed content.
  </para>
  </listitem>
  <listitem>
  <para>Determinism would still be a problem. 
  </para>
  </listitem>
  <listitem>
  <para>Local element declarations force customizations to “cascade” up the tree.
  </para>
  </listitem>
  <listitem>
  <para>No support for co-constraints.
  </para>
  </listitem>
  </itemizedlist>
</listitem>
<listitem>
<para>Schematron could do it all, but it would require a lot of rules.
</para>
</listitem>
</itemizedlist>
</foil>

<foil>
<title>Conclusions</title>

<itemizedlist>
<listitem>
<para>The DocBook RELAX NG schema satisfies the redesign goals to a large
extent: it looks and feels like DocBook
while at the same time having simpler, more logical content models and
better contraints.</para>
</listitem>
<listitem>
<para>The RELAX NG grammar is demonstrably easier to
customize, at least for those applications that can use the RELAX NG
grammar directly.</para>
</listitem>
<listitem>
<para>DocBook NG has only 356 elements and 1,701 patterns.</para>
</listitem>
</itemizedlist>
</foil>

<foil>
<title>References</title>

<itemizedlist>
<listitem>
<para><ulink url="http://docbook.org/tdg/en/html-ng/"/>, a special edition of
<citetitle>DocBook: The Definitive Guide</citetitle> showing the DTD and
(flattened) RELAX NG content models.</para>
</listitem>
<listitem>
<para><ulink url="http://www.oasis-open.org/committees/docbook/"/>, the
DocBook Technical Committee.</para>
</listitem>
<listitem>
<para><ulink url="http://norman.walsh.name/threads/refactorDocBook"/>, a thread
through the essays I’ve written about redesigning DocBook.</para>
</listitem>
</itemizedlist>
</foil>

</foilgroup>
</slides>