As your software development project and development team grow, you might need to create reference documentation such as a user guide for internal or external use. Creating this sort of documentation becomes more cumbersome the longer you defer it. Developing a framework that supports creating multiple types of documentation from a single source can be advantageous for small and large projects alike; with forethought, you can also leverage this documentation to support your project's quality assurance (QA) and testing needs. This article shows how the DITA and XSLT 2.0 transformations can facilitate a single-sourcing strategy for both development and user documentation.
The XSL transforms provided with this article (see Download) are an extension of an open source project I developed five years ago as an attempt to shorten both documentation and QA time. I wanted to reduce the task of collecting use cases and turning them into client acceptance tests, which were then reused as a training resource for new developers. In some respects, this project reflects a breakdown of business intelligence; I played the role of QA, technical writer, and development lead. Taken in another light, I see this work as an early indicator of agile strategies that I have found indispensable in subsequent projects—surfacing often by facilitating client walk-throughs, looser coupling with use cases, and getting just enough done to move forward.
As this project grew, I ended up with a large XML file persisted in an XML DBMS. It contains a description of the high-level application architecture of the software under development and was broken into modules, pages, page states, and controls on the page. Along with this file, I built a collection of XQuery and XSL transforms that could extract and publish a user guide, an acceptance test document, and an RSS feed containing a navigation path through the application based on changes made in the previous two-week period. The RSS feed drove the manual testing effort.
At the time, although I had heard of DITA, I had no practical experience with what was then a relatively new specification. So, I created my own schema, started to collect data, and developed my transforms. My reading about DITA no doubt influenced the approach I took as I:
- Addressed modularity and reuse
- Wrote a basic topic structure
- Created collections of concepts and task lists
Start with DITA topics: concepts, tasks, and topic maps
The sample application this article describes is incredibly simple. It has a home page and a three-page wizard that you can use to enter the name and address of a person. This application does not actually exist—that is, it exists only in theory. It contains a single path (although I intend to expand the sample files to include multiple alternate flows in a future iteration).
The data used to create the user guide is separated into pages and cases, where each page represents a single HTML page and a case represents a simple use case, such as "Enter your name into the name field, and verify that it is capitalized properly." These topics are collected into a DITA topic map, which you can use to generate a PDF file containing a page-by-page user guide using the DITA Open Toolkit.
The DITA approach to topic-based writing focuses on three fundamental types of topic:
- Concepts, which tend to be abstract
- References, which tend to be more concrete
- Tasks, which describe the steps taken to accomplish something
Listing 1 shows a sample concept; Listing 2 shows a sample task. Once you have a number of written topics, you can collect and organize them into a document using a topic map, which is similar to table of contents. You can use the same topics with multiple topic maps to produce multiple documents.
Each page in the sample application is represented with a DITA concept, tying together a description of the page’s purpose, a collection of the navigation controls on the page, and references to any use cases that are appropriate for this page. You can see in Listing 1 how the DITA concept describing a page contains a description of the UI elements on the page and references to a single use case task.
Listing 1. A DITA concept for an application page
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE concept PUBLIC "-//OASIS//DTD DITA Concept//EN"
"../../dtd/concept.dtd">
<concept id="wiz2" xml:lang="en-us">
<title>Wizard Page 2</title>
<conbody>
<p>Name Details</p>
<section>
<title>User Interface: Controls</title>
<screen>
<uicontrol id="wiz3">Continue</uicontrol>
<uicontrol importance="optional"
id="cancel">Cancel</uicontrol>
</screen>
</section>
<section>
<title>Use Cases</title>
<xref href="../cases/case_004.dita" type="task"/>
</section>
</conbody>
</concept>
|
The elements screen and uicontrol
are typically used in DITA documents to describe UI components. They're used for
this purpose in this article as well, but as you will see, these elements also
calculate a navigation path through the sample application.
Use cases are represented with DITA tasks, which identify a discrete set of steps taken
to produce a result. When I used this approach to document an actual
application, I also added cases for known issues, tagged with a keyword
regression, and excluded them from the user guide.
When the topic map is repurposed for use as a testing document, these regression
tests can be included, providing a context for manual testing.
Listing 2 shows a DITA task detailing the steps required to reproduce an action that can be carried out on a page. Notice how one of the steps—adding a middle name—is marked as optional.
Listing 2. A DITA task for an application use case
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE task PUBLIC "-//OASIS//DTD DITA Task//EN"
"../../dtd/task.dtd">
<task id="case_004" xml:lang="en-us">
<title>Case 004</title>
<prolog></prolog>
<taskbody>
<context><p>context: case 004</p></context>
<steps>
<step><cmd>Enter First Name</cmd></step>
<step><cmd>Enter Last Name</cmd></step>
<step importance="optional"><cmd>Enter Middle Name</cmd></step>
</steps>
</taskbody>
</task>
|
The folder structure for the sample DITA project is very flat, with directories for cases and pages. Later, these directories will be accompanied by a directory for tests. In addition, a directory is maintained for the XSL transforms used to generate the test topics. DITA topic maps are kept in the root of the project.
The DITA topic map for this simple application, in Listing 3, is also simple. When you use the DITA Open Toolkit to generate a user guide, the results are straightforward and useful, and you can easily add information to the individual page files to add complexity and depth. You can see how the topic map is like a table of contents containing four sections.
Listing 3. A DITA topic map
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE map PUBLIC "-//OASIS//DTD DITA Map//EN"
"../dtd/map.dtd">
<map title="Sample Application User Guide">
<topicref href="pages/home.dita" type="concept" id="home"/>
<topicref href="pages/wiz1.dita" type="concept"/>
<topicref href="pages/wiz2.dita" type="concept"/>
<topicref href="pages/wiz3.dita" type="concept"/>
</map>
|
Transform topics into a walk-through document
Because the DITA screen and uicontrol
elements were used to describe the navigation controls (links, buttons, and
menus) on a page, it is not a complicated piece of engineering to extract
information from the individual DITA page files and use this information to create
a new set of DITA tasks. These tasks describe how to navigate from one page to
another—for instance, as in the navigation task nav_home_wiz1.dita,
in Listing 4. You can see how the naming convention
concatenates the identifiers for the two pages to represent navigation from one
to the other; the information from the original page concept now represents a
navigation task.
Listing 4. A navigation task
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE task PUBLIC "-//OASIS//DTD DITA Task//EN" "../dtd/task.dtd">
<task id="nav_home_wiz1.dita" xml:lang="en-us">
<title>Navigate to Wizard Page 1</title>
<prolog/>
<taskbody>
<steps>
<step>
<cmd>On Home Page, click
<uicontrol>Launch Wizard</uicontrol>
</cmd>
</step>
<step>
<cmd>Verify that Wizard Page 1 loads</cmd>
</step>
</steps>
</taskbody>
</task>
|
The navigation tasks are kept in a new directory called tests alongside the pages and cases directories. In addition to these tasks, tests contains a new set of test concepts—one for each page—that simply identify that the page is being tested. You can expand these concepts, like the wizard page testing concept in Listing 5, to include more information about how to test the page—for instance, identifying which pages apply to which user roles, priority and severity of testing, and so on.
Listing 5. A testing concept
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE concept PUBLIC "-//OASIS//DTD DITA Concept//EN" "../dtd/concept.dtd">
<concept id="test_wiz1.dita" xml:lang="en-us">
<title>Wizard Page 1</title>
<conbody>
<p>This is the first wizard page: Name Details</p>
</conbody>
</concept>
|
The information contained in each test concept document is drawn directly from a DITA concept in the pages directory. In fact, all the topics contained in the tests directory are generated directly from the topics in the other two directories and the user guide topic map (in Listing 3) using XSLT. Listing 6 shows a new walk-through topic map that is also generated from these same files. When you supply the walk-through topic map as a parameter to a build script in the DITA Open Toolkit, the toolkit uses the new tasks and concepts to generate a walk-through script that traverses the navigation graph for the sample application. The result is a path through the application that guides a structured walk-through of the application for either internal audit or client use.
For each page, the walk-through script also contains acceptance criteria drawn from the use cases, which you can use as a talking point during a client demo or manual testers can use during user or factory acceptance testing. And because you can regenerate the entire tests directory whenever the content in the other two directories is altered, you can regenerate this document and use it at any stage in your development cycle, whether you have a single page or a hundred pages.
Listing 6. The walk-through DITA topic map
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE map PUBLIC "-//OASIS//DTD DITA Map//EN" "../dtd/map.dtd">
<map title="Sample Application User Guide">
<topicref href="tests/test_home.dita" type="concept">
<topicref href="pages/../cases/case_001.dita" type="task"/>
<topicref href="pages/../cases/case_002.dita" type="task"/>
</topicref>
<topicref href="tests/test_wiz1.dita" type="concept">
<topicref href="tests/nav_home_wiz1.dita" type="task"/>
<topicref href="pages/../cases/case_003.dita" type="task"/>
</topicref>
<topicref href="tests/test_wiz2.dita" type="concept">
<topicref href="tests/nav_wiz1_wiz2.dita" type="task"/>
<topicref href="pages/../cases/case_004.dita" type="task"/>
</topicref>
<topicref href="tests/test_wiz3.dita" type="concept">
<topicref href="tests/nav_wiz2_wiz3.dita" type="task"/>
<topicref href="pages/../cases/case_005.dita" type="task"/>
<topicref href="pages/../cases/case_006.dita" type="task"/>
</topicref>
<topicref href="tests/test_home.dita" type="concept">
<topicref href="tests/nav_wiz3_home.dita" type="task"/>
</topicref>
</map>
|
Streamline for an XSLT 2.0 rescue
When I first developed a schema to model the information used to create and
repurpose these documents, I attempted to avoid an issue that I encountered on
an earlier project. Previously, I had developed schemas that were too granular; now,
conversely, my file was too monolithic, keeping all of my XML in a single file. This idea
does have several advantages, of course, such as reducing file administration and
versioning issues, while also reducing the complexity of the transforms necessary
to generate new information. Although a monolithic approach is possible
with DITA using the ditabase element (which basically
serves as a container for DITA topics such as concept,
task, and reference), a
common best practice in the DITA community is to create one DITA topic for each file.
A more granular approach such as this allows superior version control and facilitates
reuse and repurposing, which is really the point of the current undertaking.
To make it as granular as possible, which is what I have done, is more efficient.
Regarding the XSL transform itself, increased granularity raises two major issues:
pulling information out of multiple files and then pushing information back into
multiple files. To retrieve information from multiple files, I used the
xsl:document() function, which is easy to use as long
as you are dealing with a flat file structure. To generate multiple documents in the
tests directory from these various DITA documents, I used the
xsl:result-document element, which was introduced
with XSLT 2.0. Listing 7 and Listing 8
demonstrate how you would use xsl:result-document
in the XSL transform to create a new concept and a new task.
Listing 7. Using xsl:result-document to generate a DITA concept
<xsl:result-document href="..\{$doc-path-test}"
doctype-system="../dtd/concept.dtd"
doctype-public="-//OASIS//DTD DITA Concept//EN">
<concept id="{$doc-name-test}" xml:lang="en-us">
<title>
<xsl:value-of select="title"/>
</title>
<conbody>
<p>
<xsl:value-of select="conbody/p"/>
</p>
</conbody>
</concept>
</xsl:result-document>
|
Note: Notice how in both Listing 7 and
Listing 8 the doctype-system and
doctype-public attributes available to
xsl:output-encoding are also available for the
xsl:result-document element. Without these, it is not
possible to attach the appropriate DITA DTDs to the generated files; without these
DTDs, you cannot use the generated files with the DITA Open Toolkit. Therefore, the use of
these attributes is critical.
Also, whereas using DITA tasks to represent use cases makes reasonable sense, representing pages with DITA references rather than concepts also is sensible because they refer to real-world things such as HTML pages. I decided to use concepts to represent pages because I knew that I would generate the more abstract test concepts from them and that I wanted to maintain this alignment. In other words, this was an arbitrary choice.
In Listing 8, you can see how the XSLT to generate a navigation task document is a bit more complicated than that used to generate a concept.
Listing 8. Using xsl:result-document to generate a DITA task
<xsl:result-document href="..\{$doc-path-nav}"
doctype-system="../dtd/task.dtd"
doctype-public="-//OASIS//DTD DITA Task//EN">
<task id="{$doc-name-nav}" xml:lang="en-us">
<title>Navigate to <xsl:value-of select="title"/>
</title>
<prolog/>
<taskbody>
<steps>
<step>
<cmd>On <xsl:value-of select="$source_title"/>,
click <xsl:copy-of select="$uicontrol"/>
</cmd>
</step>
<step>
<cmd>Verify that
<xsl:value-of select="title"/> loads</cmd>
</step>
</steps>
</taskbody>
</task>
</xsl:result-document>
|
Again, notice the use of the doctype-system and
doctype-public attributes to attach the appropriate
OASIS DITA DTD to the topic that the XSL transform created. Refer to
Listing 4 to see an example of the task created.
When the new documents are generated, they are referenced within the same
XSL transform that generated them, as in Listing 9.
You use these references to create the new walk-through topic map from the
existing user guide topic map by recursively following the id
attributes contained within the uicontrol elements
in the source page concepts. Using XSLT 2.0, I was able to use a single
transformation to create the topic map and all supporting files—an
accomplishment that simply would not be possible (or at the very least would
not be enjoyable) using XSLT 1.0.
Listing 9. Referencing the generated testing concept and task
<topicref href="{$doc-path-test}" type="concept">
<topicref href="{$doc-path-nav}" type="task"/>
<xsl:if test="@id != 'home' ">
<xsl:apply-templates select="conbody" mode="cases"/>
</xsl:if>
</topicref>
|
Note: To see the full XSL transform, download the attached sample files.
Whenever you change the content used to generate these topics, you can regenerate new topics so the walk-through or acceptance documentation is timely and up to date. For instance, a build script might remove any existing generated files, run the user guide-to-walk-through transform, then use the DITA Open Toolkit build scripts to generate current copies of the user guide and acceptance or walk-through documents as PDF files.
Because the DITA screen and uicontrol
elements describe navigation controls (see Listing 1),
traversing a path through the application becomes a matter of simple recursion. I
used the importance attribute (which is common to
DITA elements) throughout to represent navigation controls that are optional, such
as Cancel buttons, which can be ignored for the purpose of
navigation. A similar strategy is used to prevent the dreaded stack overflow, which
occurs when navigating away from a page returns flow to a page that was
previously traversed. I also found the otherprops
attribute to be useful for this purpose—again, because it is common and
easily available to all DITA elements.
For a simple application, I have described a simple transform. I hope that this article demonstrates how to develop a strategy of document reuse along with some benefits of initiating documentation projects early so you can repurpose them both immediately and throughout the life cycle of your software project. Using a single source to generate multiple document projects that crosscut the various stages of the development cycle opens further opportunities to leverage this shared knowledge. This approach is important because if a documentation is used by multiple stakeholders in a software project, it is much more likely to be maintained and to gain value over time.
Applying a more flexible approach to documentation also has the advantage of crosscutting methodologies. If you are involved with a client, for example, who demands a high level of formality and ceremony but your development team practices an agile methodology, repurposing documentation might be exactly the approach you need to address the demands of both your client and your chosen methodology. If this is the case, DITA and XSLT 2.0 might be just the tools you need.
| Description | Name | Size | Download method |
|---|---|---|---|
| Source files for the DITA project | sample_code.zip | 44KB | HTTP |
Information about download methods
Learn
- Introduction to Darwin Information Typing Architecture (Don Day, Michael Priestley, and David Schell, developerWorks, September 2005): Discover fundamental DITA terminology and ideas.
- Darwin Information Typing Architecture (DITA XML): Find out more about DITA at the OASIS Cover Pages.
- Saxon: Anatomy of an XSLT processor (Michael Kay, developerWorks, February 2001): See how Saxon led the way in adoption of the XSLT 2.0 specification.
- CaseBook (SourceForge, February 2007): Visit the open source project that inspired this article.
- More DITA-related content (developerWorks, January 2005 - current): Find articles and tutorials about DITA.
- XML area on developerWorks: Get the resources you need to advance your skills in the XML arena.
- IBM XML certification: Find out how you can become an IBM-Certified Developer in XML and related technologies.
- XML technical library: See the developerWorks XML Zone for a wide range of technical articles and tips, tutorials, standards, and IBM Redbooks.
- developerWorks technical events and webcasts: Stay current with technology in these sessions.
- developerWorks on Twitter: Join today to follow developerWorks tweets.
- developerWorks
podcasts: Listen to interesting interviews and discussions for software developers.
Get products and technologies
- DITA Open Toolkit: Download the open source toolkit for processing DITA.
- IBM product evaluation versions: Download or explore the online trials in the IBM SOA Sandbox and get your hands on application development tools and middleware products from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.
Discuss
- XML zone discussion forums: Participate in any of several XML-related discussions.
- developerWorks blogs: Check out these blogs and get involved.




