About a dozen or so years ago at a conference, there was a presentation about the practice of using keys in DITA, and when it came time for questions, someone in the crowd asked “Why don’t we just use variables like we do in FrameMaker?” Coming from a FrameMaker background, still being relatively new to DITA, and working with a CCMS that couldn’t handle keys at the time, I also wondered about this. The response to the question was: “better reuse”. It took me a long time to fully understand how true the answer is, and how much more flexible the key-based way of doing things is in DITA.
To better understand how keys work, I set myself a challenge to create a test document and then progressively use keys to get a handle on their potential for reuse. I did all of this years ago and even did a presentation on it for a TC Dojo with Liz Fraley, but somehow never got around to doing an article about keys for DITAWriter. Until now.
The Sample Files
The sample files I put together are freely available on GitHub at dita_keys_examples. The examples grow in complexity and are designed to show how keys can be used. The original target document is an out-of-copyright version of a TRS-80 Expansion Interface manual dating to the late 1970s. The original version can be found on the Project Gutenberg website at. The content has been lightly “DITA-fied”, just enough to hopefully make it effective as a set of sample files. I also think that example technical manuals like this show how far technical communications as a discipline has progressed since it was originally published.
Key-less
To understand the benefits of keys, it makes sense to start without them to see to get a baseline. The first set of DITA files has a simple structure: two parts consisting of a set of topicrefs that point to specific DITA files.
And if you look at a sample paragraph in a topic, it is also pretty basic.
Nothing much to see here. There’s nothing wrong with it, but it has not been optimized for any level of reuse. That’s where keys come in.
Incorporating Key Definitions Directly in the Map
The second set of DITA files embeds keys for holding the name for the company, the computer model, and for the peripheral directly within the map.
For each of these keys, the keydef uses a value for the keys (keys=”computer_name”), and the topicmeta/keywords/keyword provides an associated value (“TRS-80”). And otherwise, there is no change to the rest of the bookmap.
The equivalent paragraph from the first example uses two of the keys referenced in the map, both inserted using the phrase (<ph>) element set to a specific keyref value that matches the keydef/keys value inserted in the map.
When outputted <ph keyref=”computer_name”/> will be replaced with “TRS-80”, and <ph keyref=”peripheral_name”/> will be replaced with “Expansion Interface” (without the quotes). If there is ever a need to update the names for the computer, peripheral, or the company, all that needs to be done is to update the value in the key definition in the map. This is good—and it is not far from how a variable would be used in a document in FrameMaker—but if you ever had to make a change to all TRS-80 documents, you would have to find all the bookmaps where the specific product model is mentioned and change the value directly in each map. There’s got to be a better way, right?
Using Conkeyrefs and a Separate DITA File to Hold Values
In the third set of example code we take a different route and now use content key references (conkeyrefs) to pull in values that are stored in a separate file. This is done by using a key definition (<keydef>) that points to a file that contains the keys (highlighted below).
Note that the key definition is wrapped in a topic group with the attribute @processing-role set to “resource-only”, which tells the output generator to ignore this content in terms of printing the output; it is there solely as a resource. The file name it points to is called product_info.dita. In this case this file contains information on the same three “keys” we’ve seen in the previous example, and to make things clear, the information is arranged in a table.
A look at one of these table rows looks like the following, with computer_name set by the @id attribute within a phrase element (highlighted below).
In the corresponding topic paragraph, a @conkeyref attribute is used with a phrase element that pulls in the value using a filename/id pair, so “product_info” (the filename) and the corresponding id (“computer_name” for the first instance).
Things are getting more abstract at this point, but basically, the map points to keys that are contained within the product_info.dita file, which sets values defined by an @id attribute. The @conkeyrefs attributes in the target topic pulls in a value by referencing the filename/id pair. Note that because the @id attribute is set to a phrase element, the referencing topic also has to use a phrase element for it to properly resolve.
This is where things get interesting from a content reuse standpoint: a single file contains several keys, and this file can be referenced by more than one bookmap. So if there’s a change made to the computer name (such as changing it from “TRS-80” to “TRS-90”), you make the change to the the product_info.dita file and it propagates to all of the bookmap files that point to it the next time they are outputted. Consistency and reuse for product-related information all in one file.
But things can be further abstracted for levels of reuse outside of things like product-related information.
Creating an Image Warehouse
The fourth example code set uses the same idea as the previous example, using conkeyrefs to pull in values that are stored in a separate file. This time specifically for images.
The same key definition (<keydef>) mechanism is used, this time pointing to a file that contains the keyed images. And as before the key definition is wrapped in a topic group with the attribute @processing-role set to “resource-only”, and it points to a file called image_warehouse.dita.
Similar to the previous example, the images are set within a table along with their description. The second example shown below even shows how a product key is being used in the description of the image.
At the code level, each image uses an @id attribute that is used as an identifier for the image file, which is also directly specified using an @href attribute.
In the topic where the image is being resolved—in this case within a task topic type and within the info portion of a single step—the @conkeyref points to the filename/id combo, which in this case is “image_warehouse/fig2”. (I realize the name for the image is less than optimal, though my thinking at the time was that I wanted to retain the original name for the image. In retrospect I would rename it to something more descriptive).
The reuse possibilities in this case focuses primarily on images that can be used across several documents. And secondarily, if an image being used needs to be updated, it can be done once in the image warehouse, and it will be updated automatically the next time a document that references it is outputted.
In practice you would likely have several different types of image stores to cover things like corporate logos, images that are common to a group of products, and those that are shared between product lines.
But you can go further than this by turning the target of the topicrefs within a bookmap to keys.
Keyed Topicrefs
The fifth set of example code builds on the previous example by inserting a mapref element into the bookmap that points to a topic called keydefs_topics.ditamap. Unlike the keydefs that follow it, no processing-role=”resource-only” is needed with the mapref, as it is only used as a resource. You will also notice that that topicref all have their @href attributes replaced with @keys and @keyrefs attributes—that will be explained shortly.
The keydefs_topics.ditamap is simply a list of keydefs and named @keys that point to specific URLs for the DITA files comprising this document.
Each of the topicrefs in the bookmap reference a keyref whose name is specified by the @keys attribute in the keydefs_topics.ditamap file. At output, this works in the same way as if the @href was added to each topicref individually.
The reason why you might want to do this is that it makes it easier to share topics between documents. Let’s say you have an “introduction” topic or perhaps some legal material that is used across several documents. Simply add it to a “topics store” similar to keydefs_topics.ditamap and then reuse by calling its @keyref across as many documents as you like.
How Far Down the Rabbit Hole Do You Go with Keys?
You can go further than the examples seen here, but this adds to the complexity of using keys; ultimately documentation teams need to determine how far they want to abstract their key usage. I’d argue that there is a trade-off between flexibility and opacity when using keys. As a minor example of this, take a look at the following two maps:
In these two views (both taken from the latest version of Oxygen), there are fewer elements in the key-less version on the left, and the topic types are visually represented by their icons. The keyed bookmap on the right has more elements, includes the topic title and the associated key, but all the icons are generic topics, even though each topic is properly typed as in the keyless example. It’s a small thing, but it does take more time for a technical writer to process what is going on in the keyed bookmap.
There’s also additional effort needed to use keys effectively, and there has been guidance and discipline among the technical writing staff to ensure that things like product-related keys, image warehouses, and keyed topics and the like are all handled consistently. I can think of plenty of occasions when I was working on an update to an existing document where the equivalent of the product-name keys was not set by the previous technical writer. In those instances, I had to do a search-and-replace on all the instances where the product was simply written in and replace them with their key equivalents. It’s also worth noting that some CCMSs have other ways of handling things like images, making it more efficient to use their own object references than creating a key-based image warehouse.
I think the best piece of advice I ran across relating to keys comes from Madcap’s Leigh White, who said:
Some people would like to see keys used for all references. I think that is needlessly complex. References that are context-specific gain nothing from being keyed. It’s only when you need to ‘flip-flop’ a term or a reference based on where you’re using a topic that keys have value.
My advice is always to start as small as you can with keys. If you discover additional reuse potential down the road, you can always switch a direct reference to an indirect one.
So, when beginning with keys use them where you can get some immediate level of reuse. As you get the hang of them, you can begin to architect their reuse across sets of documents. And please feel free to play with the code examples used in this article to get a better understanding of their use.