Visualizing Complex Content Models with Spatial Schemas
Structured content can have various levels of complexity, from simple sequences of form fields — titles and descriptions, metadata values from lists, and body fields — to more elaborate sequences and nested structures. The latter can be particularly useful in regulated contexts such as legal or medical documentation, but aren’t by any means limited to those. Generally speaking, the better defined a content model can be, the more consistent and informational the content is, and the greater the potential benefits.
One way of ensuring control of content structures is to use XML-aware authoring tools such as Oxygen or FontoXML. These editors validate content against XML schemas — documents that define the permitted structures using syntaxes such as DTD, XML Schema (with a capital S), and RELAX NG. The authoring tools themselves can be configured to make authoring in XML visually appealing and accessible to non-specialists. However, setting up schemas in the first place or improving existing ones isn’t so easy.
Authors and managers must be consulted to make sure the formal structures work both in terms of intended outputs and in terms of the authoring experience. The structures should support authors’ mental models of the content they write. To aid this process, a clear visualization of the whole content model would be very helpful. Sometimes, information architects represent aspects of content models with Visio-style boxes and connectors. This works well when examining the detail of a model, but the full context of that detail — the whole topic or document model — rapidly gets too much to view on one screen or page. In addition, updating a diagram such as this takes time and isn’t well suited to collaborative development on the fly during a meeting.
Most commonly, schema developers are stuck with the raw schema syntax. Here, for example, is part of the task DTD based on the DITA XML 1.2 standard.
<!— LONG NAME: Step —> <!ENTITY % step.content “((%note;)*, %cmd;, (%choices; | %choicetable; | %info; | %itemgroup; | %stepxmp; | %substeps; | %tutorialinfo;)*, (%stepresult;)? )” >
This extract controls the elements that can go directly within a procedural step element. It allows for any number of note elements, followed by an obligatory cmd (a command; the core of the procedural step), followed by any number of choices / choicetable / info / itemgroup / stepxmp / substeps / tutorialinfo elements in any order, followed by an optional stepresult. (While this might seem fussy and unnecessarily limiting if you are not used to working with such detailed content models, the thinking behind it is clear: any step should have an action-oriented sentence but notes should be read before that sentence; and other information might be helpful but there can only be one result of a well-specified step.)
The step element is one of quite a few allowed elements in a DITA task, and each has its own defined content model in the DTD. It is obvious that seeing a big list of these content models isn’t necessarily the most accessible way to get an idea of DITA task structure, or to work with modifications of that structure (DITA is designed to enable more constrained or specialized content models based on the “out of box” types.)
Over the last couple of weekends, I’ve been refining a framework for visualizing schemas that:
- Provides an accessible way for authors, managers, and schema developers alike to understand or refine a content model.
- Is easy to update and maintain without specialist tools or knowledge[¹].
- Offers a single-page view of the whole content model at a glance, rather than the common approach of revealing only certain aspects of the model in each view. While it can sometimes be helpful to focus on details of the model, the full picture is very helpful for putting the detail in context and working with the model in a way that’s easily grasped. (As is often the case with conceptual architectures, printing the visualization out and doodling/handwriting notes on it could be particularly useful for collaborative schema development)[¹].
- Is structured enough that it could be parsed to generate at least a skeleton formal schema such as a DTD.
- Is general enough that it can be used for any content model, whether that model will be implemented in DITA XML, other XML languages, other markup standards such as SGML, or perhaps even a schema that isn’t based on markup, such as the model for a relational database.
I call it a spatial schema. It’s authored in a spreadsheet tool such as Google Sheets. Here’s an example of a somewhat constrained DITA task topic model using this framework:
The rules for reading this are:
- The nested boxes represent the hierarchy of elements: which elements are contained by which.
- The name at the top left of a box (or in the middle of a box) is the element name.
- The indent level represents the level in the hierarchy.
- Multiple separate boxes at the same level indicate that those elements are in sequence: the latter ones follow the former. For example, an optional abstract element follows an optional titlealts, which follows a mandatory title. abstract cannot come before title.
- Multiple items in a single box indicate multiple options at that point in the sequence. For example, after cmd, there can be any number of choices / choicetable / info / itemgroup / stepxmp / substeps elements in any order.
- The number at the top right of a box signifies the number of the box’s elements that can appear within the box’s direct container. For example:
- 0+ means any number, e.g. the note or hazardstatement elements at the beginning of a step.
- 1 in the same box would mean that there must be either a note or a hazardstatement at the beginning of a step, but not both.
- Inline elements such as ph are not represented directly, to keep the visualization simple and specific to the topic type itself.
- You should read the contents of the last descendants of any element as text data and inline elements. For example, cmd may only contain inline elements; no block elements.
To see the source document and copy it for your own use, view this Google Sheets document.
- The model for the whole document type (at least the elements) is represented in a reasonably compact and accessible manner.
- As it’s authored in a spreadsheet tool, it’s easy to use other columns to the left of the diagram for notes, descriptions of XML attributes that are part of the content model, or any other relevant info. For example, I used one column for the DITA inheritance path, and another to indicate where this model was different from the base, unspecialized one.
- As it follows a consistent structure, it would be possible to generate a skeleton schema document from it. From a coding point of view, one way to start would be to export the sheet as a comma separated values file (.csv), and build an internal representation of the document model based on the first column in which an element name appeared (the indent level) and the number (if any) contained in that row.
- In the main visualization itself, there’s currently no room to include XML attributes that are part of the content model, although they can be described in adjacent columns of the sheet.
- There is a practical limit to the degree of nesting that can be visualized in this way, and so generic block elements are indicated as [regular block element]. A similar approach should be taken with nested topics — the recursion can be indicated but left at that. This could, however, be seen as an advantage rather than a limitation — authors and users alike can get lost in deeply nested structures, and a rule of thumb might be that unless you can visualize a structure, you shouldn’t write content using it!
- There is no provision for directly describing conditionally dependent relationships: “if this optional element is present then another one must be too”.
Here is one example of the latter from the experimental troubleshooting task specialization included with Oxygen XML, drawn from the DITA 1.3 spec in development:
<!— LONG NAME: Remedy —> <!ENTITY % remedy.content “((%title;)?, (%responsibleParty;)?, (%steps; | %steps-unordered; | %steps-informal;) )?” >
This says that the remedy element can be empty, i.e. with no content, but if it has any content, it must have one of steps, steps-unordered, or steps-informal. A workaround to represent this using the spatial schema framework would be to use a dummy/virtual container for the child elements:
However, this type of structure does not seem to be needed very often in any case.
Here’s the link to the demo Google Sheet again. Let me know what you think in the comments. Could this be helpful to you? Is there anything that could be tweaked to improve it?
Originally published at blog.joepairman.com on March 15, 2015.