OASIS Mailing List ArchivesView the OASIS mailing list archive below
or browse/search using MarkMail.

 


Help: OASIS Mailing Lists Help | MarkMail Help

docbook message

[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]


Subject: Another draft od DocBook Transclusion


On 20.11.2014 1:04, Bob Stayton wrote:
> ACTION: Jirka to update the document with these changes.

Hi,

please find attached next version of Transclusion draft. I hope that I
have implemented all changes we agreed during telcon. I tried to
separate more formal definition now and put examples into appendices.

Any comments welcomed, including copy-edit (I don't recall, but Larry or
Dick offered to do copy-edit pass over my Czenglish.)

				Jirka


-- 
------------------------------------------------------------------
  Jirka Kosek      e-mail: jirka@kosek.cz      http://xmlguru.cz
------------------------------------------------------------------
     Professional XML and Web consulting and training services
DocBook/DITA customization, custom XSLT/XSL-FO document processing
------------------------------------------------------------------
 OASIS DocBook TC member, W3C Invited Expert, ISO JTC1/SC34 rep.
------------------------------------------------------------------
    Bringing you XML Prague conference    http://xmlprague.cz
------------------------------------------------------------------
Title: DocBook Transclusion

DocBook Transclusion

NaN December 2014


Introduction

This document describes syntax, semantics and processing model of DocBook transclusion mechanism. Please be aware that this is a working draft – everything described below might change or disappear completely. This proposal tries to resolve Requirements for transclusion in DocBook. DocBook TC welcomes any feedback on this draft, especially from users and developers of DocBook authoring and processing tools. Please direct your comments to DocBook mailing list by sending email to .

Note

Previous version of this draft proposed new elements ref and def for implementing transclusions. Meanwhile DocBook TC decided that transclusions should rely as much as possible on standard technologies. XInclude 1.1 added new features that allow to implement transclusion features on top of the XInclude. As a result transclusions were completely redesigned to be layered on top of XInclude 1.1.

This resulted in a loss of some features, notably it's no longer possible to locally redefine text replacement (see example).

The following namespace bindings are assumed if namespace prefix is used in the text of this document:

trans

DocBook transclusion namespace (http://docbook.org/ns/transclusion)

db

DocBook namespace (http://docbook.org/ns/docbook)

xi

XInclude namespace (http://www.w3.org/2001/XInclude)

local

XInclude namespace for copying attributes without namespace (http://www.w3.org/2001/XInclude/local-attributes)

Transclusion processing

Processing model of transclusion is very simple. First normal XInclude processing is done on the input document. Then document is modified by the transclusion processor in order to fix problems like duplicate IDs or broken cross-references. The resulting document can be then processed using normal tools.

Transclusion processor is controlled by presence of special attributes from http://docbook.org/ns/transclusion namespace on elements. Those attributes are typically inserted into document by using new XInclude 1.1 [XI11] feature described in section 4.3 Attribute Copying when processing XML.

Transclusion processor copies document node by node. For most nodes this is an identity transformation with few exceptions controlled by transclusion properties. Transclusion properties suffix and linkscope are defined for each node in the document as follows:

suffix

Suffix defines value to append to all ID values on the element (where are ID values is defined in ID-list property).

Default suffix is an empty string.

This property is inherited.

It's value can be changed by trans:idfixup and trans:suffix attributes.

linkscope

Linkscope defines how to correct references to IDs on the element (which values has to be corrected is defined by IDREF-list property).

Allowed values are user, local, near and global.

Default linkscope value is near.

This property is inherited.

It's value can be changed by trans:linkscope attribute.

For each document type there are two additional properties ID-list and IDREF-list controlling transclusion process. ID-list property defines attributes and elements where IDs can appear. Similarly IDREF-list defines attributes and elements where references to ID can appear. For DocBook 5.0 definition of those properties can be found in Definition of ID-list and IDREF-list properties for DocBook 5.0. Transclusion processors are free to support ID-list and IDREF-list configurations for other document types, for example DocBook 4.x or TEI. This allows to use transclusion with different document types.

For each node ID references contained in attributes or elements defined in IDREF-list are corrected as follows:

When linkscope=user

No adjustment is done.

When linkscope=local

All ID references on element are suffixed by value of the suffix property.

When linkscope=near

All ID references on element are adjusted to point to the closest element which has a matching ID.

When searching for the closest element with a matching ID ancestor elements of the element with an ID reference are gradually inspected and matching ID is searched between all their descendants. If there is no matching ID, then parent is inspected and so on until match is found or document root is reached.

When linkscope=global

All ID references on element are adjusted to point to the first element in document order which has a matching ID.

A matching ID doesn't mean string equality between ID and IDREF values – it is sufficient if first parts of ID and IDREF values after removal of possibly added suffixes are matching.

Value of transclusion properties can be set on any element by the following attributes:

trans:idfixup attribute
value none

Suffix transclusion property is set to an empty string.

value suffix

Suffix transclusion property is set to a concatenation of the inherited suffix value and a value specified in trans:suffix attribute.

value auto

Suffix transclusion property is set to a value which is unique for each element.[1]

trans:suffix attribute

Value of this attribute contributes to suffix transclusion property.

It's an error to specify this attribute when trans:idfixup="suffix" is not specified on the element as well.

trans:linkscope attribute
value user

Linkscope property is set to user.

value local

Linkscope property is set to local.

value near

Linkscope property is set to near.

value global

Linkscope property is set to global.

During transclusion process all attributes from transclusion namespace are removed from the resulting document.

Definition of ID-list and IDREF-list properties for DocBook 5.0

ID-list

Following attribute is member: xml:id.

IDREF-list

Following attributes are members: linkend, linkends, otherterm, zone, startref, arearefs, targetptr, endterm.

Also attribute href in XLink namespace is member of this list if its value begins with #.

A. Using new XInclude 1.1 features for your content

The most common transclusion scenario is reuse of shared strings (see http://docbook.org/docs/transclusion-requirements/transclusion-requirements.html#uc-1). With XInclude 1.0 this was possible only using fancy XPointer schemes which were not very interoperable. With XInclude 1.1 situation is more easier.

Let's assume we have definitions of shared strings.

Example A.1. Definitions stored in a separate document (definitions.001.xml)

<?xml version="1.0" encoding="UTF-8"?>
<article xmlns="http://docbook.org/ns/docbook" version="5.0">
  <title>Placeholder for definitions</title>
  <para>
    <phrase xml:id="product-version">3.14</phrase>
    <phrase xml:id="product-name">FooWiz</phrase>
    <phrase xml:id="corp-name">ACME Inc.</phrase>
  </para>
</article>

Now, their naive reuse leads to duplicate IDs problem.

Example A.2. Usage of definitions stored in a separate document and problem of duplicated IDs

<?xml version="1.0" encoding="UTF-8"?>
<article xmlns="http://docbook.org/ns/docbook" version="5.0"
  xmlns:xi="http://www.w3.org/2001/XInclude">
  <info>
    <title>Transclusions demo</title>
  </info>
  <para>The latest version of
    <application><xi:include href="definitions.001.xml" xpointer="product-name"/></application> from
    <xi:include href="definitions.001.xml" xpointer="corp-name"/>
    is <xi:include href="definitions.001.xml" xpointer="product-version"/>.</para>
  <para>You can buy <xi:include href="definitions.001.xml" xpointer="product-name"/> in our on-line store.</para>
</article>

Result of transclusion:

<?xml version="1.0" encoding="UTF-8"?>
<article xmlns="http://docbook.org/ns/docbook" version="5.0">
  <info>
      <title>Transclusions demo</title>
  </info>
  <para>The latest version of
    <application>
         <phrase xml:base="definitions.001.xml" xml:id="product-name">FooWiz</phrase>
      </application> from
    <phrase xml:base="definitions.001.xml" xml:id="corp-name">ACME Inc.</phrase>
    is <phrase xml:base="definitions.001.xml" xml:id="product-version">3.14</phrase>.</para>
  <para>You can buy <phrase xml:base="definitions.001.xml" xml:id="product-name">FooWiz</phrase> in our on-line store.</para>
</article>

Unfortunately upon inclusion ID attributes are preserved which leads to duplicate IDs problem when one definition is included more then once.


XInclude 1.1 has special set-xml-id attribute which can be used for changing or completely removing of xml:id attribute on included content.

Example A.3. Removal of top-level ID during transclusion

<?xml version="1.0" encoding="UTF-8"?>
<article xmlns="http://docbook.org/ns/docbook" version="5.0"
  xmlns:xi="http://www.w3.org/2001/XInclude">
  <info>
    <title>Transclusions demo</title>
  </info>
  <para>The latest version of
    <application><xi:include href="definitions.001.xml" xpointer="product-name" set-xml-id=""/></application> from
    <xi:include href="definitions.001.xml" xpointer="corp-name" set-xml-id=""/>
    is <xi:include href="definitions.001.xml" xpointer="product-version" set-xml-id=""/>.</para>
  <para>You can buy <xi:include href="definitions.001.xml" xpointer="product-name" set-xml-id=""/> in our on-line store.</para>
</article>

Result of transclusion:

<?xml version="1.0" encoding="UTF-8"?>
<article xmlns="http://docbook.org/ns/docbook" version="5.0">
  <info>
      <title>Transclusions demo</title>
  </info>
  <para>The latest version of
    <application>
         <phrase xml:base="definitions.001.xml">FooWiz</phrase>
      </application> from
    <phrase xml:base="definitions.001.xml">ACME Inc.</phrase>
    is <phrase xml:base="definitions.001.xml">3.14</phrase>.</para>
  <para>You can buy <phrase xml:base="definitions.001.xml">FooWiz</phrase> in our on-line store.</para>
</article>


Another new XInclude 1.1 feature is ability to override attributes on included content. This can be used for example for overriding of effectivity attributes. In order to do that you must put your attributes on xi:include element in a special namespace http://www.w3.org/2001/XInclude/local-attributes.

Example A.4. Overriding of DocBook attributes on inclusion

Consider section (section.001.xml) which is labeled as for Linux (os="linux").

<?xml version="1.0" encoding="UTF-8"?>
<section xmlns="http://docbook.org/ns/docbook"
    version="5.0"
    os="linux">
    <title>Installation</title>
    <para>Text</para>
</section>

Now we want to include it into another document and pretend that it's actually targeted at BSD-like system.

<?xml version="1.0" encoding="UTF-8"?>
<article xmlns="http://docbook.org/ns/docbook"
    xmlns:xi="http://www.w3.org/2001/XInclude"
    xmlns:local="http://www.w3.org/2001/XInclude/local-attributes"
    version="5.0">
  <title>Sample article</title>
  <xi:include href="section.001.xml" local:os="bsd"/>
</article>

This local:os attribute is changed into os attribute in no namespace during XInclude processing.

<?xml version="1.0" encoding="UTF-8"?>
<article xmlns="http://docbook.org/ns/docbook" version="5.0">
  <title>Sample article</title>
  <section version="5.0" os="bsd" xml:base="section.001.xml">
      <title>Installation</title>
      <para>Text</para>
   </section>
</article>


B. Special ID/IDREF processing

Transcluded content can contain an xml:id attributes. If one fragment is transcluded more then once then the resulting document after transclusion will contain duplicate IDs. The same problem may arise if IDs are colliding in transcluded modules. To overcome this problem all IDs and references to them can be adjusted during the transclusion process.

How IDs are going to be adjusted during transclusion is controlled by the trans:idfixup attribute on the xi:include element.

Of course if IDs are adjusted then all corresponding references has to be also corrected. This is controlled by trans:linkscope attribute.

By using various combinations of trans:idfixup and trans:linkscope attributes we can achieve different linking behavior. The following examples show the effect of using those two attributes. Examples are transcluding the following procedure which contains one internal link and one external (points to target outside of this module).

Example B.1. Module with sample procedure

<?xml version="1.0" encoding="UTF-8"?>
<procedure xmlns="http://docbook.org/ns/docbook" xml:id="paper-insert">
  <title>Inserting paper into printer</title>
  <para>This procedure is targeted to printer owners.
    If you don't have printer, consider <link linkend="buy">buying one</link>.</para>  
  <step xml:id="s1"><para>Make sure that you have paper.</para></step>
  <step><para>Insert paper into printer. If you don't have paper consult <xref linkend="s1"/></para></step>
</procedure>

Now lets assume that we want to transclude this module twice to show how we can deal with duplicate IDs problem.

Example B.2. Automatic ID/IDREF adjustment

<?xml version="1.0" encoding="UTF-8"?>
<book xmlns="http://docbook.org/ns/docbook"
      xmlns:xi="http://www.w3.org/2001/XInclude"
      xmlns:trans="http://docbook.org/ns/transclude"
      version="5.0">
  <title>Definitive Printer Guide</title>
  <chapter xml:id="buy">
    <title>Buying printer</title>
    <para>Grab money, go to shop, ...</para>
  </chapter>
  <chapter>
    <title>Quick installation guide</title>
    <para>Carefully follow all procedures bellow.</para>
    <xi:include href="procedure.001.xml" trans:idfixup="auto"/>
  </chapter>
  <chapter>
    <title>Maintenance</title>
    <para>Be friendly to your printer when you speak to it.</para>
    <para>If green led is blinking, please add missing paper using the following procedure.</para>
    <xi:include href="procedure.001.xml" trans:idfixup="auto"/>
  </chapter>
</book>

Result of transclusion:

<?xml version="1.0" encoding="UTF-8"?>
<book xmlns="http://docbook.org/ns/docbook" version="5.0">
  <title>Definitive Printer Guide</title>
  <chapter xml:id="buy">
      <title>Buying printer</title>
      <para>Grab money, go to shop, ...</para>
  </chapter>
  <chapter>
      <title>Quick installation guide</title>
      <para>Carefully follow all procedures bellow.</para>
      <procedure xml:base="procedure.001.xml" xml:id="paper-insert---d1e23">
         <title>Inserting paper into printer</title>
         <para>This procedure is targeted to printer owners.
    If you don't have printer, consider <link linkend="buy">buying one</link>.</para>  
         <step xml:id="s1---d1e23">
            <para>Make sure that you have paper.</para>
         </step>
         <step>
            <para>Insert paper into printer. If you don't have paper consult <xref linkend="s1---d1e23"/>
            </para>
         </step>
      </procedure>
  </chapter>
  <chapter>
      <title>Maintenance</title>
      <para>Be friendly to your printer when you speak to it.</para>
      <para>If green led is blinking, please add missing paper using the following procedure.</para>
      <procedure xml:base="procedure.001.xml" xml:id="paper-insert---d1e56">
         <title>Inserting paper into printer</title>
         <para>This procedure is targeted to printer owners.
    If you don't have printer, consider <link linkend="buy">buying one</link>.</para>  
         <step xml:id="s1---d1e56">
            <para>Make sure that you have paper.</para>
         </step>
         <step>
            <para>Insert paper into printer. If you don't have paper consult <xref linkend="s1---d1e56"/>
            </para>
         </step>
      </procedure>
  </chapter>
</book>

We have to specify db:idfixup in order to trigger automatic ID/IDREF fixup. All IDs in transcluded modules are automatically suffixed to prevent ID collisions. Then IDREFs are fixed so that links point to the nearest possible target. For example the link from step 2 to step 1 in procedure always points to the same instance of procedure. However buy link is pointing correctly to target in the main document.


Example B.3. Global linkscope

<?xml version="1.0" encoding="UTF-8"?>
<book xmlns="http://docbook.org/ns/docbook"
      xmlns:xi="http://www.w3.org/2001/XInclude"
      xmlns:trans="http://docbook.org/ns/transclude"
      version="5.0">
  <title>Definitive Printer Guide</title>
  <chapter xml:id="buy">
    <title>Buying printer</title>
    <para>Grab money, go to shop, ...</para>
  </chapter>
  <chapter>
    <title>Quick installation guide</title>
    <para>Carefully follow all procedures bellow.</para>
    <xi:include href="procedure.001.xml" trans:idfixup="auto"/>
  </chapter>
  <chapter>
    <title>Maintenance</title>
    <para>Be friendly to your printer when you speak to it.</para>
    <para>If green led is blinking, please add missing paper using the following procedure.</para>
    <xi:include href="procedure.001.xml" trans:idfixup="auto" trans:linkscope="global"/>
  </chapter>
</book>

Result of transclusion:

<?xml version="1.0" encoding="UTF-8"?>
<book xmlns="http://docbook.org/ns/docbook" version="5.0">
  <title>Definitive Printer Guide</title>
  <chapter xml:id="buy">
      <title>Buying printer</title>
      <para>Grab money, go to shop, ...</para>
  </chapter>
  <chapter>
      <title>Quick installation guide</title>
      <para>Carefully follow all procedures bellow.</para>
      <procedure xml:base="procedure.001.xml" xml:id="paper-insert---d1e23">
         <title>Inserting paper into printer</title>
         <para>This procedure is targeted to printer owners.
    If you don't have printer, consider <link linkend="buy">buying one</link>.</para>  
         <step xml:id="s1---d1e23">
            <para>Make sure that you have paper.</para>
         </step>
         <step>
            <para>Insert paper into printer. If you don't have paper consult <xref linkend="s1---d1e23"/>
            </para>
         </step>
      </procedure>
  </chapter>
  <chapter>
      <title>Maintenance</title>
      <para>Be friendly to your printer when you speak to it.</para>
      <para>If green led is blinking, please add missing paper using the following procedure.</para>
      <procedure xml:base="procedure.001.xml" xml:id="paper-insert---d1e56">
         <title>Inserting paper into printer</title>
         <para>This procedure is targeted to printer owners.
    If you don't have printer, consider <link linkend="buy">buying one</link>.</para>  
         <step xml:id="s1---d1e56">
            <para>Make sure that you have paper.</para>
         </step>
         <step>
            <para>Insert paper into printer. If you don't have paper consult <xref linkend="s1---d1e23"/>
            </para>
         </step>
      </procedure>
  </chapter>
</book>

We used trans:linkscope="global" on the second transclusion. Result is that link from step 2 in the second procedure now links to step 1 in the first procedure.


Example B.4. Local linkscope

<?xml version="1.0" encoding="UTF-8"?>
<book xmlns="http://docbook.org/ns/docbook"
      xmlns:xi="http://www.w3.org/2001/XInclude"
      xmlns:trans="http://docbook.org/ns/transclude"
      version="5.0">
  <title>Definitive Printer Guide</title>
  <chapter xml:id="buy">
    <title>Buying printer</title>
    <para>Grab money, go to shop, ...</para>
  </chapter>
  <chapter>
    <title>Quick installation guide</title>
    <para>Carefully follow all procedures bellow.</para>
    <xi:include href="procedure.001.xml" trans:idfixup="auto" trans:linkscope="local"/>
  </chapter>
  <chapter>
    <title>Maintenance</title>
    <para>Be friendly to your printer when you speak to it.</para>
    <para>If green led is blinking, please add missing paper using the following procedure.</para>
    <xi:include href="procedure.001.xml" trans:idfixup="auto"/>
  </chapter>
</book>

Result of transclusion:

<?xml version="1.0" encoding="UTF-8"?>
<book xmlns="http://docbook.org/ns/docbook" version="5.0">
  <title>Definitive Printer Guide</title>
  <chapter xml:id="buy">
      <title>Buying printer</title>
      <para>Grab money, go to shop, ...</para>
  </chapter>
  <chapter>
      <title>Quick installation guide</title>
      <para>Carefully follow all procedures bellow.</para>
      <procedure xml:base="procedure.001.xml" xml:id="paper-insert---d1e23">
         <title>Inserting paper into printer</title>
         <para>This procedure is targeted to printer owners.
    If you don't have printer, consider <link linkend="buy---d1e23">buying one</link>.</para>  
         <step xml:id="s1---d1e23">
            <para>Make sure that you have paper.</para>
         </step>
         <step>
            <para>Insert paper into printer. If you don't have paper consult <xref linkend="s1---d1e23"/>
            </para>
         </step>
      </procedure>
  </chapter>
  <chapter>
      <title>Maintenance</title>
      <para>Be friendly to your printer when you speak to it.</para>
      <para>If green led is blinking, please add missing paper using the following procedure.</para>
      <procedure xml:base="procedure.001.xml" xml:id="paper-insert---d1e56">
         <title>Inserting paper into printer</title>
         <para>This procedure is targeted to printer owners.
    If you don't have printer, consider <link linkend="buy">buying one</link>.</para>  
         <step xml:id="s1---d1e56">
            <para>Make sure that you have paper.</para>
         </step>
         <step>
            <para>Insert paper into printer. If you don't have paper consult <xref linkend="s1---d1e56"/>
            </para>
         </step>
      </procedure>
  </chapter>
</book>

We used db:linkscope="local" on the first transclusion. This means that no link from this transclusion can point outside of this transclusion. Because there was such link (buy link), the result of transclusion is broken because there is no corresponding target for IDREF buy---d1e23.

This method of transclusion might be useful if you are transcluding foreign content and want to isolate its links.


Example B.5. Manually assigned suffix

<?xml version="1.0" encoding="UTF-8"?>
<book xmlns="http://docbook.org/ns/docbook"
      xmlns:xi="http://www.w3.org/2001/XInclude"
      xmlns:trans="http://docbook.org/ns/transclude"
      version="5.0">
  <title>Definitive Printer Guide</title>
  <chapter xml:id="buy">
    <title>Buying printer</title>
    <para>Grab money, go to shop, ...</para>
  </chapter>
  <chapter>
    <title>Quick installation guide</title>
    <para>Carefully follow all procedures bellow.</para>
    <xi:include href="procedure.001.xml" trans:idfixup="suffix" trans:suffix="_install-proc"/>
  </chapter>
  <chapter>
    <title>Maintenance</title>
    <para>Be friendly to your printer when you speak to it.</para>
    <para>If green led is blinking, please add missing paper using the following procedure.</para>
    <xi:include href="procedure.001.xml" trans:idfixup="suffix" trans:suffix="_maintain-proc"/>
  </chapter>
</book>

Result of transclusion:

<?xml version="1.0" encoding="UTF-8"?>
<book xmlns="http://docbook.org/ns/docbook" version="5.0">
  <title>Definitive Printer Guide</title>
  <chapter xml:id="buy">
      <title>Buying printer</title>
      <para>Grab money, go to shop, ...</para>
  </chapter>
  <chapter>
      <title>Quick installation guide</title>
      <para>Carefully follow all procedures bellow.</para>
      <procedure xml:base="procedure.001.xml" xml:id="paper-insert_install-proc">
         <title>Inserting paper into printer</title>
         <para>This procedure is targeted to printer owners.
    If you don't have printer, consider <link linkend="buy">buying one</link>.</para>  
         <step xml:id="s1_install-proc">
            <para>Make sure that you have paper.</para>
         </step>
         <step>
            <para>Insert paper into printer. If you don't have paper consult <xref linkend="s1_install-proc"/>
            </para>
         </step>
      </procedure>
  </chapter>
  <chapter>
      <title>Maintenance</title>
      <para>Be friendly to your printer when you speak to it.</para>
      <para>If green led is blinking, please add missing paper using the following procedure.</para>
      <procedure xml:base="procedure.001.xml" xml:id="paper-insert_maintain-proc">
         <title>Inserting paper into printer</title>
         <para>This procedure is targeted to printer owners.
    If you don't have printer, consider <link linkend="buy">buying one</link>.</para>  
         <step xml:id="s1_maintain-proc">
            <para>Make sure that you have paper.</para>
         </step>
         <step>
            <para>Insert paper into printer. If you don't have paper consult <xref linkend="s1_maintain-proc"/>
            </para>
         </step>
      </procedure>
  </chapter>
</book>

If we care about the resulting IDs after transclusion we can manually assign some meaningful suffix before IDs in transcluded document.

Although suffixes seems as better approach for automatically generated ones, for manually specified ones prefix could be more useful (for example when HTML filenames are generated based on xml:id value). Should we put prefix option back to the specification?

Example B.6. Disabling ID fixup

<?xml version="1.0" encoding="UTF-8"?>
<book xmlns="http://docbook.org/ns/docbook"
      xmlns:xi="http://www.w3.org/2001/XInclude"
      version="5.0">
  <title>Definitive Printer Guide</title>
  <chapter xml:id="buy">
    <title>Buying printer</title>
    <para>Grab money, go to shop, ...</para>
  </chapter>
  <chapter>
    <title>Quick installation guide</title>
    <para>Carefully follow all procedures bellow.</para>
    <xi:include href="procedure.001.xml"/>
  </chapter>
  <chapter>
    <title>Maintenance</title>
    <para>Be friendly to your printer when you speak to it.</para>
    <para>If green led is blinking, please add missing paper using the following procedure.</para>
    <xi:include href="procedure.001.xml"/>
  </chapter>
</book>

Result of transclusion:

<?xml version="1.0" encoding="UTF-8"?>
<book xmlns="http://docbook.org/ns/docbook" version="5.0">
  <title>Definitive Printer Guide</title>
  <chapter xml:id="buy">
      <title>Buying printer</title>
      <para>Grab money, go to shop, ...</para>
  </chapter>
  <chapter>
      <title>Quick installation guide</title>
      <para>Carefully follow all procedures bellow.</para>
      <procedure xml:base="procedure.001.xml" xml:id="paper-insert">
         <title>Inserting paper into printer</title>
         <para>This procedure is targeted to printer owners.
    If you don't have printer, consider <link linkend="buy">buying one</link>.</para>  
         <step xml:id="s1">
            <para>Make sure that you have paper.</para>
         </step>
         <step>
            <para>Insert paper into printer. If you don't have paper consult <xref linkend="s1"/>
            </para>
         </step>
      </procedure>
  </chapter>
  <chapter>
      <title>Maintenance</title>
      <para>Be friendly to your printer when you speak to it.</para>
      <para>If green led is blinking, please add missing paper using the following procedure.</para>
      <procedure xml:base="procedure.001.xml" xml:id="paper-insert">
         <title>Inserting paper into printer</title>
         <para>This procedure is targeted to printer owners.
    If you don't have printer, consider <link linkend="buy">buying one</link>.</para>  
         <step xml:id="s1">
            <para>Make sure that you have paper.</para>
         </step>
         <step>
            <para>Insert paper into printer. If you don't have paper consult <xref linkend="s1"/>
            </para>
         </step>
      </procedure>
  </chapter>
</book>

Default behaviour of XInclude is not to do any postprocessing like DocBook transclusions. The resulting document thus contain duplicated IDs and it is not valid.


Example B.7. Chaining of suffixes

Suppose we have note in a separate file (note.001.xml):

<?xml version="1.0" encoding="UTF-8"?>
<note xmlns="http://docbook.org/ns/docbook" xml:id="note">
  <para>Important note.</para>
</note>

We transclude it into another file (procedure.002.xml) with manual suffix assignment:

<?xml version="1.0" encoding="UTF-8"?>
<procedure xmlns="http://docbook.org/ns/docbook" xml:id="paper-insert"
  xmlns:xi="http://www.w3.org/2001/XInclude"
  xmlns:trans="http://docbook.org/ns/transclude">
  <title>Inserting paper into printer</title>
  <para>This procedure is targeted to printer owners.
    If you don't have printer, consider <link linkend="buy">buying one</link>.</para>  
  <step xml:id="s1"><para>Make sure that you have paper.</para></step>
  <step><para>Insert paper into printer. If you don't have paper consult <xref linkend="s1"/></para></step>
  <step>
    <xi:include href="note.001.xml" trans:idfixup="suffix" trans:suffix="_note001"/>
  </step>  
</procedure>

And then this procedure is transcluded into master document, again with manually specified suffix:

<?xml version="1.0" encoding="UTF-8"?>
<book xmlns="http://docbook.org/ns/docbook"
      xmlns:xi="http://www.w3.org/2001/XInclude"
      xmlns:trans="http://docbook.org/ns/transclude"
      version="5.0">
  <title>Definitive Printer Guide</title>
  <chapter xml:id="buy">
    <title>Buying printer</title>
    <para>Grab money, go to shop, ...</para>
  </chapter>
  <chapter>
    <title>Maintenance</title>
    <para>Be friendly to your printer when you speak to it.</para>
    <para>If green led is blinking, please add missing paper using the following procedure.</para>
    <xi:include href="procedure.002.xml" trans:idfixup="suffix" trans:suffix="_procedure002"/>
  </chapter>
</book>

In transcluded content ID of note contains chained suffix:

<?xml version="1.0" encoding="UTF-8"?>
<book xmlns="http://docbook.org/ns/docbook" version="5.0">
  <title>Definitive Printer Guide</title>
  <chapter xml:id="buy">
      <title>Buying printer</title>
      <para>Grab money, go to shop, ...</para>
  </chapter>
  <chapter>
      <title>Maintenance</title>
      <para>Be friendly to your printer when you speak to it.</para>
      <para>If green led is blinking, please add missing paper using the following procedure.</para>
      <procedure xml:base="procedure.002.xml" xml:id="paper-insert_procedure002">
         <title>Inserting paper into printer</title>
         <para>This procedure is targeted to printer owners.
    If you don't have printer, consider <link linkend="buy">buying one</link>.</para>  
         <step xml:id="s1_procedure002">
            <para>Make sure that you have paper.</para>
         </step>
         <step>
            <para>Insert paper into printer. If you don't have paper consult <xref linkend="s1_procedure002"/>
            </para>
         </step>
         <step>
            <note xml:base="note.001.xml" xml:id="note_procedure002_note001">
               <para>Important note.</para>
            </note>
         </step>  
      </procedure>
  </chapter>
</book>


C. DocBook schema with support for transclusions

TBD

D. Sample transclusion processor written in XSLT 2.0

Please note that this sample transclusion processor is not yet feature complete. It supports only subset of proposal.

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
                xmlns:f="http://docbook.org/xslt/ns/extension"
                xmlns:mp="http://docbook.org/xslt/ns/mode/private"
                xmlns:db="http://docbook.org/ns/docbook"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns:ta="http://docbook.org/ns/transclude"
                xmlns:xia="http://www.w3.org/2001/XInclude/local-attributes"
                exclude-result-prefixes="f mp xs ta xia">

<!-- Remove for production files, pretty print can harm mixed content -->
<xsl:output indent="yes"/>

<xsl:template match="/">
  <xsl:variable name="adjusted" select="f:adjust-ids(/)"/>
  <xsl:variable name="result" select="f:adjust-idrefs($adjusted)"/>
  <xsl:sequence select="f:transclude-cleanup($result)"/>
</xsl:template>

<!-- Separator for auto generated suffixes -->
<xsl:param name="psep" select="'---'"/>

<!-- Function and mode for changing IDs based on provided suffix -->
<xsl:function name="f:adjust-ids" as="node()+">
  <xsl:param name="doc" as="node()+"/>

  <xsl:apply-templates select="$doc" mode="mp:transclude"/>
</xsl:function>

<xsl:template match="node()" mode="mp:transclude">
  <xsl:param name="idfixup" select="'none'" tunnel="yes"/>
  <xsl:param name="suffix" tunnel="yes"/>
  <xsl:copy>
    <xsl:copy-of select="@* except @xml:id"/>
    <xsl:if test="@xml:id">
      <xsl:choose>
        <xsl:when test="($idfixup = 'none')">
          <xsl:copy-of select="@xml:id"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:attribute name="xml:id" select="concat(@xml:id, $suffix)"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:if>
    <xsl:apply-templates mode="mp:transclude"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="node()[@ta:*]" mode="mp:transclude">
  <xsl:param name="idfixup" select="'none'" tunnel="yes"/>
  <xsl:param name="suffix" tunnel="yes"/>

  <xsl:variable name="new-idfixup" select="if (@ta:idfixup) then @ta:idfixup else $idfixup"/>
  <xsl:variable name="linkscope" select="if (@ta:linkscope) then @ta:linkscope else 'near'"/>
  <xsl:variable name="new-suffix">
    <xsl:choose>
      <xsl:when test="$new-idfixup = 'auto'">
        <xsl:sequence select="concat($psep, generate-id(.))"/>
      </xsl:when>
      <xsl:when test="$new-idfixup = 'suffix'">
        <xsl:sequence select="concat($suffix, @ta:suffix)"/>
      </xsl:when>
      <xsl:otherwise></xsl:otherwise>
    </xsl:choose>
  </xsl:variable>

  <xsl:copy>
    <xsl:copy-of select="@* except @xml:id"/>
    <xsl:if test="@xml:id">
      <xsl:choose>
        <xsl:when test="($new-idfixup = 'none')">
          <xsl:copy-of select="@xml:id"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:attribute name="xml:id" select="concat(@xml:id, $new-suffix)"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:if>
    <xsl:attribute name="ta:suffix" select="$new-suffix"/>
    <xsl:apply-templates mode="mp:transclude">
      <xsl:with-param name="idfixup" select="$new-idfixup" tunnel="yes"/>
      <xsl:with-param name="suffix" select="$new-suffix" tunnel="yes"/>
    </xsl:apply-templates>
  </xsl:copy>  
</xsl:template>

<!-- Function and mode for adjusting references to IDs -->
<xsl:function name="f:adjust-idrefs" as="node()+">
  <xsl:param name="doc" as="node()+"/>

  <xsl:apply-templates select="$doc" mode="mp:adjust-idrefs"/>
</xsl:function>

<xsl:template match="node()|@*" mode="mp:adjust-idrefs">
  <xsl:copy>
    <xsl:apply-templates select="@* | node()" mode="mp:adjust-idrefs"/>
  </xsl:copy>
</xsl:template>

<!-- FIXME: add support for @linkends, @zone, @arearefs -->
<!-- FIEMX: add support for xlink:href starting with # -->
<xsl:template match="@linkend | @endterm | @otherterm | @startref" mode="mp:adjust-idrefs">
  <xsl:variable name="idref" select="."/>

  <xsl:variable name="annotation" select="ancestor-or-self::*[@ta:linkscope][1]"/>
  <xsl:variable name="linkscope" select="($annotation/@ta:linkscope, 'near')[1]"/>
  <xsl:variable name="suffix" select="$annotation/@ta:suffix"/>

  <xsl:attribute name="{local-name(.)}">
    <xsl:choose>
      <xsl:when test="$linkscope = 'user'">
        <xsl:value-of select="$idref"/>
      </xsl:when>
      <xsl:when test="$linkscope = 'local'">
        <xsl:value-of select="concat($idref, $suffix)"/>
      </xsl:when>
      <xsl:when test="$linkscope = 'near'">
        <xsl:value-of select="f:nearest-matching-id($idref, ..)"/>
      </xsl:when>
      <xsl:when test="$linkscope = 'global'">
        <xsl:value-of select="f:nearest-matching-id($idref, root(.))"/>
      </xsl:when>
    </xsl:choose>
  </xsl:attribute>
</xsl:template>

<!-- Function searches nearest matching ID in a given context -->
<xsl:function name="f:nearest-matching-id" as="xs:string?">
  <xsl:param name="idref" as="xs:string"/>
  <xsl:param name="context" as="node()"/>

  <!-- FIXME: key() requires document-node() rooted subtree -->
  <!--  <xsl:variable name="targets" select="key('unprefixed-id', f:unprefixed-id($idref, $context), $context)"/> -->
  <xsl:variable name="targets" select="$context//*[@xml:id][f:unprefixed-id(@xml:id, .) eq f:unprefixed-id($idref, $context)]"/> 

  <xsl:choose>
    <xsl:when test="not($targets) and $context/..">
      <xsl:sequence select="f:nearest-matching-id($idref, $context/..)"/>
    </xsl:when>
    <xsl:when test="$targets">
      <xsl:sequence select="$targets[1]/string(@xml:id)"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:message>Error: no matching ID for reference "<xsl:value-of select="$idref"/>" was found.</xsl:message>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

<!-- FIXME: type annotation should be without ?, find why it is called with empty sequence -->
<xsl:function name="f:unprefixed-id" as="xs:string?">
  <xsl:param name="id" as="xs:string?"/>
  <xsl:param name="context" as="node()"/>
  
  <xsl:variable name="suffix" select="$context/ancestor-or-self::*[@ta:suffix][1]/@ta:suffix"/>

  <xsl:sequence select="if ($suffix) then substring-before($id, $suffix) else $id"/>
</xsl:function>

<!--
<xsl:key name="unprefixed-id" match="*[@xml:id]" use="f:unprefixed-id(@xml:id, .)"/>
-->

<!-- Function and mode for removing transclusion attributes from the final output -->
<xsl:function name="f:transclude-cleanup" as="node()+">
  <xsl:param name="doc" as="node()+"/>
  
  <xsl:apply-templates select="$doc" mode="mp:transclude-cleanup"/>
</xsl:function>
  
<xsl:template match="node()" mode="mp:transclude-cleanup">
  <xsl:copy>
    <xsl:apply-templates mode="mp:transclude-cleanup"/>
  </xsl:copy>
</xsl:template>      

<xsl:template match="*" mode="mp:transclude-cleanup" priority="10">
  <xsl:element name="{name()}" namespace="{namespace-uri()}">
    <xsl:copy-of select="@* except @ta:*"/>
    <xsl:apply-templates mode="mp:transclude-cleanup"/>
  </xsl:element>
</xsl:template>      
  
</xsl:stylesheet>

Bibliography

[XI11] XML Inclusions (XInclude) Version 1.1. W3C Working Draft. 26 November 2014. Available at http://www.w3.org/XML/2012/08/xinclude-11/



[1] For example XSLT based implementations can use generate-id() function to generate such unique suffix.

Attachment: signature.asc
Description: OpenPGP digital signature



[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]