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 + +}