...
Each defines a message element and a target namespace for that message. We're not bothering to show DFDL properties in these little examples because they don't matter for purposes of what we're trying to illustrate:
Code Block | ||
---|---|---|
| ||
<schema xmlns:a=".... a ...." targetNamespace="... a ..."> <element name="a_msg" type="a:a_msg_type"/> ... plus type definitions </schema> |
...
You now have one single schema that can be used to parse any of your messages. The result of the parse will always be surrounded by the envelope
element, but if the typeCode is 0 the element will be parsed as type A, 1 is B, 2 is C, and so on.
A Variation: The Type Code isn't "Real": An Asymmetric DFDL Schema
There is one other interesting variation worth discussing. What if the type code isn't actually part of the data. What if it is being slapped on the front so you can distinguish the different kinds of data, but you don't want it to show up in the infoset, nor be re-created when you unparse the data.
In that case we use a DFDL feature called hidden groups to hide the type code. We'll also play some tricks to prevent the type code from unparsing at all. Here's how the combined schema changes:
...
Code Block | ||
---|---|---|
| ||
<schema targetNamespace="... abc ..."> <import namespace="... a ..." schemaLocation="a.dfdl.xsd"/> <import namespace="... b ..." schemaLocation="b.dfdl.xsd"/> <import namespace="... c ..." schemaLocation="c.dfdl.xsd"/> <element name="envelope" type="abc:envelopeType"/> <complexType name="envelopeType"> <sequence> <sequence dfdl:hiddenGroupRef="abc:h_typeCode"/> <!-- DIFFERENT: Use a HIDDEN GROUP. --> <choice dfdl:choiceDispatchKey='{ xs:string(typeCode) }'> <element ref="m:a_msg" dfdl:choiceBranchKey="0" xmlns:m="...a..."/> <element ref="m:b_msg" dfdl:choiceBranchKey="1" xmlns:m="...b..."/> <element ref="m:c_msg" dfdl:choiceBranchKey="2" xmlns:m="...c..."/> </choice> </sequence> </complexType> <!-- Up to this point, only one line of the schema was different. The one that references the hidden group below. This hidden group at parse time will populate the typeCode element. The trick to keep it from unparsing is this: At unparse time the elements in the hidden group are not part of the infoset, so when unparsing this, the unparser will have nothing to go on ( when it encounters the need to unparse this hidden choice group. Now, dfdl:choiceDispatchKey is only evaluated when parsing, not when unparsing) and so the unparser has nothing to go on, so will choose the first branch of the choice here, which contains nothing so nothing gets unparsed. --> <group name="h_typeCode"> <choice dfdl:choiceDispatchKey='{ "parse" }'> <sequence dfdl:choiceBranchKey="unparse"> <!-- Don't unparse anything. By default, when unparsing a choice, the first branch is taken --> </sequence> <sequence dfdl:choiceBranchKey="parse"> <element name="typeCode" type="xs:unsignedInt" dfdl:outputValueCalc='{ 0 }'> <!-- And there is this one additional annoying detail: The dfdl:outputValueCalc above is only present to satisfy the Daffodil schema compiler. (All elements in hidden groups must have a way to unparse, which means they are defaultable or have a dfdl:outputValueCalc, or it will not schema-compile. Daffodil's compiler is not quite smart enough to realize this element will never be unparsed so the schema itcompiler insists on having a dfdl:outputValueCalc even though it the property will never be used.) --> </element> </sequence> </choice> </group> </schema> |
...