You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 4 Next »

Observations

  • many global group defs exist with the intention that they are ONLY going to be used as hidden groups. An example of this is presence-bit indicator flags. These are 1-bit elements that live in a hidden group because they control presence of absence of an element in the data.
  • other global group defs are created with the intention that they are only going to be used as non-hidden groups. However, users are free to use these as hidden groups.
  • The daffodil schema compiler has a mapping that tells us whether the only group refs referring to a particular group def are all hidden or are not all hidden, or none are hidden.
  • It is possible to determine for any given Term, if it ever could appear in a hidden context or not. That is, it is possible to determine whether a Term is always hidden, never hidden, or sometimes hidden, sometimes not. This can be determined by following the upward transitive closure of all containments.

Implementation

This flag member is set on infoset elements at the time they are created (parsing) or spliced into the infoset (unparsing - streaming unparser).

The isHidden flag is effectively an Evaluatable[Boolean].

If a GlobalGroupDef is only referenced from hiddenGroupRefs, then it and all terms inside it are statically known to be hidden.

If a GlobalGroupDef is never referenced from hiddenGrouRefs, then it an all terms immediately inside it are statically known not to be hidden.

Otherwise it must be determined dynamically depending on what hiddenGroupRefs are in the surrounding dynamic context.

This is much like any runtime-computed property value. E.g., much like how ByteOrder is computed. An Evaluatable[Boolean] is defined and made available on TermRuntimeData.

This works by dynamically maintaining boolean PState/UState member isInsideHiddenContext.

  1. ParseOrUnparseState has member.

    var isInsideHiddenContext : Boolean = false
  2. SequenceRuntimeData has constructor argument/member:

    val maybeHiddenGroupRefArg : Maybe[ModelGroupRuntimeData] 
    lazy val maybeHiddenGroupRef = maybeHiddenGroupRefArg // and also serialized
    def isHidden = maybeHiddenGroupRef.isDefined

    with value Nope for anything except a SequenceGroupRef that has the dfdl:hiddenGroupRef property. This is a Maybe type to provide for access to the referenced group's model-group runtime data. However, for purposes of isHidden computation this is just used as a boolean flag.

  3. In the parse1 and unparse1 methods of Parser and Unparser, If
    1. the TRD of the current processor is of type SequenceRuntimeData, and
    2. trd.maybeHiddenGroupRef.isDefined, and
    3. the state.isInsideHiddenContext is currently false
    4. then invoke the parse/unparse method within a code branch that first sets the isInsideHiddenContext to true, and sets it back to false upon unwinding. Note that a try-finally type of unwind-protect could be used, but should not be necessary, as parsers are supposed to unwind the stack without throws, and all throws are fatal when unparsing.
    5. else invoke the parse/unparse method normally, which does not affect the state of isInsideHiddenContext, so if already true, it stays true, if currently false, stays false.
  4. When infoset elements are created by element combinators, (parsing), or when they are accepted and spliced into the infoset by element combinators (unparsing) they are setIsHidden(state.isInsideHiddenContext)
  5. Runtime checking for elements inside hidden groups being either defaultable, or dfdl:outputValueCalc.
    1. When an element is setIsHidden(true), then if it is of simple type it should be checked to insure it is either defaultable or dfdl:outputValueCalc, and it is a runtime SDE if not.
  6. ChoiceCombinator.unparser method computes a choiceBranchEventMap, and also determines statically which branch should be taken if the choice is hidden. Both these are parameters to the ChoiceUnparserCombinator which creates a ChoiceUnparserCombinator which decides at runtime if it is unparsing an isHidden choice, and selects to use the statically determined branch if so, otherwise uses the choiceBranchEventMap.
  7. The ChoiceBranchEventMap is computed without regard for isHidden.

Test Plan/Design-for-Test

Tests should insure that elements are properly hidden if they are multiple group references away from a true dfdl:hiddenGroupRef.

Transition Plan

Releases 2.5.0 and prior did not use this technique.

Existing tests that expect to determine isHidden from ERDs of elements should be removed/rewritten, as the information is no longer available there.

Existing code that expects to find isHidden on ERDs should get it from the Infoset Element (DIElement class) directly instead.

Since we cannot know if an element will be hidden or not until runtime, many checks currently done at schema compile time must instead be done at runtime. For example, in childrenInHiddenGroupNotDefaultableOrOVC, a check is done for whether an element inside a hidden group is neither defaultable nor has dfdl:outputValueCalc. This test must be done at runtime instead as described above.

Static isHidden parameters - all these must be removed. Anything that statically depends on knowledge of isHidden must be revised to not depend on it.

Static analysis changes: many currently static attributes such as possibleFirstChildElementsInInfoset, currently depend on isHidden being statically determined. There is a specific static childrenInHiddenGroupNotDefaultableOrOVC attribute which must be removed.


  • No labels