|
|
Original requirement or use case |
Future post DITA 1.2 work from Issue #12007: Item 2: Consider adding a scoping mechanism for use with key definitions and
possibly other aspects of DITA based on the map hierarchy or the combined element hierarchy within a set of maps. Related
topic: Consider allowing subsequent key definitions within the same map or within peer maps to override previous key definitions,
probably as part of some hierarchal scope, and probably in a fashion that is the same as or similar to override mechanisms
to be developed for other features such as ditaval.
Add an optional
@keyscope attribute to the
topicref-atts attribute group and its variants, so that it appears on most map and topicref specializations. Put simply, the presence of
this attribute indicates that key definitions within the element apply only for key references within the element.
The presence of the @keyscope attribute with a non-empty value indicates to processors that the element defines a new key scope. The contents of the key
scope are as follows:
|
• |
The key scope-defining element itself. This means that any key definitions specified by the element are part of the scope,
and any key reference on the element is evaluated against the effective key definitions for the scope. |
|
• |
The key scope-defining element’s contents after conref resolution. |
|
• |
Any locally-scoped content referenced from within the key scope via @href on a topicref (or specialization). |
The root element of the root map in a map structure always defines an implicit root key scope.
A key scope inherits all the key definitions from its parent scope. The parent key scope is defined as the effective key scope
that surrounds the boundaries of a scope. If a key is defined in both parent and child scopes, the definition from the parent
takes precedence. The rules for key definition precedence within a key scope are identical to those in DITA 1.2.
Put another way, the effective key definitions for a key scope consist of the following items.
|
• |
The effective key definitions from the parent scope, if any. |
|
• |
The effective key definitions within the scope, minus those that are inherited from its parent. |
Note
The decision to have definitions in parent scopes take precedence over definitions in child scopes is based on the existing
DITA 1.2 practice where a key definition in a parent map takes precedence over a definitions for the same key from child maps.
That said, there are good arguments for having key definitions in child scopes override those from parent scopes for references
within that scope. We could put control of this in the author’s hands via another attribute specifying whether the parent
or child takes precedence (keyscopeprecedence=parent|child), though I worry that it might be confusing for authors.
Key references within a key scope are resolved using the effective key definitions for that scope. Key definitions outside
the scope of a key reference may not be used to resolve the reference, though their presence may be reported in error messages
by the processor.
The value of the @keyscope attribute is a descriptive identifier for the key scope. The value must be unique for all @keyscope attributes within the same map, and should be unique to the whole map structure, but global uniqueness is not required. The value for the attribute may not necessarily
be used directly for processing, but the combination of the URI of the containing map and the value of the @keyscope attribute can be used to identify the key scope for various purposes. For example:
|
• |
Processors should use the combination of map URI and @keyscope value when reporting errors or warnings related to key reference resolution. |
|
• |
Processors may use the @keyscope value as part of the mechanism of identifying the effective key scope when resolving key references. |
|
• |
Tools may use the combination of map URI and @keyscope value when reporting/validating/auditing keys and key references in a map structure. |
|
• |
Authoring applications may provide a way for users to specify the map URI and @keyscope value along with a root map to specify the keyref resolution context during authoring. |
Important
If two key scopes in a given map structure happen to use the same value for
@keyscope, they are still treated as independent key scopes with their own effective set of key definitions. Determining key definition
precedence in a non-contiguous key scope would be prohibitively complicated, both for processors and authors.
Note
It would be more intuitive for @keyscope to be a boolean attribute. However, without a human-readable identifier for the scope, good error reporting and auditing
is almost impossible, and processing is more challenging.
Combination of Standalone Maps
This map combines three standalone course maps, each with its own set of keys. Each of the mapref elements is marked with a keyscope attribute, meaning that the key definitions within the referenced map sub-structures will be confined to those sub-structures.
Since the summary key is defined in this map as part of the implicit root scope, and keys defined in parent scopes override those in child
scopes, its definition overrides any conflicting definition of summary in any of the referenced maps.
<map xml:lang="en">
<title>Training Courses</title>
<mapref href="course-1.ditamap" keyscope="course-1"/>
<mapref href="course-2.ditamap" keyscope="course-2"/>
<mapref href="course-3.ditamap" keyscope="course-3"/>
<topicref keys="summary" href="omnibus-summary.dita"/>
</map>
Without key scopes, the key names that have definitions for all three maps, like introduction or prerequisites, would take their effective definition from course-1.ditamap, resulting in incorrect behavior in the output.
Reuse of the Same Topic with Different Key Behavior
In this example, the “oil change” procedures for Tractor X and Tractor Y are similar enough to reuse the same topic for both,
but the name of the product is included in the title via keyref. In the map below, the topic common/oilchange.dita is referenced twice. Each reference is wrapped within a topicgroup that defines a key scope, and each scope has its own definition of the ProductName key.
<map xml:lang="en">
<title>Equipment Oil Change Procedures</title>
<topicgroup keyscope="Tractor-X">
<keydef keys="ProductName">
<topicmeta>
<linktext>Tractor X</linktext>
</topicmeta>
</keydef>
<topicref href="common/oilchange.dita"/>
</topicgroup>
<topicgroup keyscope="Tractor-Y">
<keydef keys="ProductName">
<topicmeta>
<linktext>Tractor Y</linktext>
</topicmeta>
</keydef>
<topicref href="common/oilchange.dita"/>
</topicgroup>
</map>
<task id="oilchange" xml:lang="en">
<title>Changing the Oil on the <ph keyref="ProductName"/></title>
<!-- etc. -->
</task>
An alternative way to code the above map would be to specify @keyscope on each of the topicref elements, and next the keydef elements within them. This is a somewhat less intuitive but equally valid formulation.
<map xml:lang="en">
<title>Equipment Oil Change Procedures</title>
<topicref href="common/oilchange.dita" keyscope="Tractor-X">
<keydef keys="ProductName">
<topicmeta>
<linktext>Tractor X</linktext>
</topicmeta>
</keydef>
</topicref>
<topicref href="common/oilchange.dita" keyscope="Tractor-Y">
<keydef keys="ProductName">
<topicmeta>
<linktext>Tractor Y</linktext>
</topicmeta>
</keydef>
</topicref>
</map>
Without key scopes, the effective text for both references would be “Tractor X,” making this an impossible scenario in DITA
1.2.
Key Definition Containment
This example illustrates how key definitions within a scope do not apply outside that scope. Here, key-1 is defined within the key scope scope-1. Since the reference to key-1 is outside that scope, the reference is treated as an undefined key.
<map xml:lang="en">
<title>Key Definition Containment Example</title>
<topicgroup keyscope="scope-1">
<keydef keys="key-1" href="someTopic.dita"/>
</topicgroup>
<!-- Processors should issue a warning for an undefined key
since the reference occurs in the root scope, and the
root scope does not contain a definition for key-1. -->
<topicref keyref="key-1"/>
</map>
Precedence Within a Scope
In the following map, the mapref specifies a keyscope, and then contains several key definitions. Since key precedence in a scope follows DITA 1.2 rules, the key definitions in
this map take precedence over key definitions in the sub-map, and earlier key definitions within the scope take precedence
over later ones.
<map id="map-1" xml:lang="en">
<title>Outer Map</title>
<mapref href="submap.ditamap" keyscope="scope-1">
<keydef id="keydef-1" keys="key-1"/>
<keydef id="keydef-2" keys="key-2"/>
</mapref>
<keydef id="keydef-3" keys="key-1"/>
</map>
<map id="submap" xml:lang="en">
<title>Sub-Map</title>
<keydef id="keydef-4" keys="key-1"/>
<keydef id="keydef-5" keys="key-2"/>
</map>
Here are the effective key definitions for the scopes in this map structure.
|
• |
Implicit root scope
Key Name |
Defining Element |
key-1 |
keydef-3, since this key definition and topicref-1 are both in root scope.
|
key-2 |
Undefined, since all definitions for this key occur within the boundaries of scope-1 |
|
|
• |
scope-1
Key Name |
Defining Element |
key-1 |
keydef-3, since this key definition is in the root scope, and thus takes precedence over any definitions in child scopes.
|
key-2 |
keydef-2 The root scope does not contain a definition for key-2 . Since key definition precedence within a scope occurs according to the same rules used in DITA 1.2, and keydef-2 happens shallower in the map structure of scope-1 than keydef-5, keydef-2 takes precedence.
|
|