From 15bb1f29617095ae928848735dc449a41073d788 Mon Sep 17 00:00:00 2001
From: olabusayoT <50379531+olabusayoT@users.noreply.github.com>
Date: Wed, 21 Jan 2026 15:04:21 -0500
Subject: [PATCH] Add warning for `dfdl:occursCountKind=parsed` without
`dfdl:separatorSuppressionPolicy=anyEmpty`
- Introduced `TestImplicitvParsed` including TDML tests for `occursCountKind=parsed` and `occursCountKind=implicit`.
- Added "SeparatorSuppressionPolicyError" warning to enforce `separatorSuppressionPolicy="anyEmpty"` for `occursCountKind=parsed`.
- Implicit with SSP=trailingEmpty works as expected, with it looking for the prefix / for absent arre1 in e2 in the added implicitvparsed.tdml as per the spec (Table 47: RepDef(min) ~ Rep(max - min), which means RepDef(1) followed by Rep(2), so it expects the separator for the last empty arre1 element), so the right thing to do if we don't want the empty trailing / is to use anyEmpty
- Add SSP warning and specify error message in SequenceGroupDelimiters TDML test
- Updated test cases to align with these changes.
DAFFODIL-2801
---
.../daffodil/core/dsom/SequenceGroup.scala | 23 ++-
.../org/apache/daffodil/xsd/dafext.xsd | 1 +
.../occursCountKind/implicitvparsed.tdml | 134 ++++++++++++++++++
.../SequenceGroupDelimiters.tdml | 9 +-
.../apache/daffodil/usertests/SepTests.tdml | 4 +-
.../occursCountKind/TestImplicitvParsed.scala | 35 +++++
6 files changed, 201 insertions(+), 5 deletions(-)
create mode 100644 daffodil-test/src/test/resources/org/apache/daffodil/section14/occursCountKind/implicitvparsed.tdml
create mode 100644 daffodil-test/src/test/scala/org/apache/daffodil/section14/occursCountKind/TestImplicitvParsed.scala
diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/SequenceGroup.scala b/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/SequenceGroup.scala
index aa143c092d..a6a9bc0037 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/SequenceGroup.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/SequenceGroup.scala
@@ -102,6 +102,7 @@ abstract class SequenceGroupTermBase(xml: Node, lexicalParent: SchemaComponent,
with SeparatorSuppressionPolicyMixin {
requiredEvaluationsIfActivated(checkIfValidUnorderedSequence)
+ requiredEvaluationsIfActivated(checkValidityOccursCountKind)
requiredEvaluationsIfActivated(checkIfNonEmptyAndDiscrimsOrAsserts)
requiredEvaluationsIfActivated(checkIfMultipleChildrenWithSameName)
@@ -160,6 +161,24 @@ abstract class SequenceGroupTermBase(xml: Node, lexicalParent: SchemaComponent,
}
}.value
+ lazy val checkValidityOccursCountKind: Unit = {
+ if (hasSeparator && (separatorSuppressionPolicy ne SeparatorSuppressionPolicy.AnyEmpty)) {
+ val optInvalidChild = groupMembers.find {
+ case e: ElementBase => e.occursCountKind == OccursCountKind.Parsed
+ case _ => false
+ }
+ if (optInvalidChild.isDefined) {
+ optInvalidChild.get.SDW(
+ WarnID.SeparatorSuppressionPolicyError,
+ "Member of a sequence with dfdl:occursCountKind='parsed' must have a " +
+ "containing sequence with dfdl:separatorSuppressionPolicy='anyEmpty', " +
+ "but was %s. This may be changed to an error in a future version of Daffodil.",
+ separatorSuppressionPolicy
+ )
+ }
+ }
+ }
+
/**
* Provides validation for assert and discriminator placement
*/
@@ -181,12 +200,12 @@ abstract class SequenceGroupTermBase(xml: Node, lexicalParent: SchemaComponent,
protected final lazy val checkIfValidUnorderedSequence: Unit = {
if (!isOrdered) {
checkMembersAreAllElementOrElementRef
- checkMembersHaveValidOccursCountKind
+ checkUnorderedSequenceMembersHaveValidOccursCountKind
checkUnorderedSequenceMembersHaveUniqueNamesInNamespaces
}
}
- private lazy val checkMembersHaveValidOccursCountKind: Unit = {
+ private lazy val checkUnorderedSequenceMembersHaveValidOccursCountKind: Unit = {
val validChildren: Seq[ElementBase] =
groupMembers
.filter { m => m.isInstanceOf[LocalElementDecl] || m.isInstanceOf[ElementRef] }
diff --git a/daffodil-propgen/src/main/resources/org/apache/daffodil/xsd/dafext.xsd b/daffodil-propgen/src/main/resources/org/apache/daffodil/xsd/dafext.xsd
index 719870bb27..8e0398c04a 100644
--- a/daffodil-propgen/src/main/resources/org/apache/daffodil/xsd/dafext.xsd
+++ b/daffodil-propgen/src/main/resources/org/apache/daffodil/xsd/dafext.xsd
@@ -755,6 +755,7 @@
+
diff --git a/daffodil-test/src/test/resources/org/apache/daffodil/section14/occursCountKind/implicitvparsed.tdml b/daffodil-test/src/test/resources/org/apache/daffodil/section14/occursCountKind/implicitvparsed.tdml
new file mode 100644
index 0000000000..1a68f470b3
--- /dev/null
+++ b/daffodil-test/src/test/resources/org/apache/daffodil/section14/occursCountKind/implicitvparsed.tdml
@@ -0,0 +1,134 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+ 2
+
+ 3.5
+ one
+
+
+ 4
+ two
+
+ a
+ 6
+
+
+
+
+
+
+
+
+
+
+ 1
+ 2
+
+ 3.5
+ one
+
+
+ 4
+ two
+
+ a
+ 6
+
+
+
+
+
+
\ No newline at end of file
diff --git a/daffodil-test/src/test/resources/org/apache/daffodil/section14/sequence_groups/SequenceGroupDelimiters.tdml b/daffodil-test/src/test/resources/org/apache/daffodil/section14/sequence_groups/SequenceGroupDelimiters.tdml
index d3f10849f1..4f9af20236 100644
--- a/daffodil-test/src/test/resources/org/apache/daffodil/section14/sequence_groups/SequenceGroupDelimiters.tdml
+++ b/daffodil-test/src/test/resources/org/apache/daffodil/section14/sequence_groups/SequenceGroupDelimiters.tdml
@@ -296,8 +296,15 @@
+
+
+ occursCountKind='parsed'
+ must have
+ separatorSuppressionPolicy='anyEmpty'
+ but was never
+
-
+ left over data
diff --git a/daffodil-test/src/test/resources/org/apache/daffodil/usertests/SepTests.tdml b/daffodil-test/src/test/resources/org/apache/daffodil/usertests/SepTests.tdml
index 61d08de6b9..5878e386f6 100644
--- a/daffodil-test/src/test/resources/org/apache/daffodil/usertests/SepTests.tdml
+++ b/daffodil-test/src/test/resources/org/apache/daffodil/usertests/SepTests.tdml
@@ -456,11 +456,11 @@
-
+
-
+
diff --git a/daffodil-test/src/test/scala/org/apache/daffodil/section14/occursCountKind/TestImplicitvParsed.scala b/daffodil-test/src/test/scala/org/apache/daffodil/section14/occursCountKind/TestImplicitvParsed.scala
new file mode 100644
index 0000000000..26a5dc5ba3
--- /dev/null
+++ b/daffodil-test/src/test/scala/org/apache/daffodil/section14/occursCountKind/TestImplicitvParsed.scala
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.daffodil.section14.occursCountKind
+
+import org.apache.daffodil.junit.tdml.TdmlSuite
+import org.apache.daffodil.junit.tdml.TdmlTests
+
+import org.junit.Test
+
+object TestImplicitvParsed extends TdmlSuite {
+ val tdmlResource = "org/apache/daffodil/section14/occursCountKind/implicitvparsed.tdml"
+}
+
+class TestImplicitvParsed extends TdmlTests {
+ val tdmlSuite = TestImplicitvParsed
+
+ @Test def test_array_parsed = test
+ @Test def test_array_implicit = test
+
+}