Dynamically converted measure units in DITA through XSL-T
When technical content includes measurements that can be expressed using different
units, it is often difficult for the author to know which unit to use. Different readers may have
requirements for seeing different units. Working within DITA, and using the data
element for measurements, it is possible to produce dynamically-converted output using units that
suit the individual reader's needs.
By
Tony Self
Oils ain't oils, and standards ain't standard
"A stone's throw" is not a very accurate unit of measure. And while other units of
measure are more accurate, they can be incomprehensible to those unfamiliar, and especially
those inculcated with an alternative unit. A person may know how long it takes to walk a mile,
but has no idea whether a fathom is shorter or longer, or even a measure of distance. Whether
it's distance, weight, volume, currency, pressure, temperature, or scores of other units, a
"standard" is rarely universal.
Even very common standard units have variations... or perhaps homonyms (words that share
spelling and punctuation, but not meaning). A
"gallon" to someone from the Canada is
20% more than a
"gallon" to someone from the United States. And a
"dry
gallon", also used in the United States, is 3% less than a
"standard"
"US gallon".
What a unit means not only changes across borders; they also change over time. In fact, over
time, a mile has varied in length from about 1 kilometre to about 10 kilometres. A Roman mile
(remembering that
"mille" in Latin means
"one thousand") was 1,000
paces. And a pace meant two steps, in case you thought
"pace" and
"step"
were the same unit! There were also different Arab miles, Danish miles, Scots miles, Irish
miles, Hungarian miles, Portuguese miles, and so on.
Miles are not the same as miles
Even today, there are two commonly used standard miles: one of 5,280 feet, and another of
6,076 feet. The former is used for distance on land, and is qualified as a
"land
mile" or a
"statute mile". The latter measure is used for distance across the
sea or the through the air, and is equivalent to one degree of latitude; it is differentiated
from a land mile through the term
"nautical mile".
In the United States, aircraft speeds are sometimes measured in (statute) miles per hour
(mph), but in other countries, nautical miles per hour, or
"knots", is the more
common unit.
Miles are not the same as miles
Air Speed Indicator with knots
Air Speed Indicator with mph
The problem in practice
An example of the problem for technical communicators in practice is summarised in the
question,
"what unit do I use for aircraft flight manual?". The choices are to use knots,
to use mph, or to use both. Remembering that
"the reader is king", the correct choice is
influenced by the audience. For a German pilot, the flight manual should use knots. For a US
pilot, the flight manual should use mph. Single-sourcing techniques make it possible to deliver
different variants for different audiences. But what about the flight manual for a German pilot
flying a US aircraft? Or a US pilot flying an aircraft fitted with an ASI that uses knots? Would
including both measurements be a wiser choice?
The problem with including both units, particularly when the speeds are so important as they
are in aviation, is that there may be confusion. For example, the emergency procedures for an
8KCAB aircraft (as listed in the Operating Manual) include a forced landing minimum approach
speed of 70 mph. Approaching at 70 knots is too fast, and it's easy to see how a quick
glance at the
"70" figure with an assumption about the unit could be problematic. Ideally,
the solution would be for the manual to show the units that match the aircraft instrument units.
If the aircraft displays two units, then the manual should use the same units that the pilot
"thinks in".
To make this possible, the author would have to nominate a default unit for the publication,
with an override based on the type of instrument fitted to a particular aircraft (so that the
manual is specific to the individual aircraft), and another override that the pilot can choose.
Of course, this is not possible for a paper manual, or a PDF, but it is possible for an
electronic flight manual.
Dynamic units with DITA
In a typical scenario, some parts of an aircraft manual might be maintained by the
manufacturer, other parts by the aircraft national distributor, and other parts by the aircraft
owner or operator. Let's assume that the
"base manual" is provided by the manufacturer in
DITA format, using mph as the default unit. The distributor will then add or replace some
content based on local certification requirements, in DITA format, using knots as the default
unit. The operator then makes some further changes, also in DITA, to reflect the instruments
fitted to the individual aircraft. Finally, let's make an assumption that the pilot needs to
work in kilometres per hour for a particular operational requirement. It is quite easy to cater
for this scenario in DITA.
Firstly, the semantics for marking up speeds needs to be agreed by all
contributors. The suggested markup rules are shown in the
example:
<ph><data type="speed" datatype="mph" value="70" translate="yes"></data>70 mph</ph>
where
the type attribute indicates the type of measurement unit, the
datatype attribute indicates the unit itself, the value
attribute contains the number, and the translate attribute whether the unit
should be converted or not. (In some cases, it may be necessary to quote a speed with a
fixed unit.)
A better alternative would be to create a specialisation of ph, perhaps
named measure, which would be the
"container" for the
data element. Another alternative would be to create a specialisation of
foreign, and incorporate all the metadata attributes within that element.
But let's assume we want to stay with base DITA.
Although its name suggests otherwise, the data element in DITA is intended for
metadata, which would not normally be displayed in the output. That's why the ph container
is used to store the default text. If the content is published or otherwise processed by a
tool that is not aware of the markup rules, then the content of the ph
element will be displayed normally. However, if a processor was aware of the
data markup, it could replace the content of the containing
ph element with a calculated value based on datatype and
value attributes of the data element, and a unit
preference.
The calculation would be made within the processing using XSL-T. An example of such conversion
code
is:
<!-- Set the default unit to be used to display speeds -->
<!-- and create a parameter to be used for the value to be converted -->
<xsl:param name="unit_speed" select="'kts'"/>
<xsl:param name="value_speed"></xsl:param>
<!-- Look for data elements within ph elements -->
<!-- If found, call the 'convert' template -->
<xsl:template match="*[local-name() = 'ph'][child::*[local-name() = 'data']]" priority = "1" >
<xsl:call-template name="convert" />
</xsl:template>
<!-- The 'convert' template -->
<!-- If the data elements are OK for conversion, run the standardise_to_kph template -->
<xsl:template name="convert">
<xsl:choose>
<xsl:when test="@translate='yes' and $unit_speed!='source'">
<span class="data">
<xsl:call-template name="standardise_to_kph" />
</xsl:call-template>
</span>
</xsl:when>
<xsl:otherwise>
<span class="data">
<xsl:value-of select="."/>
</span>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- standardise_to_kph template -->
<!-- Convert from the original speed using the value and datatype attributes -->
<!-- Then using the converted speed (in kph), call the speed template -->
<xsl:template name="standardise_to_kph">
<xsl:param name="unit_speed" select="$unit_speed"/>
<xsl:param name="value_speed" select="$value_speed"/>
<xsl:choose>
<xsl:when test="@datatype='kph'">
<xsl:call-template name="speed">
<xsl:with-param name="unit_speed" select="$unit_speed" />
<xsl:with-param name="value_speed" select="$value_speed div 1" />
</xsl:call-template>
</xsl:when>
<xsl:when test="@datatype='mph'">
<xsl:call-template name="speed">
<xsl:with-param name="unit_speed" select="$unit_speed" />
<xsl:with-param name="value_speed" select="$value_speed div 0.621371" />
</xsl:call-template>
</xsl:when>
<xsl:when test="@datatype='kts'">
<xsl:call-template name="speed">
<xsl:with-param name="unit_speed" select="$unit_speed" />
<xsl:with-param name="value_speed" select="$value_speed div 0.539957" />
</xsl:call-template>
</xsl:when>
</xsl:choose>
</xsl:template>
<!-- speed template -->
<!-- Using the passed speed (in kph) and value to be converted to, -->
<!-- write the speed, then a space ( ), then the unit -->
<xsl:template name="speed">
<xsl:param name="unit_speed"/>
<xsl:param name="value_speed"/>
<xsl:choose>
<xsl:when test="$unit_speed='kph'">
<xsl:value-of select="format-number($value_speed, '#.0')"/>
</xsl:when>
<xsl:when test="$unit_speed='mph'">
<xsl:value-of select="format-number($value_speed * 0.621371, '#.0')"/>
</xsl:when>
<xsl:when test="$unit_speed='kts'">
<xsl:value-of select="format-number($value_speed * 0.539957, '#.0')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="format-number($value_speed, '#.0')"/>
</xsl:otherwise>
</xsl:choose>
<xsl:text> </xsl:text>
<xsl:value-of select="$unit_speed"/>
</xsl:template>
The final requirement is to allow the pilot to override the display unit, and this can be done
by setting the unit_speed parameter when the XSL-T is called. (This would typically be
implemented in the user interface as a preference dropdown.) A code sample for such a
server-side processing request (in ASP.Net VB)
is:
Dim XslArg As New System.Xml.Xsl.XsltArgumentList
Dim speedunits As String = Request.QueryString("unit_speed")
If Not (speedunits = "mph" Or speedunits = "kts" Or speedunits = "source") Then speedunits = "kph"
If Not speedunits = "" Then XslArg.AddParam("unit_speed", "", speedunits)
Example of default, knots and mph dynamically-converted output
Result
The resultant dynamically-converted units can be displayed in knots, mph or kph, regardless of
what unit has been used when the speed is mentioned. As with all document engineering processes,
the system is reliant upon accurate metadata. If the attributes are not completed accurately,
the result will not be accurate. Once the processing routines for DITA content using the speed
markup have been written, there is no additional cost to converting all of a document's speeds,
or for those of a suite of documents, or for the system to be introduced globally. DITA is a
standard, and if you work within that standard, many benefits flow.
Oils Ain't Oils
To an Australian audience of a certain age, the
"oils
ain't oils" in the title makes some sense. It is a catchphrase from a famous Castrol
advertising campaign, built on the premise that not all motor oils are the
same.
Acknowledgement
Thanks to Eliot Kimber for his generous advice.
Speeds displaying only data element content (that is, not
converted)
Speeds converted to mph
Speeds converted to knots