diff --git a/daffodil-cli/src/test/scala/org/apache/daffodil/cli/cliTest/TestCLIParsing.scala b/daffodil-cli/src/test/scala/org/apache/daffodil/cli/cliTest/TestCLIParsing.scala index 51eb670610..622c92d3ea 100644 --- a/daffodil-cli/src/test/scala/org/apache/daffodil/cli/cliTest/TestCLIParsing.scala +++ b/daffodil-cli/src/test/scala/org/apache/daffodil/cli/cliTest/TestCLIParsing.scala @@ -358,7 +358,7 @@ class TestCLIParsing { runCLI(args"parse -s $schema -r unknown") { cli => cli.sendLine("12", inputDone = true) - cli.expectErr("No root element found for unknown in any available namespace") + cli.expectErr("No root element found for {}unknown") }(ExitCode.UnableToCreateProcessor) } diff --git a/daffodil-cli/src/test/scala/org/apache/daffodil/cli/cliTest/schematron/TestSvrlOutput.scala b/daffodil-cli/src/test/scala/org/apache/daffodil/cli/cliTest/schematron/TestSvrlOutput.scala index b728d47938..1800b1808d 100644 --- a/daffodil-cli/src/test/scala/org/apache/daffodil/cli/cliTest/schematron/TestSvrlOutput.scala +++ b/daffodil-cli/src/test/scala/org/apache/daffodil/cli/cliTest/schematron/TestSvrlOutput.scala @@ -125,7 +125,7 @@ class TestSvrlOutput { runCLI(args"parse --validate schematron=$conf -s $schema -r unknown") { cli => cli.send("12", inputDone = true) - cli.expectErr("No root element found for unknown in any available namespace") + cli.expectErr("No root element found for {}unknown") }(ExitCode.UnableToCreateProcessor) } } diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/SchemaComponent.scala b/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/SchemaComponent.scala index d3d4adaa56..231fda8845 100644 --- a/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/SchemaComponent.scala +++ b/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/SchemaComponent.scala @@ -330,19 +330,31 @@ final class Schema private ( } /** - * Given a name, retrieve the appropriate object. + * Given a qname, retrieve the appropriate object. * * This just scans each schema document in the schema, checking each one. */ - def getGlobalElementDecl(name: String) = { + def getGlobalElementDecl(qname: RefQName): Option[GlobalElementDecl] = { val sds = schemaDocuments val res = sds.flatMap { sd => { - val ged = sd.getGlobalElementDecl(name) + val ged = sd.getGlobalElementDecl(qname) ged } } - noneOrOne(res, name) + noneOrOne(res, qname.toString) + } + + def searchGlobalElementDecl(ncName: String): Seq[GlobalElementDecl] = { + Assert.invariant(!ncName.contains(":")) + val sds = schemaDocuments + val res = sds.flatMap { sd => + { + val ged = sd.searchGlobalElementDecl(ncName) + ged + } + } + res } def getGlobalSimpleTypeDef(name: String) = noneOrOne(schemaDocuments.flatMap { _.getGlobalSimpleTypeDef(name) }, name) diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/SchemaDocument.scala b/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/SchemaDocument.scala index 85f8c4f75d..63675fcb9f 100644 --- a/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/SchemaDocument.scala +++ b/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/SchemaDocument.scala @@ -22,6 +22,7 @@ import scala.xml.Node import org.apache.daffodil.core.dsom.IIUtils.IIMap import org.apache.daffodil.lib.api.WarnID import org.apache.daffodil.lib.exceptions.Assert +import org.apache.daffodil.lib.xml.RefQName import org.apache.daffodil.lib.xml.XMLUtils /** @@ -261,9 +262,16 @@ final class SchemaDocument private (xmlSDoc: XMLSchemaDocument) lazy val defineVariables = annotationObjs.collect { case dv: DFDLDefineVariable => dv } /** - * by name getters for the global things that can be referenced. + * by name/qname getters for the global things that can be referenced. */ - def getGlobalElementDecl(name: String) = globalElementDecls.find { _.name == name } + def getGlobalElementDecl(qname: RefQName): Option[GlobalElementDecl] = + globalElementDecls.find { + _.namedQName.toRefQName == qname + } + def searchGlobalElementDecl(name: String): Seq[GlobalElementDecl] = + globalElementDecls.filter { + _.name == name + } def getGlobalSimpleTypeDef(name: String) = globalSimpleTypeDefs.find { _.name == name } def getGlobalComplexTypeDef(name: String) = globalComplexTypeDefs.find { _.name == name } def getGlobalGroupDef(name: String) = globalGroupDefs.find { _.name == name } diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/SchemaSet.scala b/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/SchemaSet.scala index 792b730ead..71dab86bf4 100644 --- a/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/SchemaSet.scala +++ b/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/SchemaSet.scala @@ -315,19 +315,19 @@ final class SchemaSet private ( * root element name, then this searches for a single element having that name, and if it is * unambiguous, it is used as the root. */ - private def findRootElement(name: String) = { + private def findRootElement(qname: RefQName): GlobalElementDecl = { val candidates = schemas.flatMap { - _.getGlobalElementDecl(name) + _.getGlobalElementDecl(qname) } schemaDefinitionUnless( candidates.length != 0, - "No root element found for %s in any available namespace", - name + "No root element found for %s", + qname ) schemaDefinitionUnless( candidates.length <= 1, "Root element %s is ambiguous. Candidates are %s.", - name, + qname, candidates.map { gef => { val tns = gef.schemaDocument.targetNamespace @@ -356,7 +356,20 @@ final class SchemaSet private ( ge } case RootSpec(None, rootElementName) => { - findRootElement(rootElementName) + val possibleRoots: Seq[GlobalElementDecl] = schemaSet.schemas.flatMap { + _.searchGlobalElementDecl(rootElementName) + } + if (possibleRoots.length == 1) { + possibleRoots.head + } else { + // we're here because it's ambiguous what root element to return, and + // no namespace URI was provided. So we assume not specifying a namespace + // URI may mean the intention was to choose the root that it is in No Namespace. + // If there is no such, then the diagnostic will encourage user to specify + // the namespace explicitly. + val qn = RefQName(None, rootElementName, NoNamespace) + findRootElement(qn) + } } case _ => Assert.impossible() } @@ -412,7 +425,7 @@ final class SchemaSet private ( */ def getGlobalElementDecl(refQName: RefQName): Option[GlobalElementDecl] = { getSchema(refQName.namespace).flatMap { - _.getGlobalElementDecl(refQName.local) + _.getGlobalElementDecl(refQName) } } diff --git a/daffodil-core/src/test/scala/org/apache/daffodil/core/util/TestUtils.scala b/daffodil-core/src/test/scala/org/apache/daffodil/core/util/TestUtils.scala index 39495e1adb..b01fca1630 100644 --- a/daffodil-core/src/test/scala/org/apache/daffodil/core/util/TestUtils.scala +++ b/daffodil-core/src/test/scala/org/apache/daffodil/core/util/TestUtils.scala @@ -386,10 +386,10 @@ class Fakes private () { lazy val xsd_sset: SchemaSet = SchemaSet(sch, "http://example.com", "fake") lazy val xsd_schema = xsd_sset.getSchema(NS("http://example.com")).get lazy val fakeSD = xsd_schema.schemaDocuments(0) - lazy val fakeElem = fakeSD.getGlobalElementDecl("fake").get + lazy val fakeElem = fakeSD.searchGlobalElementDecl("fake").head lazy val fakeCT = - fakeSD.getGlobalElementDecl("fake2").get.typeDef.asInstanceOf[GlobalComplexTypeDef] + fakeSD.searchGlobalElementDecl("fake2").head.typeDef.asInstanceOf[GlobalComplexTypeDef] lazy val fakeSequence = fakeCT.sequence lazy val Seq(fs1, fs2, fs3) = fakeSequence.groupMembers lazy val fakeChoiceGroupRef = fs1.asInstanceOf[ChoiceGroupRef] diff --git a/daffodil-tdml-lib/src/main/scala/org/apache/daffodil/tdml/TDMLRunner.scala b/daffodil-tdml-lib/src/main/scala/org/apache/daffodil/tdml/TDMLRunner.scala index ad25deacf6..3a37895d31 100644 --- a/daffodil-tdml-lib/src/main/scala/org/apache/daffodil/tdml/TDMLRunner.scala +++ b/daffodil-tdml-lib/src/main/scala/org/apache/daffodil/tdml/TDMLRunner.scala @@ -695,12 +695,12 @@ abstract class TestCase(testCaseXML: NodeSeq, val parent: DFDLTestSuite) { } def getRootNamespaceString() = { - if (optExpectedOrInputInfoset.isDefined) + if (this.rootNSAttrib != "") + rootNSAttrib + else if (optExpectedOrInputInfoset.isDefined) infosetRootNamespaceString else if (optEmbeddedSchema.isDefined) XMLUtils.EXAMPLE_NAMESPACE.toString - else if (this.rootNSAttrib != "") - rootNSAttrib else { // For some TDML Processors, we have to provide // the root namespace. They don't provide a way to search diff --git a/daffodil-tdml-processor/src/test/resources/test/tdml/chameleon-schema1.dfdl.xsd b/daffodil-tdml-processor/src/test/resources/test/tdml/chameleon-schema1.dfdl.xsd new file mode 100644 index 0000000000..1ef318e372 --- /dev/null +++ b/daffodil-tdml-processor/src/test/resources/test/tdml/chameleon-schema1.dfdl.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/daffodil-tdml-processor/src/test/resources/test/tdml/generic-schema1.dfdl.xsd b/daffodil-tdml-processor/src/test/resources/test/tdml/generic-schema1.dfdl.xsd new file mode 100644 index 0000000000..7b83031ae5 --- /dev/null +++ b/daffodil-tdml-processor/src/test/resources/test/tdml/generic-schema1.dfdl.xsd @@ -0,0 +1,28 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/daffodil-tdml-processor/src/test/scala/org/apache/daffodil/processor/tdml/TestTDMLRunner2.scala b/daffodil-tdml-processor/src/test/scala/org/apache/daffodil/processor/tdml/TestTDMLRunner2.scala index 691e299249..bbaceeb9f6 100644 --- a/daffodil-tdml-processor/src/test/scala/org/apache/daffodil/processor/tdml/TestTDMLRunner2.scala +++ b/daffodil-tdml-processor/src/test/scala/org/apache/daffodil/processor/tdml/TestTDMLRunner2.scala @@ -608,4 +608,80 @@ abc # a comment @Test def test_apos_test1(): Unit = { runner.runOneTest("apos_test1") } @Test def test_apos_test2(): Unit = { runner.runOneTest("apos_test2") } + // DFDL-2947 + @Test def test_rootNSSpecifiesNoNamespaceRoot(): Unit = { + val tdmlTestSuite = + + + 37 + + + 37 + + + + + + val runner = new Runner(tdmlTestSuite) + runner.runOneTest("test1") + } + + @Test def test_rootNSSpecifiesNamespaceRoot(): Unit = { + val tdmlTestSuite = + + + boy + + + boy + + + + + + val runner = new Runner(tdmlTestSuite) + runner.runOneTest("test1") + } + + @Test def test_noRootCandidates1(): Unit = { + val tdmlTestSuite = + + + 37 + + Schema Definition Error + no root element found + data1 + + + + + val runner = new Runner(tdmlTestSuite) + runner.runOneTest("test1") + } + + @Test def test_noRootCandidates2(): Unit = { + val tdmlTestSuite = + + + 37 + + Schema Definition Error + no global element found + {"{doesNotExist}"}data + + + + + val runner = new Runner(tdmlTestSuite) + runner.runOneTest("test1") + } } diff --git a/daffodil-test/src/test/resources/org/apache/daffodil/section06/namespaces/namespaces.tdml b/daffodil-test/src/test/resources/org/apache/daffodil/section06/namespaces/namespaces.tdml index 47c40bb3ad..2345228cf9 100644 --- a/daffodil-test/src/test/resources/org/apache/daffodil/section06/namespaces/namespaces.tdml +++ b/daffodil-test/src/test/resources/org/apache/daffodil/section06/namespaces/namespaces.tdml @@ -910,7 +910,7 @@ Schema Definition Error - More than one definition for name: vagueEle + More than one definition for name: {}vagueElem