Conditional processing

Conditional processing is the filtering or flagging of information based on processing-time criteria. Conditional processing is based on attributes specified in the DITA source.

About conditional processing

Certain concepts are critical for a full understanding of conditional processing.

conditional processing
A process that determines whether content is included, excluded, or flagged. This process is based on a comparison of conditional-processing attributes in the DITA source with the rules that are set in one or more DITAVAL documents.
conditional processing attribute

Attributes that can be used for filtering and flagging. These are the following attributes:

  • @props and any attribute specialized from @props, including those integrated by default in the OASIS-provided document-type shells: @audience, @deliveryTarget, @platform, @product, @otherprops
  • The @rev attribute, which supports flagging but not filtering
conditional-processing profile
A set of rules that are provided to a processor for use at rendering time. These rules are based on one or more DITAVAL documents.
DITAVAL document
A document that specifies a set of rules that define which elements to include, exclude, or flag. A DITAVAL document can be a file on the file system, a set of rules stored in memory, or another way of storing information that is expressed using DITAVAL syntax.
filtering
The process of excluding content at rendering time.
flagging
The process of emphasizing content by inserting images, text, or stylistic formatting at rendering time.

Expectations for conditional processing

Certain behaviors are expected of processors when working with conditional processing.

Processors SHOULD be able to perform filtering and flagging using the following attributes: @props, @audience, @deliveryTarget, @platform, @product, and @otherprops.

The @props attribute can be specialized to create new attributes, and processors SHOULD be able to perform conditional processing on specializations of @props.

Although metadata elements exist with similar names, such as the <audience> element, the specification does not define any mechanism for conditional processing using metadata elements.

About the DITAVAL document

A DITAVAL document specifies a set of rules that defines which elements to include, exclude, or flag.

The markup for DITAVAL documents provides a standard way to define all conditional processing that is associated with the DITA specification.

Each rule in a DITAVAL document does one of the following:
  • Defines a rendering behavior for an attribute and value pair, for example, audience="novice".
  • Defines a default behavior for a conditional processing attribute, such as defining a default rendering behavior of exclude for the @deliveryTarget. With that default, any @deliveryTarget value not otherwise defined in the document uses that default behavior of exclude.
  • Defines a default behavior for all conditional processing attributes, such as defining a default rendering behavior of exclude. With that default, any conditional-processing attribute not otherwise defined in the document uses that default behavior of exclude.

While the DITAVAL markup is not part of the DITA topic or map vocabulary and cannot be specialized, the XML itself is part of the specification. See DITAVAL elements for details.

Conditional processing attribute values

Conditional processing attributes use space-delimited string values or grouped string values to support both filtering and flagging.

The simplest and most common way to specify metadata on a conditional processing attribute is using individual string values. For example, the values basic and deluxe within <p product="basic deluxe"> indicate that the paragraph applies to the basic and deluxe products.

Setting a conditional processing attribute to an empty value, such as product="", is equivalent to omitting that attribute from the element.

Conditional processing attribute values with groups

For more advanced needs, groups can be used to organize metadata into subcategories within a conditional processing attribute.

Grouped values are intended to support situations where a metadata attribute applies to multiple specialized subcategories. For example, if content is classified into two distinct types of product, those distinct types can become named groups within the @product attribute. The grouping syntax exactly matches the syntax used for generalized attributes, making it valid inside @props and any attribute specialized from @props, including those integrated by default in the OASIS-provided document-type shells: @audience, @deliveryTarget, @platform, @product, @otherprops.

The following rules apply to groups within conditional processing attributes:

  • Groups consist of a name immediately followed by a parenthetical group of zero or more space-delimited string values. For example, "groupName(valueOne valueTwo)".
  • Groups cannot be nested.
  • If two groups with the same name are found in a single attribute, they are treated as if all values are specified in the same group. The following values for the @otherprops attribute are equivalent:
    otherprops="groupA(a b) groupA(c) groupZ(APPNAME)"
    otherprops="groupA(a b c) groupZ(APPNAME)"
  • If both grouped values and ungrouped values are found in a single attribute, the ungrouped values belong to an implicit group; the name of that group matches the name of the attribute. Therefore, the following values for the @product attribute are equivalent:
    product="a database(dbA dbB) b appserver(mySERVER) c"
    product="product(a b c) database(dbA dbB) appserver(mySERVER)"

An empty group within an attribute is equivalent to omitting that group from the attribute. For example, <ph product="database() A"> is equivalent to <ph product="A">. Similarly, <ph product="operatingSystem()"> is equivalent to <ph product="">, which in turn is equivalent to <ph>.

If two groups with the same name exist on different attributes, a rule specified for that group will evaluate the same way on each attribute. For example, if the group "sample" is specified within both @platform and @otherprops, a DITAVAL rule for sample="value" will evaluate the same in each attribute. If there is a need to distinguish between similarly named groups on different attributes, the best practice is to use more specific group names such as platformGroupname and productGroupname. Alternatively, DITAVAL rules can be specified based on the attribute name rather than the group name.

If the same group name is used in different attributes, a complex scenario could be created where different defaults are specified for different attributes, with no rule set for a group or individual value. In this case a value might end up evaluating differently in the different attributes. For example, a DITAVAL can set a default of "exclude" for @platform and a default of "flag" for @product. If no rules are specified for group oddgroup(), or for the value oddgroup="edgecase", the attribute platform="oddgroup(edgecase)" will evaluate to "exclude" while product="oddgroup(edgecase)" will resolve to "flag". See DITAVAL elements for information on how to change default behaviors in DITAVAL profile.

Conditional processing and subject schemes

When a subject scheme defines controlled values for an attribute, a processor can make use of that scheme for conditional processing.

Filtering based on metadata attributes

When rendering content, a conditional processing profile can be used to specify whether an element's content is filtered based on its conditional processing attributes.

To determine whether content is filtered, a processor compares the conditional processing attributes on a DITA element to rules specified in a conditional processing profile. If any one of the conditional processing attributes evaluates as exclude, that content is filtered.

Within a DITAVAL document, it is possible to specify a default action for conditional processing attributes. When no default is specified, the processing default for any attribute or value not otherwise listed is include. For example, if no default action is provided for @audience and the value novice for that attribute is not defined, that attribute value will have a processing default of include.

When deciding whether to include or exclude a particular element, a processor evaluates each attribute independently:

  1. For each attribute:
    • If the attribute is empty, or contains only empty groups, it is equivalent to omitting the attribute from the element. If evaluated for the purposes of filtering, the attribute is treated as "include", because an omitted attribute cannot evaluate to "exclude".
    • If the attribute value does not contain any groups, then if any string token in the attribute value evaluates to include, the element evaluates to include. In other words, the attribute evaluates to exclude only when all string tokens in that attribute evaluate to exclude.
    • If the attribute value does include groups, evaluate as follows, treating ungrouped tokens together as an implicit group:
      1. For each group (including any implicit group), if any string token inside the group evaluates to include, the group evaluates to include. In other words, a group evaluates to exclude only when all string tokens in that group evaluate to exclude.
      2. If any group within an attribute evaluates to exclude, that attribute evaluates to exclude. In other words, the attribute evaluates to include only when all groups in that attribute evaluate to include.
  2. If any single attribute evaluates to exclude, the element is filtered.

For example, if a paragraph applies to three products and the publisher has chosen to exclude all of them, the processor will exclude the paragraph. This is true even if the paragraph applies to an audience or platform that is not excluded. But if the paragraph applies to an additional product that has not been excluded, then its content is still relevant for the intended output and is preserved.

Flagging based on metadata attributes

When rendering content, a conditional processing profile can be used to specify whether an element's content is flagged based on its conditional processing attributes.

For example, flagging can be used to highlight the fact that content applies to a specific audience or operating system. Flagging can also draw a reader's attention to content that has been marked as being revised.

When deciding whether to flag a particular element, a processor evaluates each value. Wherever an attribute value that has been set as flagged appears (for example, audience="administrator"), the processor adds the flag. When multiple flags apply to a single element, multiple flags are rendered, typically in the order that they are encountered.

When the same element evaluates as both flagged and included, the element is both flagged and included. When the same element evaluates as both flagged and filtered (for example, flagged because of a value for the @audience attribute and filtered because of a value for the @product attribute value), the element is filtered.

When flagging methods are specified for elements at different levels of the containment hierarchy, the flagging method that is specified for the element at the lowest level of the hierarchy applies.

For example, if a <section> element is to be flagged with green text and a <p> element within that section is to be flagged with red text, the <p> element should be rendered with red text.

Examples of conditional processing

This section is non-normative.

This section provides examples that illustrate the ways that conditional processing attributes can be set and used.

Example: Setting conditional processing values

This section is non-normative.

In this scenario, conditional processing attributes are set in DITA content.

The following code sample illustrates how conditional processing attributes are set in DITA content.
<p audience="administrator">Set the configuration options:
  <ul>
    <li product="extendedProd">Set foo to bar</li>
    <li product="basicProd extendedProd">Set your blink rate</li>
    <li>Do some other stuff</li>
    <li>Do a special thing for Linux</li>
  </ul>
</p>
In the example,
  • The entire paragraph and list of options applies to an audience of administrator.
  • The first configuration item applies only to the extendedProd product.
  • The second configuration option applies to both the baseProd and extendedProd products.

When combined with a DITAVAL document, these attributes can be used as a way to filter or flag the content when it is rendered.

Example: Simple DITAVAL document

This section is non-normative.

In this scenario, a simple DITAVAL document sets up rules for filtering and flagging based on conditional processing attributes.

The following code sample illustrates a simple DITAVAL document that sets up two rules for filtering, and two rules for flagging.

<val>
  <prop action="exclude" att="audience" val="advanced"/>
  <prop action="exclude" att="product" val="myProductPrime"/>
  <prop action="flag" att="product" val="myProduct" backcolor="purple"/>
  <revprop action="flag" val="v1.2" backcolor="yellow"/>
</val>
Based on those rules:
  1. Any element with audience="advanced" will be filtered and will not appear in the rendered content.
  2. Any element with product="myProductPrime" will be filtered and will not appear in the rendered content.
  3. Any element with product="myProduct" will be flagged with a purple background color.
  4. Any element with rev="v1.2" will be flagged with a yellow background color.
  5. All other content will be rendered normally, because any other conditional processing attribute values default to include.

Example: Changing the default behavior to "exclude"

This section is non-normative.

In this scenario, a simple DITAVAL document resets the default behavior for unspecified values to "exclude".

The following code sample illustrates a simple DITAVAL document that resets the default behavior to "exclude", and then defines two rules to include content.

<val>
  <prop action="exclude"/>
  <prop action="include" att="audience" val="novice"/>
  <prop action="include" att="product" val="myProductPrime"/>
</val>
Based on those rules:
  1. Any element with audience="novice" will be included and will appear in the rendered content.
  2. Any element with product="myProductPrime" will be included and will appear in the rendered content.
  3. All other values in conditional processing attributes evaluate to exclude.

As a result, any element with conditional processing attributes that do not match either audience="novice" or product="myProductPrime" will be filtered and will not appear in the rendered content.

Example: Flagging with @outputclass

This section is non-normative.

In this scenario, the @outputclass attribute in a DITAVAL document is used to enable CSS based flagging.

An additional expectation for this scenario is that the processor rendering DITA content preserves @outputclass values as CSS @class tokens in HTML5. For example, the phrase <ph outputclass="bird">eagle</ph> might be rendered in HTML5 as <span class="bird">eagle</span>.

The following code sample illustrates a simple DITAVAL document that sets up two rules for flagging using @outputclass.

<val>
  <prop action="flag" att="product" val="myProduct" outputclass="myProductToken"/>
  <prop action="flag" att="product" val="myOtherProduct" outputclass="myOtherProductToken"/>
</val>
Now, assume the following DITA content is processed using the rules from that DITAVAL document:
<ol>
  <li>This list item applies to all content</li>
  <li product="myProduct">This list item is specific to my product</li>
  <li product="myProduct" outputclass="example">This list item is an example of an edge case</li>
  <li product="myOtherProduct">This list item is specific to my OTHER product</li>
  <li product="myProduct myOtherProduct">This list item is specific to both of my products</li>
</ol>
Based on the rules from that DITAVAL document, the topic content is processed as follows:
  1. The first item does not specify any conditional processing attributes, and is handled normally.
  2. The second item specifies product="myProduct". Based on the DITAVAL document, this results in a setting on outputclass="myProductToken". The content is processed as if the original element was: <li product="myProduct" outputclass="myProductToken">.
  3. The third item specifies product="myProduct", but already has an @outputclass attribute specified in the source. Based on the DITAVAL document, the content is processed as if the original element was: <li product="myProduct" outputclass="myOtherProductToken example">. Note that the value supplied by the DITAVAL document is placed before any value already in the source.
  4. The fourth item specifies product="myOtherProduct". Based on the DITAVAL document, this results in a setting on outputclass="myOtherProductToken". The content is processed as if the original element was: <li product="myOtherProduct" outputclass="myOtherProductToken">.
  5. The fifth item specifies both products with product="myProduct myOtherProduct". Based on the DITAVAL document, this results in a setting of either outputclass="myProductToken myOtherProductToken" or outputclass="myOtherProductToken myProductToken". The order of the two tokens is unspecified; if a processor chooses the first, the content is processed as if the original element was: <li product="myProduct myOtherProduct" outputclass="myProductToken myOtherProductToken">.
With the expectation that the processor maps @outputclass values onto the HTML @class attribute, the rendered HTML5 result would look like this:
<ol>
  <li>This list item applies to all content</li>
  <li class="myProductToken">This list item is specific to my product</li>
  <li class="myProductToken example">This list item is an example of an edge case</li>
  <li class="myOtherProductToken">This list item is specific to my OTHER product</li>
  <li class="myProductToken myOtherProductToken">This list item is specific to both of my products</li>
</ol>

Example: Filtering based on groups

This section is non-normative.

In this scenario, groups are used for filtering within a conditional processing attribute.

The following code sample illustrates a list item that applies to two different types of product. It applies to one application server and two database applications:
<ol>
  <li>Common step</li>
  <li product="appServer(mySERVER) database(dbOne dbOther)">
    <ph>Do something special for databases dbTwo or dbOther when installing on mySERVER</ph>
  </li>
  <!-- additional list items -->
</ol>

If a publisher decides to exclude the application server mySERVER, then the appServer() group evaluates to exclude. This can be done by setting product="mySERVER" to exclude or by setting appServer="mySERVER" to exclude. This means the item is excluded, regardless of how the values dbOne or dbOther evaluate. If a rule is specified for both product="mySERVER" and appServer="mySERVER", the rule for the more specific group name "appServer" takes precedence.

Similarly, if both dbOne and dbOther evaluate to exclude, then the database() group evaluates to exclude and the element is excluded regardless of how the "mySERVER" value is set.

In more advanced usage, a DITAVAL can be used to specify a rule for a group name. For example, an author could create a DITAVAL rule that sets product="database" to "exclude". This is equivalent to setting a default of "exclude" for any individual value in a database() group; it also excludes the more common usage of "database" as a single value within the @product attribute. Thus when "myDB" appears in a database() group within the @product attribute, the full precedence for determining whether to include or exclude the value is as follows:
  1. Check for a DITAVAL rule for database="dbOne"
  2. Check for a DITAVAL rule for product="dbOne"
  3. Check for a DITAVAL rule for product="database" (default for the database group)
  4. Check for a DITAVAL rule for "product" (default for the @product attribute)
  5. Check for a default rule for all conditions (default of include or exclude for all attributes)
  6. Otherwise, evaluate to "include"

Example: Filtering and flagging topic content

This section is non-normative.

In this scenario, a publisher wants to flag information that applies to administrators and exclude information that applies to the extended product.

Consider the following DITA source fragment and conditional processing profile:

Figure 1. DITA source fragment
<p audience="administrator">Set the configuration options:
  <ul>
    <li product="extendedProd">Set foo to bar</li>
    <li product="basicProd extendedProd">Set your blink rate</li>
    <li>Do some other stuff</li>
    <li>Do a special thing for Linux</li>
  </ul>
</p>
Figure 2. DITAVAL profile
<val>
  <prop att="audience" val="administrator" action="flag">
    <startflag><alt-text>ADMIN</alt-text></startflag>
  </prop>
  <prop att="product" val="extendedProd" action="exclude"/>
</val>

When the content is rendered, the paragraph is flagged, and the first list item is excluded (since it applies to extendedProd). The second list item is still included; even though it does apply to extendedProd, it also applies to basicProd, which was not excluded.

The result will look something like the following:
ADMIN Set the configuration options:
  • Set your blink rate
  • Do some other stuff
  • Do a special thing for Linux

Example: Simple DITAVAL document

This section is non-normative.

A DITAVAL document can reference tokens that pull in additional topics from a subject scheme.

Example: DITAVAL with conditions for groups

This section is non-normative.

In this advanced scenario, grouped values are used for filtewring within a conditional processing attribute.

Example

This section is non-normative.

<val>
   <prop action="exclude" att="product" val="appserver"/>
   <prop action="include" att="product" val="mySERVER"/>
   <prop action="include" att="database" val="dbFIRST"/>
   <prop action="include" att="database" val="dbSECOND"/>
   <prop action="exclude" att="database" val="newDB"/>
</val>
Assume that "database" and "appServer" are used as group names within the @product attribute. In that case, the sample DITAVAL above performs the following actions:
  • The first <prop> element excludes the value "appServer" when used within the @product attribute. It also sets a default of "exclude" for values within any appServer() group inside of the @product attribute.
  • The second <prop> element sets "mySERVER" to include; this applies whether "mySERVER" appears alone in the @product attribute (product="mySERVER") or inside of any group (product="appServer(mySERVER)" or product="otherGroup(mySERVER)").
  • The third and fourth <prop> elements set the database values "dbFIRST" and "dbSECOND" to include. If those values appear inside of a "database" group, they are explicitly set to "include". If they appear elsewhere in a conditional attribute (such as product="dbFIRST" or platform="dbSECOND"), this rule does not apply.
  • The final <prop> element sets the database value "newDB" to exclude. If that value appears inside of a database group, it is explicitly set to "exclude". If it appears in any other group or attribute, this rule does not apply.
Remember that with groups, if all values inside of a single group evaluate to "exclude", that is equivalent to an entire attribute evaluating to "exclude", which results in the removal of the content. Using the above sample DITAVAL:
  • <p product="appServer"> is filtered out, because this value is excluded.
  • <p product="appServer(A B)"> is filtered out, because there is no explicit rule for A or B, and values in the "appServer" group inside of @product default to exclude.
  • <p product="appServer(A B mySERVER)"> is included, because product="mySERVER" evaluates to "include", which means the entire group evaluates to "include".
  • <p product="newDB"> is included, because no rule in the DITAVAL applies, so the "newDB" token defaults to "include".
  • <p product="database(newDB)"> is filtered out, because the token "newDB" is excluded when found in the database group.
  • <p product="database(dbFIRST dbSECOND newDB)"> is included, because both "dbFIRST" and "dbSECOND" are included, so the group evaluates to include.
  • <p product="database(newDB) appserver(mySERVER)"> is filtered out, because the token "newDB" is excluded when found in the database group. The entire "database" group on this paragraph evaluates to "exclude", so the element is excluded, regardless of how the "appServer" group evaluates.
Note (non-normative):
If two groups with the same name exist on different attributes, each group will evaluate the same way. For example, rules for the database group in this sample would evaluate the same whether the group is used within @product or @platform. See Conditional processing for suggestions on how to handle similar groups on different attributes.