DITA 1.3 proposed feature #13059a

Provide the ability to filter within a branch of content, in addition to the existing ability to filter an entire set of content based on a single set of conditions.

Date and version information

Original requirement

Discussed August 2, 2011: "Need the ability to filter within a branch of content, in addition to the existing ability to filter an entire set of content based on a single set of conditions."

As clarified at TC meeting May 21, 2013, this proposal consists of two separate but related updates. The first could be implemented without the second, but the second could not be implemented without the first.

  1. This proposal covers the ability to filter within a branch of content, using conditions that apply only to that branch.
  2. This proposal covers the ability to provide more than one set of filter conditions on a branch of content, with the intent that distinct copies of the branch content be generated, once per set of conditions.

Use cases

Benefits

Address the following questions:
  • Who will benefit from this feature?
    • Authors, by getting new methods to tailor information to select audiences, and new methods to publish that are much simpler than existing alternatives.
    • Tool vendors that have been waiting on a standard method for providing this function, rather than creating their own.
  • What is the expected benefit?
    • Authors may now tailor an individual section of a book to one audience, platform, or other condition, while leaving the rest of the book common to all required conditions.
    • Some authoring tools already have their own implementations of similar behavior; authors can now rely on a standard behavior to work across tools.
    • Authors with common information that must be tailored to multiple audiences may now publish that information once, rather than creating one publication to target each condition.
  • How many people probably will make use of this feature? For example, everyone, many, or few.
    • Many authors are expected to use this feature; it comes up regularly as a request, and several tools already offer similar behaviors to meet customer demand.
  • How much of a positive impact is expected for the users who will make use of the feature? For example, significant or minor.
    • Significant; those already using tool-specific implementations will have a new way to do this that works across tools, while users of other tools should see this as a new standard feature. Those attempting alternate methods for the second use case will see significant reduction in time to create, build, and maintain that common information.

Costs

Outline the impact (time and effort) of the feature on the following groups:
  • Maintainers of the DTDs and XSDs: minor impact to create the new elements for this feature.
  • Editors of the DITA specification:
    • How many new topics will be required? One topic per element defined below (3 total); likely, a new topic in the architectural specification describing how to use the feature.
    • How many existing topics will need to be edited? None
    • Will the feature require substantial changes to the information architecture of the DITA specification? If so, what? No substantial changes.
  • Vendors of tools: XML editors,component content management systems, processsors, etc.
    • All DITA tools may be impacted by this, with a greater impact on processors (including editors, CMS vendors, build tools) that render or interpret DITA content dynamically based on filter conditions.
    • Tools that do not have special support for filtering - such as an editor that does not offer a filtered view of content while editing - will likely not have any additional support for this feature.
    • Tools that already have their own implementation will likely want to provide support for both methods. This is expected to be easier than implementing the behavior from scratch. Few tools are known to implement the multiple-conditions-per-branch aspect of this proposal, though others are known to have ways to assign unique conditions to a branch.
    • Tools that do not have any version of this feature, but wish to implement processing for it, will have the biggest impact. Estimate medium to large impact compared with other major DITA features.
  • DITA community-at-large. Will this feature add to the perception that DITA is becoming too complex? Will it be simple for end users to understand?
    • As with any new feature, people who do not need this will be perceived as unnecessary or too complex. However, enough users desire the function that they will try to understand it, and limited prototypes so far using the design below have not caused problems.

Technical requirements

Important: This section must be complete in order for the proposal to be approved.
Provide a detailed description of how the solution will work. Be sure to include the following details:
Processing feature
  • How, in general, will the feature work?
    • When a <ditavalref> element is specified in a map, the conditions from the referenced DITAVAL will be processed for each topic in that branch of the map. The <ditavalref> will also be used for that branch itself, so that if the branch uses a topicref with otherprops="hide", and the <ditavalref> excludes otherprops="hide", that topicref and its children should be removed.
    • When multiple <ditavalref> elements are specified at the same level of a map branch, the content will be copied once per ditaval, with each copy using one of the conditions. For example, if 3 <ditavalref> elements are specified as peers in the same branch, that branch of content should produce three distinct versions of the content, with each version using one of the <ditavalref> elements to set conditions, as described in the previous bullet.
    • When copies are created due to the previous function, generated output files for formats such as HTML must be renamed. This is not an issue for monolithic formats such as PDF or for systems that may produce dynamic filtered content without predetermined file names. For situations where file names are important, this proposal recommends that the names be based on the copy-to attribute, which can specify a token to add to the name. For example, if the DITA document is sample.dita, and the copy-to attribute is copy-to="token", the generated XHTML document would be sample-token.html. If the copy-to attribute is not specified, this proposal recommends that processors fall back to the base name of the DITAVAL file (for example, "linux" when using the ditaval document "linux.ditaval"). If the author wishes to keep one set of content with the original name, the <noFileRenaming> element (described below) may be used.
  • How will authors take advantage of the new feature? Authors will use the <ditavalref> element to specify a DITAVAL file that provides conditions for a branch.
  • Will the feature have an impact on other processing features? For example, will the proposed feature have an impact on key resolution? Should not impact key resolution, but need to investigate ramifications of using a key to specify a ditaval file on <ditavalref>.
  • What edge cases need to be considered?
    • Including <ditavalref> in a sub-tree; for example,
      <topicref href="a.dita">
        <ditavalref href="some.ditaval"/>
        <topicref href="b.dita">
          <ditavalref href="other.ditaval"/>
          ...

      For the purposes of this proposal, this should be considered an error condition, due to the complexity of handling both exponentially growing filter combinations (imagine 3 ditavals at each level) and file naming for the extra copies of copies.

    • Including <ditavalref> as a child of map itself: this should be considered legal, and results in the filters being applied to the map itself. This could be a way to handle sub-maps that use their own filter conditions, or multiple could be specified to create extra copies of the full map.
    • Including <ditavalref> as a child of a reference to a map; for example:
      <topicref href="other.ditamap" format="ditamap">
        <ditavalref href="some.ditaval"/>
      </topicref>
      This should be processed in an equivalent manner to the previous edge case, resulting in a filter that is applied to "other.ditamap". So, it is equivalent to:
      <topicref>
        <ditavalref href="some.ditaval"/>
        ...contents of other.ditamap...
      </topicref>
    • Multiple (non-equivalent) copies of the same file copied to the same name: this proposal recommends that this be treated as an error condition; processors may respond by using an alternate naming scheme for one of the copies.
Topic or map specialization
(none)
Domain
List of topic or map types that will include the domain:

The new domain will be called the "ditaval domain". It will be included in all of the core content maps distributed by OASIS (map, base map, book map, classification map). It will not be included in subject scheme. The learning subcommittee may decide whether to include it in learningMap or learningBookmap.

Element
  • <ditavalref>
    • Element name and attributes: The <ditavalref> element will be a domain specialization of <topicref>. The content model is (ditavalmeta?). The attributes will match topicref attributes, with the following modifications:
      • @copy-to will be defined as specifying a token to be used with file renaming, as described earlier in this proposal.
      • @format defaults to "ditaval"
      • @toc and @print default to "no"; @linking defaults to "none" (could remove entirely if TC prefers)
      • Remove @navtitle, which is deprecated in DITA 1.2 in favor of <navtitle>.
      • Remove @collection-type, @type, and @chunk
      • @processing-role defaults to "resource-only"
      • Suggested for this proposal (looking for TC feedback), @scope should default to "local", as ditaval documents that are unavailable to a processor generally cannot be used, and this will override cascading values that may be inappropriate (allowing the ditaval to be found and processed for use in the map branch, even if topicref targets are all external).
    • Description of the element, including any processing requirements: Should generally be covered above; in summary, the element references a DITAVAL document, which will be used to filter the branch of content where that element is specified, as well as the topics referenced by that branch. If multiple <ditavalref> elements are specified for a single branch, the result will be multiple generated copies based on the different conditions.
    • Description of where the element will be permissible: The element is a domain specialization of <topicref>, so it is permissible in the same locations for any map that uses the domain.
    • Is the element translatable? If yes, is it a block or phrase (subflow) element? It is translatable, following the same rules as topicref.
  • <ditavalmeta>
    • Element name and attributes: The <ditavalmeta> element is a specialization of <topicmeta>. The attributes match those of <topicmeta>. The content model matches that of <topicmeta>, plus an additional optional specialization of <data>, named <noFileRenaming>. The optional <noFileRenaming> element is allowed immediately before any other <data> elements.
    • Description of the element, including any processing requirements: The element is used to specify metadata about the referenced ditaval document.
    • Description of where the element will be permissible: The element is only allowed as a child of <ditavalref>.
    • Is the element translatable? If yes, is it a block or phrase (subflow) element? Yes, following the same rules as topicmeta.
  • <noFileRenaming>
    • Element name and attributes: The <noFileRenaming> element is a specialization of <data>. The only attributes are @props and @base for specialization, @platform/@product/@audience/@otherprops, and the global @class/@xtrf/@xtrc.. The content model is empty.
    • Description of the element, including any processing requirements: When specified, the branch of content created based on the ancestor <ditavalref> should not result in renamed output topics. It is considered an error if multiple <ditavalref> elements use this token, and this usage results in conflicting copies of the same output topic.
    • Description of where the element will be permissible: The element is only allowed as a child of <ditavalref>.
    • Is the element translatable? If yes, is it a block or phrase (subflow) element? Yes, following the same rules as topicmeta.
Attributes
(none)
Overall usability
Discuss the impact to current DITA users.

DITA users that are looking for a function like this should find it relatively straightforward. The topicref element and its specializations today are used to reference a variety of files, so it is not a big leap to use <ditavalref> element to reference a ditaval file -- especially with that name. The element should only appear in contexts where it is useful, which is a bonus (though for usability it would be nice if they could be grouped at the start of a branch).

DITA users that do not need this function will see one additional element that they see as unnecessary. Those with their own document type shells may choose whether to see this element or not.

Examples

Provide examples of the proposed feature. Include an example for each of the use cases. Be sure to include edge cases, if known.

Eample: basic use case #1

input.ditamap:
<map>
  <topicref href="intro.dita"/>
  <topicref href="install.dita">
    <ditavalref href="novice.ditaval">
      <ditavalmeta><noTopicRenaming/></ditavalmeta>
    </ditavalref>
    <topicref href="do-stuff.dita"/>
    <topicref href="advanced-stuff.dita" audience="admin"/>
    <!-- more topics -->
  </topicref>
  <!-- Several chapters worth of other material -->
</map>

novice.ditaval:
<val>
  <prop att="audience" val="novice" action="include"/>
  <prop att="audience" val="admin" action="exclude"/>
</val>
If this sample is published, the following processing will take place:
  • The first topic (intro.dita) does not use any of the conditions that are specified in novice.ditaval. It is published normally, potentially using other ditaval conditions that were specified externally.
  • The second topic (install.dita) is filtered first using any external conditions, and is then filtered using the conditions in novice.ditaval.
  • The third topic (do-stuff.dita) is filtered first using any external conditions, and is then filtered using the conditions in novice.ditaval.
  • The fourth topicref (to advanced-stuff.dita) is removed from the map entirely, because it is filtered out with the conditions specified for this branch.

Example: multiple filters for one branch (use case #2)

input.ditamap:
<map>
  <topicref href="intro.dita"/>
  <topicref href="install.dita">
    <ditavalref href="win.ditaval">
      <ditavalmeta><noTopicRenaming/></ditavalmeta>
    </ditavalref>
    <ditavalref href="mac.ditaval" copy-to="apple"/>
    <ditavalref href="linux.ditaval"/>
    <topicref href="do-stuff.dita">
      <topicref href="mac-specific-stuff.dita" platform="mac"/>
      <!-- more topics and nested branches -->
    </topicref>
    <topicref href="cleanup.dita"/>
  </topicref>
  <!-- Several chapters worth of other material -->
</map>

win.ditaval:
<val>
  <prop att="platform" val="win" action="include"/>
  <prop att="platform" val="mac" action="exclude"/>
  <prop att="platform" val="linux" action="exclude"/>
</val>

mac.ditaval:
<val>
  <prop att="platform" val="win" action="exclude"/>
  <prop att="platform" val="mac" action="include"/>
  <prop att="platform" val="linux" action="exclude"/>
</val>

linux.ditaval:
<val>
  <prop att="platform" val="win" action="exclude"/>
  <prop att="platform" val="mac" action="exclude"/>
  <prop att="platform" val="linux" action="include"/>
</val>
If this sample is published to XHTML (where output file naming is important), the following processing will take place:
  • The first topic (intro.dita) is published normally, potentially using other ditaval conditions that were specified externally.
  • The install branch appears three times, once for each ditaval. The branches are created as follows:
    • The first branch uses the first ditaval file (win.ditaval). Output files are not renamed, due to the presence of <noFileRenaming/>. The file "mac-specific-stuff.dita" is removed from this hierarchy based on win.ditaval. The generated files, with indenting to show hierarchy, are:
      install.html
         do-stuff.html
           ...more topics and nested branches...
         cleanup.dita
    • The second branch uses the second ditaval file (mac.ditaval). Output files are renamed based on the @copy-to attribute. The file "mac-specific-stuff.dita" is included in this hierarchy based on mac.ditaval. The generated files, with indenting to show hierarchy, are:
      install-apple.html
         do-stuff-apple.html
            mac-specific-stuff-apple.html
            ...more topics and nested branches...
         cleanup-apple.dita
    • The third branch uses the last ditaval file (linux.ditaval). Output files are renamed, using the ditaval file name because @copy-to is not used. The file "mac-specific-stuff.dita" is removed from this hierarchy based on linux.ditaval. The generated files, with indenting to show hierarchy, are:
      install-linux.html
         do-stuff-linux.html
           ...more topics and nested branches...
         cleanup-linux.dita

Example: repeat use case #2, written as if multiple ditaval files are not possible

The previous example used three ditaval files to avoid triple maintenance of the install branch in a map. To help illustrate how the previous sample worked, this sample is included, which is functionally equivalent and has the same results:

input.ditamap:
<map>
  <topicref href="intro.dita"/>
  <topicref href="install.dita">
    <ditavalref href="win.ditaval">
      <ditavalmeta><noTopicRenaming/></ditavalmeta>
    </ditavalref>
    <topicref href="do-stuff.dita">
      <!-- more topics and nested branches -->
    </topicref>
    <topicref href="cleanup.dita"/>
  </topicref>
  <topicref href="install.dita">
    <ditavalref href="mac.ditaval" copy-to="apple"/>
    <topicref href="do-stuff.dita">
      <topicref href="mac-specific-stuff.dita" platform="mac"/>
      <!-- more topics and nested branches -->
    </topicref>
    <topicref href="cleanup.dita"/>
  </topicref>
  <topicref href="install.dita">
    <ditavalref href="linux.ditaval"/>
    <topicref href="do-stuff.dita">
      <!-- more topics and nested branches -->
    </topicref>
    <topicref href="cleanup.dita"/>
  </topicref>
  <!-- Several chapters worth of other material -->
</map>

Example: edge case: ditavalref used in an already filtered branch

<topicref href="a.dita">
  <ditavalref href="some.ditaval"/>
  <topicref href="b.dita">
    <ditavalref href="other.ditaval"/>
    <ditavalref href="another.ditaval"/>
    <!-- more content -->
  </topicref>
</topicref>
This should be by processors as an error. Doing otherwise would be considered overly complex for most authors and processors, which would need to understand:
  1. New precedence of filtering rules in b.dita - combining "some", "other" / "another", and potentially more further down in the branch
  2. File naming for b.dita and further nested topics.

Example: edge case: ditavalref used in an already filtered branch (variant)

This is a variant on the previous edge case, where the <ditavalref> in a nested branch is actually within a nested map:
in input.ditamap:
<topicref href="branch.dita">
  <ditavalref href="filterBranch.ditaval"/>
  <topicref>
      <!-- content and further nesting -->
      <mapref href="nested.ditamap"/>
  </topicref>
</topicref>

nested.ditamap
<map>
  <ditavalref href="nestConditions.ditaval"/>
  <!-- content in nested map -->
</map>

When the nested content is resolved inside input.ditamap, the result is that the nested conditions will be present inside a branch that already uses <ditavalref>. The nested conditions should be ignored.

Example: edge case: including <ditavalref> as a child of the map

<map>
  <title>Sample map</title>
  <ditavalref href="novice.ditaval">
    <ditavalmeta><noFileRenaming/></ditavalmeta>
  </ditavalref>
  <!-- lots of content -->
</map>

This map would be equivalent to processing all contents of the map with the conditions in novice.ditaval. If conditions are provided external to the map (such as a parameter to the process), those conditions are processed first.

Example: edge case: including a ditavalref as a child of a reference to a map

<topicref href="parent.dita">
  <topicref href="other.ditamap" format="ditamap">
    <ditavalref href="some.ditaval"/>
  </topicref>
</topicref>

other.ditamap:
<map>
  <topicref href="nestedTopic1.dita">
    <topicref href="nestedTopic2.dita"/>
  </topicref>
  <topicref href="nestedTopic3.dita"/>
</map>
This is functionally equivalent to applying the conditions in some.ditaval to the topics in the nested map. For the purposes of filtering, it could be rewritten as:
<topicref href="parent.dita">
  <topicref>
    <ditavalref href="some.ditaval"/>
    <topicref href="nestedTopic1.dita">
      <topicref href="nestedTopic2.dita"/>
    </topicref>
    <topicref href="nestedTopic3.dita"/>
  </topicref>
</topicref>
For the purposes of filtering, this map could also be rewritten as:
<topicref href="parent.dita">
  <topicref href="nestedTopic1.dita">
    <ditavalref href="some.ditaval"/>
    <topicref href="nestedTopic2.dita"/>
  </topicref>
  <topicref href="nestedTopic3.dita">
    <ditavalref href="some.ditaval"/>
  </topicref>
</topicref>

Example: edge case: multiple non-equivalent copies of the same file copied to the same name

<topicref href="a.dita">
  <ditavalref href="one.ditaval"><ditavalmeta><noFileRenaming/></ditavalmeta>
  <ditavalref href="two.ditaval"><ditavalmeta><noFileRenaming/></ditavalmeta>
  <topicref href="b.dita"/>
</topicref>
<topicref href="a.dita"/>
<topicref href="c.dita">
  <ditavalref href="one.ditaval" copy-to="token"/>
  <ditavalref href="two.ditaval" copy-to="token"/>
</topicref>
This contains several errors, because multiple conditions result in multiple output files using the same name. When generating XHTML:
  1. a.dita will generate a.html using 3 alternate set of conditions -- one.ditaval, two.ditaval, and no ditaval.
  2. b.dita will generate b.html using 2 alternate set of conditions -- one.ditaval and two.ditaval.
  3. c.dita will generate c-token.html using both extra sets of conditions.