Adding new profiling attributes

Your need for profiling conditions may go beyond those provided by the standard DocBook profiling attributes, most of which are computer related (os, arch, etc.). What if you want to profile on model number, or OEM business name, or some other property for which there is no suitable attribute in DocBook?

If you want to add custom attributes to DocBook and use them for profiling, you need to take two steps:

  1. Add the attribute declarations to the DocBook DTD (DocBook version 4) or RelaxNG (DocBook version 5).

  2. Add support for your new attributes in the stylesheets.

Adding attributes to the DTD

Adding new profiling attributes to the DocBook 4 DTD is pretty easy because the DocBook DTD has hooks for customization in the form of empty parameter entities. A parameter entity is an entity that is used only in the DTD. If you declare such an entity before the empty declaration, then your entity's content will take precedence and be merged into the DTD.

The DocBook 4 DTD has a set of common attributes that are available on almost all elements. A subset of those common attributes are the profiling attributes, and they are declared in a parameter entity named effectivity.attrib. There is another parameter entity named local.effectivity.attrib that can be used to add new attributes.

You can extend the DTD in the internal or external subset of the DTD. The internal DTD subset is declared in the DOCTYPE inside your documents. The following example declares two new profiling attributes:

<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "docbookx.dtd" [
<!ENTITY % local.effectivity.attrib 
   "model  CDATA  #IMPLIED
    oem  CDATA  #IMPLIED">
]>
<book>
...

If you have a lot files, adding declarations to the internal subset can be a tedious process. In such cases, it is usually easier to add to the external DTD subset, which is in the DTD files stored outside the documents. For DocBook, you can create a custom DTD file that contains your custom parameter entity declarations and then imports the standard DTD.

<!ENTITY % local.effectivity.attrib 
   "model  CDATA  #IMPLIED
    oem  CDATA  #IMPLIED">

<!ENTITY % DocBookDTD PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
                "docbookx.dtd">
%DocBookDTD;

This example assumes you are putting the custom DTD in the same directory as docbookx.dtd. You can use a relative path, an absolute path, or a catalog entry to resolve the path. Then the DOCTYPEs in your documents just need to reference your custom DTD file instead of the standard DTD. You can avoid that editing chore by using an XML catalog file to redirect your existing PUBLIC or SYSTEM identifier to your new file.

Once you have added the new attribute declarations, you can use your new attributes in your documents for profiling. For example:

<para oem="acme">The Acme Company ...</para>
<para oem="bingham">The Bingham Company ...</para>

Adding attributes to RelaxNG

If you are using DocBook version 5, then the standard schema for it is written in RelaxNG. The schema is written using the compact syntax of RelaxNG, and it is structured to make it easy to add attributes in a customization of the schema. The flexibile parameter entity structure used in DocBook 4 is replaced with an even more flexible named pattern system in DocBook 5's RelaxNG. Although there is a DTD version of DocBook 5 available, but it is not structured with parameter entities as in DocBook 4, so it is harder to customize.

To add an attribute to the RelaxNG schema in the compact syntax, you create a new file that imports the stock schema and then adds any changes. To add an attribute, you must first find the named pattern in the schema that would best hold your new attributes and then use the RelaxNG append syntax. Here is an example similar to the one in the previous section.

namespace db = "http://docbook.org/ns/docbook"

include "docbook.rnc" inherit = db

db.effectivity.attributes &=
  attribute model { text }?
  & attribute oem { text }?

The &= syntax means to append these new attributes to the existing pattern named db.effectivity.attributes. That pattern contains the other profiling attribute declarations, and is part of the common attributes used by most elements.

Profiling with new attributes

Once you have created your new attributes, you need to customize the stylesheets to recognize and respond to them for profiling. This can be done by copying and customizing one big template from the stylesheet module profiling/profile-module.xsl. This needs to be done in a customization of a profiling stylesheet, as described in the section “Customization and profiling”.

<xsl:template match="*" mode="profile">  1

  <xsl:variable name="arch.content">  2
    <xsl:if test="@arch">
      <xsl:call-template name="cross.compare">
        <xsl:with-param name="a" select="$profile.arch"/>
        <xsl:with-param name="b" select="@arch"/>
      </xsl:call-template>
    </xsl:if>
  </xsl:variable>
  <xsl:variable name="arch.ok" select="not(@arch) or not($profile.arch) or
                                       $arch.content != '' or @arch = ''"/>

  <xsl:variable name="oem.content">  3
    <xsl:if test="@oem">
      <xsl:call-template name="cross.compare">
        <xsl:with-param name="a" select="$profile.oem"/>
        <xsl:with-param name="b" select="@oem"/>
      </xsl:call-template>
    </xsl:if>
  </xsl:variable>
  <xsl:variable name="oem.ok" 4
                select="not(@oem) or not($profile.oem) or
                                   $oem.content != '' or @oem = ''"/>
...

  <xsl:if test="$arch.ok and $oem.ok and $condition.ok and 5
      $conformance.ok and $lang.ok and $os.ok and
      $revision.ok and $revisionflag.ok and $role.ok and 
      $security.ok and $status.ok and $userlevel.ok and 
      $vendor.ok and $attribute.ok">
    <xsl:copy>  6

1

This is the main template for selecting profiled content. It matches on all elements.

2

This variable is an example of how an existing profile attribute such as arch is handled. You should copy these lines and change the name for your new attribute.

3

New variables created for a new profile attribute, modeled after an existing profile attribute.

4

This variable determines if the new attribute is to be selected during profiling.

5

Include the oem.ok variable in the final test where all conditions are applied.

6

If the profiling attributes permit, then copy the current element to the output. Thus this element is selected for inclusion during profiling.