Introduction
In Part 2, we introduced context rules and provided a primer on writing XPath expression. In this part, will take an example business rule (BR) and go through the steps, and cover common mistakes, of encoding the BR into a BREX context rule.
NOTE: For purposes of this exercise, we use Issue 4.0 and later markup. If you are still working with Issue 3.0, or earlier markup, the steps in writing BREX context rules is the same, only the tag names will be different.
The Business Rule
The business rules (BR) for this exercise is as follows:
All procedural steps must have an authored ID.
One of the first steps in authoring a BREX context rule is translating the human-readable BR into the exact XML structures the BR applies to. This activity helps determine if the BR can be represented as a BREX context rule. Fortunately, for this exercise, and in general practice (as it is common for a BR to explicitly state the XML structures involved), translating a BR to the relevant XML structures is straight-forward:
The phrase, “procedural steps” clearly refers to
<proceduralStep>
elements as defined within theproced.xsd
schema.The phrase, “authored ID” refers to the
id
attribute on the element.
Where challenges arise is producing the XPath expression and associated BREX markup that accurately represents the BR.
Attempt #1
Because the BR has the phrase, “must have”, we may be inclined to try something like the following (the following is not correct, can you spot the mistakes?):
<structureObjectRule>
<objectPath allowedObjectFlag="1">
//proceduralStep[@id]
</objectPath>
<objectUse>A procedural step must have an authored ID.</objectUse>
</structureObjectRule>
A common mistake when learning how to write context rules is the proper setting of the allowedObjectFlag
attribute, and the misunderstanding of how its value is interpreted in relation to the evaluation of the XPath expression. Unfortunately, the specification text that describes the attribute can contribute to the misunderstanding. The specification describes the attribute as follows (Issue 6, Chap 4.10.2.2):
allowedObjectFlag
( M ), defines if and how the object is applied within the organization or the project. The attribute can have one of the following values:
"
0
" - No, the object must not be used in the context concerned"
1
" - Yes, the object must be included in the context concerned"
2
" - the object can optionally be used in the context concerned, however, fully in accordance with the specification text and the Schemas
The BR says, “must have,” and the spec says, “must be included”, for value 1
, so 1
is the right value, right? Nope.
The allowedObjectFlag
applies to what the XPath expression itself returns and if any value restrictions are defined via <objectValue>
. For this exercise, <objectValue>
is not relevant, but the following is an example of how it is used:
<structureObjectRule>
<objectPath allowedObjectFlag="2">
//dmAddress/dmIdent/dmCode/@subSubsystemCode</objectPath>
<objectUse>Subsubsystem code may only be 0 through 9.</objectUse>
<objectValue valueForm="range" valueAllowed="0~9"/>
</structureObjectRule>
The value of allowedObjectFlag
is interpreted as follows if there are NO value restrictions defined:
“
0
” - The XPath expression must return no results.“
1
” - The XPath expression must return at least one, or more items.“
2
” - The XPath expression can return zero or more items (the rule always passes).
If value restrictions are defined, allowedObjectFlag
is interpreted as follows:
“
0
” - The XPath expression must return no results, or if results are returned, each item MUST NOT match any of the values specified.“
1
” - The XPath expression must return at least one or more items, and for each item returned, it MUST match at least one of the specified values.“
2
” - The XPath expression can return zero (no match) or more items. If zero items, the rule passes. If one or more items, each item MUST match at least one of the specified values.
Revisiting our first attempt:
<structureObjectRule>
<objectPath allowedObjectFlag="1">
//proceduralStep[@id]
</objectPath>
<objectUse>A procedural step must have an authored ID.</objectUse>
</structureObjectRule>
And with the more technical, but hopefully clearer, explanation of the allowedObjectFlag
attribute, Attempt #1 has the following problem: The rule fails for a non-procedural data module since the XPath expression will not match any <proceduralStep>
nodes. An allowedObjectFlag
of “1
” requires there is at least one match.
Attempt #2
One way to address the problem with Attempt #1 is to limit the rule so it will only apply to procedural data modules. Therefore, we may try something like the following (let’s assume we are working with Issue 5.0 data):
<contextRules
rulesContext="http://www.s1000d.org/S1000D_5-0/xml_schema_flat/proced.xsd">
<structureObjectRuleGroup>
<structureObjectRule>
<objectPath allowedObjectFlag="1">
//proceduralStep[@id]
</objectPath>
<objectUse>
A procedural step must have an authored ID.
</objectUse>
</structureObjectRule>
</structureObjectRuleGroup>
</contextRules>
If you recall in Part 2, using the rulesContext
attribute is not recommended, but it does solve the problem of the rule not getting applied to (Issue 5) non-procedural data modules. However, the rule is still deficient in enforcing the BR. Why?
The rule passes anytime the XPath expression returns at least one match. Therefore, if I had 10 <proceduralStep>
elements in a data module, but only 1 had the id
attribute defined, the data module will pass the rule because that one step will be returned by the expression while the 9 other steps violating the BR go unreported.
Attempt #3
Hopefully, the old adage, “third time’s a charm," applies here. In order to address the problems with Attempt #2, we need to apply a very useful technique when it comes to translating BRs into BREX context rules:
Match what is not allowed
For some, this may seem counter-intuitive, but you will come to realize that this technique greatly simplifies the authoring of BREX context rules. Let’s remind ourselves the original wording of the BR:
All procedural steps must have an authored ID.
Now, lets flip the phrasing so it represents what is not allowed:
A procedural step with no authored ID is not allowed.
Not as readable as the original, but it is logically equivalent and in a form that is easier to implement as a BREX context rules:
<structureObjectRule>
<objectPath allowedObjectFlag="0">
//proceduralStep[not(@id)]
</objectPath>
<objectUse>
A procedural step must have an authored ID.
</objectUse>
</structureObjectRule>
🎉SUCCESS 🎉
Explanation of changes made:
The
allowedObjectFlag
attribute changed to “0”: The expression must return no matches.The XPath expression changed to match elements that should not exist: steps with no IDs.
The need to contextualize the rule to a specific schema-type (
proced.xsd
) is no longer required since we know other schemas do not support the<proceduralStep>
element, where no matches will ever occur. The exception isprocess.xsd
(Process data modules), but in this case, the BR is still applicable, so we have a single context rule that satisfies two (schema) contexts and will not generate false failures for other data module types.
It is worth noting the <objectUse>
content is unchanged. The role of <objectUse>
is to provide a human-readable description of the rule, to function as a reference guide to data module authors. Our rephrasing of the BR solely serves in codifying the BR as a BREX context rule. In practice, the <objectUse>
content is copied directly from the business rules document of your project or is a concise summary of the BR. Most BREX validation tools will echo the contents of <objectUse>
in any failures reported, for example:
What’s Next?
Part 4 will cover the steps of translating a real-world business rule into a BREX context rule, show that you are not limited to simple path-like expressions, and summarize tips to keep in mind when developing BREX context rules.