XSLT coding practices in the DITA-OT
Wiki page: Submitted by robander on Fri, 2009-04-03 19:55. Last updated on Mon, 2009-04-06 04:41.
XSLT Coding practices in the DITA-OT
The core developers on the DITA Open Toolkit generally try to keep several coding practices and design patterns in mind when adding to the toolkit's XSLT code. If you are interested in digging around in the DITA Open Toolkit, or in contributing XSLT patches back to the core toolkit, you may want to keep these practices in mind:
- The toolkit follows the modularization rules spelled out in the DITA Architectural Specification. All XSLT steps use a wrapper that imports processing rules, to allow for additional extensions / customizations. See Modularization in XSLT from the DITA specification.
- Always use the specialized form to refer to elements. Never use a literal element name in an XPATH expression. (The one exception is the <dita> element, which does not have a class attribute). For example, instead of matching "table", match "*[contains(@class,' topic/table ')]". It's more verbose and a bit harder to read, but it's what makes specialized processing possible.
- Do not use priority attributes. The toolkit code is written to expect overrides (related to specialization or otherwise). If XSLT for one specialization uses priorities, then all overrides of that module must copy or increase the priority, making management difficult. It is better to simply let XSLT's native import precedence determine priority.
- Always use mode templates in place of named templates. Name templates are only appropriate for basic functions unrelated to the context, such as string operations ("get-extension"); although even basic functions also work as modes. The reason is that it is possible to override mode templates; in addition, it becomes easy to override a particular class of elements. For example, with a template named "add-linking-attributes", you can only replace that template for every element. With match="*" and mode="add-linking-attributes", you can create an override that updates your specialized <xref> but leaves <xref> itself untouched.
- If you are patching code in a manner that replaces existing named templates, do not remove the named template, which may break existing customizations. Instead, the named template should be re-written to call its replacement.
- When mode templates are added to the preprocessing modules, they should contain namespaces. Most of the modules already define these namespaces, so the same pattern should be followed (such as "mappull:" and "topicpull:"). The existing modes and their purpose should be described in a comment at the top of the file.
- New error messages should always be created with a mode template that uses the ditamsg: namespace; the mode should describe the message. For example:<xsl:apply-templates select="." mode="ditamsg:required-cleanup-in-content"/>
- The message itself should be defined at the end of the module:
<xsl:template match="*" mode="ditamsg:required-cleanup-in-content">
<xsl:call-template name="output-message">
<xsl:with-param name="msgnum">039</xsl:with-param>
<xsl:with-param name="msgsev">W</xsl:with-param>
</xsl:call-template>
</xsl:template>
Keeping messages out of line has many advantages:
- It is easy to selectively override a message for a specialized element
- It is easy to override a single message if you do not want it to appear (you override the message, not the element that generates it)
- It is easier to reuse messages, and the message number is only defined once in a file
- The mode name is self-documenting, indicating what the message is about
- In the future we may group message into a single imported file, so messages may be reused between modules
- Write for XSLT 1.0 compatibility where possible. Avoid EXSL extensions, particularly where they do not have a counterpart in XSLT 2.0. Avoid Java extensions. Make liberal use of <xsl:fallback> to inform the user that a feature is not going to work, or will work less optimally, with an XSLT 1.0 processor.
- Login to post comments
- 10414 reads