in daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/UnseparatedSequenceUnparsers.scala [83:208]
protected def unparse(state: UState): Unit = {
state.groupIndexStack.push(1L) // one-based indexing
var index = 0
var doUnparser = false
val limit = childUnparsers.length
while (index < limit) {
val childUnparser = childUnparsers(index)
val trd = childUnparser.trd
state.pushTRD(trd) // because we inspect before we invoke the unparser
//
// Unparsing an ordered sequence depends on the incoming
// stream of infoset events matching up with the order that
// they are expected as the unparser recurses through the
// child term unparsers.
//
childUnparser match {
case unparser: RepeatingChildUnparser => {
state.arrayIterationIndexStack.push(1L)
state.occursIndexStack.push(1L)
val erd = unparser.erd
var numOccurrences = 0
val maxReps = unparser.maxRepeats(state)
//
// The number of occurrances we unparse is always exactly driven
// by the number of infoset events for the repeating/optional element.
//
// For RepUnparser - array/optional case - in all cases we should get a
// startArray event. If we don't then
// the element must be entirely optional, so we get no events for it
// at all.
// we must have an event
Assert.invariant(state.inspect, "No event for unparing.")
val ev = state.inspectAccessor
if (ev.erd eq erd) {
// must be a start event for this array/optional unparser
val isArr = ev.isArray
Assert.invariant(ev.isStart && (isArr || ev.erd.isOptional))
//
// StartArray for this unparser's array element
//
unparser.startArrayOrOptional(state)
while ({
doUnparser = unparser.shouldDoUnparser(unparser, state)
doUnparser
}) {
if (isArr)
if (state.dataProc.isDefined)
state.dataProc.get.beforeRepetition(state, this)
unparseOne(unparser, erd, state)
numOccurrences += 1
state.moveOverOneArrayIterationIndexOnly()
state.moveOverOneOccursIndexOnly()
state.moveOverOneGroupIndexOnly() // array elements are always represented.
if (isArr)
if (state.dataProc.isDefined)
state.dataProc.get.afterRepetition(state, this)
}
// DAFFODIL-115: if the number of occurrences is less than minOccurs we are supposed
// to check if the element is defaultable and add elements until we reach that
// number. Daffodil does not currently support defaulting during unparsing.
unparser.checkFinalOccursCountBetweenMinAndMaxOccurs(
state,
unparser,
numOccurrences,
maxReps,
state.arrayIterationPos - 1
)
unparser.endArrayOrOptional(erd, state)
} else {
// this is either a start event for a following element or an end event for a
// parent element. Either way, we never saw a start event for this array/optional,
// which means there were zero occurrenes. Make sure that is allowed for this array
//
// DAFFODIL-115: if the number of occurrences is less than minOccurs we are supposed
// to check if the element is defaultable and add elements until we reach that
// number. Daffodil does not currently support defaulting during unparsing.
unparser.checkFinalOccursCountBetweenMinAndMaxOccurs(
state,
unparser,
numOccurrences,
maxReps,
0
)
}
state.arrayIterationIndexStack.pop()
state.occursIndexStack.pop()
}
//
case scalarUnparser => {
unparseOne(scalarUnparser, trd, state)
// only move over in group if the scalar "thing" is an element
// that is represented.
scalarUnparser.trd match {
case erd: ElementRuntimeData if (!erd.isRepresented) => // ok, skip group advance
case _ => state.moveOverOneGroupIndexOnly()
}
}
}
state.popTRD(trd)
index += 1
//
// Note: the invariant is that unparsers move over 1 within their group themselves
// we do not do the moving over here as we are the caller of the unparser.
//
}
state.groupIndexStack.pop()
//
// this is establishing the invariant that unparsers (in this case the sequence unparser)
// moves over within its containing group. The caller of an unparser does not do this move.
//
// state.moveOverOneGroupIndexOnly() // move past this sequence itself, next group child it ITS parent.
}