Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Ignored RootNS #1367

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

/**
Expand Down Expand Up @@ -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 }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add some comments explaining the rationale here. E.g.,

It's ambiguous what root element, 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. 

findRootElement(qn)
}
}
case _ => Assert.impossible()
}
Expand Down Expand Up @@ -412,7 +425,7 @@ final class SchemaSet private (
*/
def getGlobalElementDecl(refQName: RefQName): Option[GlobalElementDecl] = {
getSchema(refQName.namespace).flatMap {
_.getGlobalElementDecl(refQName.local)
_.getGlobalElementDecl(refQName)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:dfdl="http://www.ogf.org/dfdl/dfdl-1.0/">
<xs:include schemaLocation="/org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd"/>
<xs:import namespace="urn:schema:namespace" schemaLocation="/test/tdml/generic-schema1.dfdl.xsd"/>

<xs:annotation>
<xs:appinfo source="http://www.ogf.org/dfdl/">
<dfdl:format ref="GeneralFormat"/>
</xs:appinfo>
</xs:annotation>

<xs:element name="data" type="xs:int" dfdl:lengthKind="explicit" dfdl:length="{ 2 }"/>
</xs:schema>
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<xs:schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:ex="http://example.com" xmlns:s="urn:schema:namespace" targetNamespace="urn:schema:namespace" xmlns:dfdl="http://www.ogf.org/dfdl/dfdl-1.0/">
<xs:include schemaLocation="/org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd"/>
<xs:annotation>
<xs:appinfo source="http://www.ogf.org/dfdl/">
<dfdl:format ref="s:GeneralFormat"/>
</xs:appinfo>
</xs:annotation>

<xs:element name="data" type="xs:string" dfdl:lengthKind="explicit" dfdl:length="{ 3 }"/>
</xs:schema>
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
<tdml:testSuite suiteName="theSuiteName" xmlns:ex={example} xmlns:tdml={tdml} xmlns:dfdl={
dfdl
} xmlns:xsd={xsd} xmlns:xs={xsd} xmlns:xsi={xsi}>
<tdml:parserTestCase name="test1" root="data" rootNS="" model="/test/tdml/chameleon-schema1.dfdl.xsd">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe rename test to reflect that rootNS is being used to specify no namespace. It's not only multiple root candidates but that one of them is no namespace, and this illustrates how to specify that.

<tdml:document>37</tdml:document>
<tdml:infoset>
<tdml:dfdlInfoset>
<data>37</data>
</tdml:dfdlInfoset>
</tdml:infoset>
</tdml:parserTestCase>
</tdml:testSuite>

val runner = new Runner(tdmlTestSuite)
runner.runOneTest("test1")
}

@Test def test_rootNSSpecifiesNamespaceRoot(): Unit = {
val tdmlTestSuite =
<tdml:testSuite suiteName="theSuiteName" xmlns:ex={example} xmlns:tdml={tdml} xmlns:dfdl={
dfdl
} xmlns:xsd={xsd} xmlns:xs={xsd} xmlns:xsi={xsi}>
<tdml:parserTestCase name="test1" root="data" rootNS="urn:schema:namespace" model="/test/tdml/chameleon-schema1.dfdl.xsd">
<tdml:document>boy</tdml:document>
<tdml:infoset>
<tdml:dfdlInfoset>
<data>boy</data>
</tdml:dfdlInfoset>
</tdml:infoset>
</tdml:parserTestCase>
</tdml:testSuite>

val runner = new Runner(tdmlTestSuite)
runner.runOneTest("test1")
}

@Test def test_noRootCandidates1(): Unit = {
val tdmlTestSuite =
<tdml:testSuite suiteName="theSuiteName" xmlns:ex={example} xmlns:tdml={tdml} xmlns:dfdl={
dfdl
} xmlns:xsd={xsd} xmlns:xs={xsd} xmlns:xsi={xsi}>
<tdml:parserTestCase name="test1" root="data1" model="/test/tdml/chameleon-schema1.dfdl.xsd">
<tdml:document>37</tdml:document>
<tdml:errors>
<tdml:error>Schema Definition Error</tdml:error>
<tdml:error>no root element found</tdml:error>
<tdml:error>data1</tdml:error>
</tdml:errors>
</tdml:parserTestCase>
</tdml:testSuite>

val runner = new Runner(tdmlTestSuite)
runner.runOneTest("test1")
}

@Test def test_noRootCandidates2(): Unit = {
val tdmlTestSuite =
<tdml:testSuite suiteName="theSuiteName" xmlns:ex={example} xmlns:tdml={tdml} xmlns:dfdl={
dfdl
} xmlns:xsd={xsd} xmlns:xs={xsd} xmlns:xsi={xsi}>
<tdml:parserTestCase name="test1" root="data" rootNS="doesNotExist" model="/test/tdml/chameleon-schema1.dfdl.xsd">
<tdml:document>37</tdml:document>
<tdml:errors>
<tdml:error>Schema Definition Error</tdml:error>
<tdml:error>no global element found</tdml:error>
<tdml:error>{"{doesNotExist}"}data</tdml:error>
</tdml:errors>
</tdml:parserTestCase>
</tdml:testSuite>

val runner = new Runner(tdmlTestSuite)
runner.runOneTest("test1")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -910,7 +910,7 @@
<tdml:document><![CDATA[333]]></tdml:document>
<tdml:errors>
<tdml:error>Schema Definition Error</tdml:error>
<tdml:error>More than one definition for name: vagueEle</tdml:error>
<tdml:error>More than one definition for name: {}vagueElem</tdml:error>
</tdml:errors>
</tdml:parserTestCase>

Expand Down
Loading