DITA 1.3 proposed feature #13004
Proposal to provide a mechanism for different effective key definitions at different locations within a map structure.
Date and version information
Include the following information:
•  The latest revision date for this proposal is 2012 January 18
•  This proposal was introduced by Jeff Ogden before being passed to Chris Nitchie.
•  This proposal was initially accepted for inclusion into DITA 1.3 on 2011 June 21: Minutes from 2011 June 21.
•  Additional discussions of this proposal as a partial mechanism for variable text in topics here.
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.
Use cases
The DITA 1.2 specification dictates that there be exactly one effective definition for a given key for all key references within a map structure (see “Effective key definitions” here). This is a severe limitation that prohibits some common use-cases, such as:
•  Omnibus publications that combine multiple standalone maps, each with their own set of key definitions.
•  Cases where a topic is reused at multiple locations in a map structure, but the behavior of links and/or text replacement for each use context must be different.
Proposed solution
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.
Benefits
•  This change is fully backwards-compatible with DITA 1.2. Existing maps will continue to function exactly as before, since they do not contain any @keyscope attributes.
•  It will now be possible to combine standalone maps with their own set of key definitions intact.
•  It will now be possible for map authors to specify context-dependent link behavior and text insertion for topics and sub-maps.
•  This feature will be used by relatively few authors, but allows for use cases which would not otherwise be possible.
Technical requirements
DTD and Schema modifications
Topic or map specialization None.
Domain None.
Element No new elements.
Attributes
•  keyscope
–  New attribute for topicref-atts group and its variants.
–  Processors will be required to process key definitions and key references within elements marked with this attribute according to the behavior described above.
–  Does not contain translatable text.
Processing impact See above.
Usability impact Key scopes are simple to specify. However, when a map utilizes this feature, the effective definition for a given key reference will now depend not only on the map that contains the reference, but the location within that map where the reference occurs. So identifying the applicable definition for a given key reference may be considerably more difficult in some cases, both for users and for tools.
Costs
•  The cost to updating and maintaining the changes to the DTD and schema files for this change is trivial.
•  The spec topic “Overview of keys” would need to be extensively updated to discuss key scopes and their implications. I suggest that this topic be split into two topics, “Key Definitions,” and “Determining the Effective Key Definition for a Key Reference.”
•  The topicref-atts topic would obviously need to be updated, and a new topic created for the @keyscope attribute.
•  DITA processing applications will have to update key reference processing.
–  The algorithm and data structures used to construct key spaces will need to be updated to account for key scopes.
–  Key reference resolution algorithms will need to be made aware of the effective context that applies for each key reference.
•  Tools that provide keyref-aware auditing and reporting tools will need to be updated to take key scopes into account.
•  Authoring tools may need to be updated to allow authors to specify the effective scope within a map structure to use to resolve key references during authoring.
•  For users who already understand the key reference mechanism, this change should be relatively straightforward. That said, the key reference mechanism is already very complex and not well understood, and this proposal does add to that complexity.
Examples
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.