You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@daffodil.apache.org by sl...@apache.org on 2023/01/26 18:55:30 UTC
[daffodil] branch main updated: Only add positionally required separators for arrays with occursCountKind="implicit"
This is an automated email from the ASF dual-hosted git repository.
slawrence pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/daffodil.git
The following commit(s) were added to refs/heads/main by this push:
new fc660df1a Only add positionally required separators for arrays with occursCountKind="implicit"
fc660df1a is described below
commit fc660df1aecfce81f276b79b9c9f9eb9ce893153
Author: Steve Lawrence <sl...@apache.org>
AuthorDate: Thu Jan 26 10:15:35 2023 -0500
Only add positionally required separators for arrays with occursCountKind="implicit"
If a schema has a separated array/optional with occursCountKind as fixed
or expression, then we currently always unparse maxOccurs separators
even if there were less than maxOccurs instances in the infoset. This is
incorrect--we should only output a separator for each instance in the
infoset and no more, regardless of the value of min/maxOccurs. Only with
occursCountKind set to implicit should min/maxOccurs be taken into
account when unparsing positionally required separators.
The unparsePositionallyRequiredSeps function handles the separator logic
for implicit arrays, but should be skipped otherwise. This modifies the
condition so it is only considered for the implicit case.
Also makes the "ock" variable in the MinMaxRepatsMixin public since it
is useful in a number of places, including this new check.
DAFFODIL-2231
---
.../unparsers/SeparatedSequenceUnparsers.scala | 21 +++--
.../unparsers/UnseparatedSequenceUnparsers.scala | 2 -
.../processors/parsers/SequenceChildBases.scala | 4 +-
.../section23/dfdl_expressions/expressions.tdml | 103 +++++++++++++++++++++
.../dfdl_expressions/TestDFDLExpressions.scala | 5 +
5 files changed, 122 insertions(+), 13 deletions(-)
diff --git a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/processors/unparsers/SeparatedSequenceUnparsers.scala b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/processors/unparsers/SeparatedSequenceUnparsers.scala
index 89ccc7310..7a0fb9095 100644
--- a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/processors/unparsers/SeparatedSequenceUnparsers.scala
+++ b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/processors/unparsers/SeparatedSequenceUnparsers.scala
@@ -17,15 +17,16 @@
package org.apache.daffodil.processors.unparsers
import org.apache.daffodil.exceptions.Assert
+import org.apache.daffodil.processors.ModelGroupRuntimeData
import org.apache.daffodil.processors.{ ElementRuntimeData, SequenceRuntimeData, TermRuntimeData }
import org.apache.daffodil.schema.annotation.props.SeparatorSuppressionPolicy
-import org.apache.daffodil.schema.annotation.props.gen.{ SeparatorPosition }
-import org.apache.daffodil.processors.ModelGroupRuntimeData
-import scala.collection.mutable.Buffer
-import SeparatorSuppressionPolicy._
-import SeparatorPosition._
+import org.apache.daffodil.schema.annotation.props.SeparatorSuppressionPolicy._
+import org.apache.daffodil.schema.annotation.props.gen.OccursCountKind
+import org.apache.daffodil.schema.annotation.props.gen.SeparatorPosition
+import org.apache.daffodil.schema.annotation.props.gen.SeparatorPosition._
import org.apache.daffodil.util.Maybe
import org.apache.daffodil.util.MaybeInt
+import scala.collection.mutable.Buffer
trait Separated { self: SequenceChildUnparser =>
@@ -458,8 +459,13 @@ class OrderedSeparatedSequenceUnparser(
var numOccurrences = numOccurs
unparserArg match {
case unparser: RepOrderedSeparatedSequenceChildUnparser => {
- val isBounded = unparser.isBoundedMax
- if (unparser.isPositional && isBounded &&
+ // note that if we are unparsing an array/optional, we only add positionally
+ // required separators for occursCountKind="implicit". All other
+ // occursCountKind's use the number of elements in the infoset to determine
+ // the number of separators, which would have already been unparsed prior to
+ // this function being called.
+ if ((unparser.ock eq OccursCountKind.Implicit) &&
+ unparser.isPositional && unparser.isBoundedMax &&
(!unparser.isDeclaredLast || !unparser.isPotentiallyTrailing)) {
val maxReps = unparser.maxRepeats(state)
while (numOccurrences < maxReps) {
@@ -469,7 +475,6 @@ class OrderedSeparatedSequenceUnparser(
state.moveOverOneGroupIndexOnly()
numOccurrences += 1
}
- //
}
}
case _ => Assert.invariantFailed("Not a repeating element")
diff --git a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/processors/unparsers/UnseparatedSequenceUnparsers.scala b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/processors/unparsers/UnseparatedSequenceUnparsers.scala
index 9d4adb2ff..e4c657837 100644
--- a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/processors/unparsers/UnseparatedSequenceUnparsers.scala
+++ b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/processors/unparsers/UnseparatedSequenceUnparsers.scala
@@ -43,8 +43,6 @@ class RepOrderedUnseparatedSequenceChildUnparser(
extends RepeatingChildUnparser(childUnparser, srd, erd)
with Unseparated {
- private val ock = erd.maybeOccursCountKind.get
-
override def checkArrayPosAgainstMaxOccurs(state: UState): Boolean = {
if (ock eq OccursCountKind.Implicit)
state.arrayPos <= maxRepeats(state)
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/SequenceChildBases.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/SequenceChildBases.scala
index 90d6f5eb6..5c9552d34 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/SequenceChildBases.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/SequenceChildBases.scala
@@ -460,7 +460,7 @@ trait MinMaxRepeatsMixin {
def erd: ElementRuntimeData
- private val ock = erd.maybeOccursCountKind.get
+ final val ock = erd.maybeOccursCountKind.get
private val minRepeats_ = {
val mr =
@@ -552,8 +552,6 @@ abstract class OccursCountMinMaxParser(
Assert.invariant(erd.maybeOccursCountKind.isDefined)
- private val ock = erd.maybeOccursCountKind.get
-
Assert.invariant(ock == OccursCountKind.Implicit ||
ock == OccursCountKind.Parsed)
diff --git a/daffodil-test/src/test/resources/org/apache/daffodil/section23/dfdl_expressions/expressions.tdml b/daffodil-test/src/test/resources/org/apache/daffodil/section23/dfdl_expressions/expressions.tdml
index 9b99d3573..00f6858b1 100644
--- a/daffodil-test/src/test/resources/org/apache/daffodil/section23/dfdl_expressions/expressions.tdml
+++ b/daffodil-test/src/test/resources/org/apache/daffodil/section23/dfdl_expressions/expressions.tdml
@@ -1375,6 +1375,43 @@
</xs:complexType>
</xs:element>
+ <!-- same idea as ocke10, but uses occursCountKind="expression" -->
+ <xs:element name="ocke9">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="exists" type="xs:boolean" dfdl:terminator=":"
+ dfdl:textBooleanTrueRep="true" dfdl:textBooleanFalseRep="false" />
+ <xs:sequence dfdl:separator="|" dfdl:separatorPosition="infix">
+ <xs:element name="field1" type="xs:string" minOccurs="0"
+ dfdl:occursCountKind="expression"
+ dfdl:occursCount="{ if (../ex:exists eq fn:true()) then 1 else 0 }" />
+ <xs:element name="field2" type="xs:string" dfdl:occursCountKind="implicit" maxOccurs="unbounded" />
+ </xs:sequence>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ <!-- same idea as ocke9, but uses occursCountKind="implicit" plus a discriminator -->
+ <xs:element name="ocke10">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="exists" type="xs:boolean" dfdl:terminator=":"
+ dfdl:textBooleanTrueRep="true" dfdl:textBooleanFalseRep="false" />
+ <xs:sequence dfdl:separator="|" dfdl:separatorPosition="infix">
+ <xs:element name="field1" type="xs:string" minOccurs="0"
+ dfdl:occursCountKind="implicit">
+ <xs:annotation>
+ <xs:appinfo source="http://www.ogf.org/dfdl/">
+ <dfdl:discriminator>{ ../ex:exists eq fn:true() }</dfdl:discriminator>
+ </xs:appinfo>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="field2" type="xs:string" dfdl:occursCountKind="implicit" maxOccurs="unbounded" />
+ </xs:sequence>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
<xs:element name="expr_space" dfdl:lengthKind="implicit">
<xs:complexType>
<xs:sequence dfdl:separator=",">
@@ -1764,6 +1801,72 @@
</tdml:errors>
</tdml:parserTestCase>
+ <tdml:unparserTestCase name="ocke_optional_separator_01" root="ocke9"
+ model="expressions-Embedded.dfdl.xsd" description="occursCountKind expression - DFDL-23-011R">
+
+ <tdml:document>true:field1|field2a|field2b|field2c</tdml:document>
+ <tdml:infoset>
+ <tdml:dfdlInfoset>
+ <ex:ocke9 xmlns:ex="http://example.com">
+ <ex:exists>true</ex:exists>
+ <ex:field1>field1</ex:field1>
+ <ex:field2>field2a</ex:field2>
+ <ex:field2>field2b</ex:field2>
+ <ex:field2>field2c</ex:field2>
+ </ex:ocke9>
+ </tdml:dfdlInfoset>
+ </tdml:infoset>
+ </tdml:unparserTestCase>
+
+ <tdml:unparserTestCase name="ocke_optional_separator_02" root="ocke9"
+ model="expressions-Embedded.dfdl.xsd" description="occursCountKind expression - DFDL-23-011R">
+
+ <tdml:document>false:field2a|field2b|field2c</tdml:document>
+ <tdml:infoset>
+ <tdml:dfdlInfoset>
+ <ex:ocke9 xmlns:ex="http://example.com">
+ <ex:exists>false</ex:exists>
+ <ex:field2>field2a</ex:field2>
+ <ex:field2>field2b</ex:field2>
+ <ex:field2>field2c</ex:field2>
+ </ex:ocke9>
+ </tdml:dfdlInfoset>
+ </tdml:infoset>
+ </tdml:unparserTestCase>
+
+ <tdml:unparserTestCase name="ocke_optional_separator_03" root="ocke10"
+ model="expressions-Embedded.dfdl.xsd" description="occursCountKind expression - DFDL-23-011R">
+
+ <tdml:document>true:field1|field2a|field2b|field2c</tdml:document>
+ <tdml:infoset>
+ <tdml:dfdlInfoset>
+ <ex:ocke10 xmlns:ex="http://example.com">
+ <ex:exists>true</ex:exists>
+ <ex:field1>field1</ex:field1>
+ <ex:field2>field2a</ex:field2>
+ <ex:field2>field2b</ex:field2>
+ <ex:field2>field2c</ex:field2>
+ </ex:ocke10>
+ </tdml:dfdlInfoset>
+ </tdml:infoset>
+ </tdml:unparserTestCase>
+
+ <tdml:unparserTestCase name="ocke_optional_separator_04" root="ocke10"
+ model="expressions-Embedded.dfdl.xsd" description="occursCountKind expression - DFDL-23-011R">
+
+ <tdml:document>false:field2a|field2b|field2c</tdml:document>
+ <tdml:infoset>
+ <tdml:dfdlInfoset>
+ <ex:ocke10 xmlns:ex="http://example.com">
+ <ex:exists>false</ex:exists>
+ <ex:field2>field2a</ex:field2>
+ <ex:field2>field2b</ex:field2>
+ <ex:field2>field2c</ex:field2>
+ </ex:ocke10>
+ </tdml:dfdlInfoset>
+ </tdml:infoset>
+ </tdml:unparserTestCase>
+
<!--
Test Name: internal_space_preserved
Schema: expressions-Embedded.dfdl.xsd
diff --git a/daffodil-test/src/test/scala/org/apache/daffodil/section23/dfdl_expressions/TestDFDLExpressions.scala b/daffodil-test/src/test/scala/org/apache/daffodil/section23/dfdl_expressions/TestDFDLExpressions.scala
index fa0b2da0a..3af67b2b2 100644
--- a/daffodil-test/src/test/scala/org/apache/daffodil/section23/dfdl_expressions/TestDFDLExpressions.scala
+++ b/daffodil-test/src/test/scala/org/apache/daffodil/section23/dfdl_expressions/TestDFDLExpressions.scala
@@ -237,6 +237,11 @@ class TestDFDLExpressions {
@Test def test_ocke_array_index_step_dne(): Unit = { runner.runOneTest("ocke_array_index_step_dne") }
@Test def test_ocke_non_upward(): Unit = { runner.runOneTest("ocke_non_upward") }
@Test def test_ocke_single_upward(): Unit = { runner.runOneTest("ocke_single_upward") }
+ @Test def test_ocke_optional_separator_01(): Unit = { runner.runOneTest("ocke_optional_separator_01") }
+ @Test def test_ocke_optional_separator_02(): Unit = { runner.runOneTest("ocke_optional_separator_02") }
+ @Test def test_ocke_optional_separator_03(): Unit = { runner.runOneTest("ocke_optional_separator_03") }
+ @Test def test_ocke_optional_separator_04(): Unit = { runner.runOneTest("ocke_optional_separator_04") }
+
@Test def test_internal_space_preserved(): Unit = { runner.runOneTest("internal_space_preserved") }
@Test def test_internal_space_preserved2(): Unit = { runner.runOneTest("internal_space_preserved2") }
@Test def test_internal_space_preserved3a(): Unit = { runner.runOneTest("internal_space_preserved3a") }