You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@daffodil.apache.org by "Thompson, Dave" <dt...@owlcyberdefense.com> on 2021/04/29 16:03:52 UTC
RE: [daffodil] branch master updated: Feature Aware
DaffodilParseXMLReader and Prefixes Fixes
Lola,
You updated DAFFODIL-2422 and DAFFODIL-2457 To resolved but didn't update the Fix Version.
Could you please update the Fix Versions for those tickets to 3.1.0.
Thanks,
Dave
-----Original Message-----
From: olabusayo@apache.org
Sent: Wednesday, April 28, 2021 1:50 PM
To: commits@daffodil.apache.org
Subject: [daffodil] branch master updated: Feature Aware DaffodilParseXMLReader and Prefixes Fixes
This is an automated email from the ASF dual-hosted git repository.
olabusayo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/daffodil.git
The following commit(s) were added to refs/heads/master by this push:
new fce9316 Feature Aware DaffodilParseXMLReader and Prefixes Fixes
fce9316 is described below
commit fce93164c2dd453da2d10dc9b3f684d61244c0b6
Author: olabusayoT <50...@users.noreply.github.com>
AuthorDate: Fri Jan 8 16:00:46 2021 -0500
Feature Aware DaffodilParseXMLReader and Prefixes Fixes
- Makes XMLReader and OutputStream content handler aware of/handle appropriately the namespaces and namespace-prefixes features
- More uniform handling of Attributes object in relation to attributes and prefixMappings
- forces prefixMapping to be in the same order as the input, otherwise it gets reversed, affecting the output of getPrefix
- adds functions to do getURI and getPrefix without nullpointerexceptions
- adds prefix function in ERD to do lookup of namedQName.namespace in erd.minimizedScope
- Replaces instances of prefixOrNull with a lookup using the current namespace, as well as the namespacebinding (either MinimizedScope or ElementBase.namespaces)
- Removes prefixOrNull
- Fixes XMLDifferenceException to include a non-stripped version of expected, if checkNamespaces/checkPrefixes is true
- updates feature checks to be before every parse and made them read-only during a parse
- adds scaladoc to test methods and updated API documentation
- updates error message for features
- changes != to ne for namespaceBindings
- refactors SAX module tests to move common functionality into Utils class
- adds tests for false/false, false/true, true/true, and true/false (default)
- adds xsi:nil namespace tests
- adds trace tests for DaffodilParseXMLReader to ensure it was correctly generating the expected events depending on the features sent it
DAFFODIL-2422 DAFFODIL-2457
---
.../org/apache/daffodil/dsom/ElementBase.scala | 2 +-
...xample_a02_targetnamespace_unqualified.dfdl.xsd | 48 ++
.../example_c02_targetnamespace_qualified.dfdl.xsd | 57 +++
.../example_nested_namespaces_qualified.dfdl.xsd | 71 +++
...sted_namespaces_qualified_with_default.dfdl.xsd | 69 +++
.../example_nested_namespaces_unqualified.dfdl.xsd | 67 +++
.../test/example_no_targetnamespace.dfdl.xsd | 54 +++
.../daffodil/processor/TestSAXParseAPI.scala | 515 +++++++++++++++++++--
.../processor/TestSAXParseUnparseAPI.scala | 103 ++---
.../daffodil/processor/TestSAXUnparseAPI.scala | 14 +-
.../apache/daffodil/processor/TestSAXUtils.scala | 356 ++++++++++++++
.../org/apache/daffodil/japi/package-info.java | 5 +
.../org/apache/daffodil/example/TestJavaAPI.java | 3 +
.../scala/org/apache/daffodil/xml/QNameBase.scala | 1 -
.../scala/org/apache/daffodil/xml/XMLUtils.scala | 63 ++-
.../daffodil/infoset/JDOMInfosetOutputter.scala | 2 +-
.../daffodil/infoset/SAXInfosetOutputter.scala | 117 +++--
.../infoset/ScalaXMLInfosetOutputter.scala | 4 +-
.../daffodil/infoset/XMLTextInfosetOutputter.scala | 2 +-
.../DaffodilParseOutputStreamContentHandler.scala | 177 ++++++-
.../processors/DaffodilParseXMLReader.scala | 83 ++--
.../apache/daffodil/processors/RuntimeData.scala | 6 +-
.../scala/org/apache/daffodil/sapi/package.scala | 5 +
.../org/apache/daffodil/example/TestScalaAPI.scala | 3 +
.../daffodil/tdml/TDMLInfosetOutputter.scala | 2 +
.../tdml/processor/DaffodilTDMLDFDLProcessor.scala | 12 +-
26 files changed, 1629 insertions(+), 212 deletions(-)
diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ElementBase.scala b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ElementBase.scala
index 90d4c29..3bc515e 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ElementBase.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ElementBase.scala
@@ -203,7 +203,7 @@ trait ElementBase
val childrenRequiredNSBindings =
this.elementChildren.flatMap { _.thisElementsRequiredNamespaceBindings }.toSet
- val myRequiredNSBinding = Set((namedQName.prefixOrNull, namedQName.namespace))
+ val myRequiredNSBinding = Set((this.namespaces.getPrefix(namedQName.namespace), namedQName.namespace))
val nilNSBinding = {
if (!isNillable) Set()
else {
diff --git a/daffodil-core/src/test/resources/test/example_a02_targetnamespace_unqualified.dfdl.xsd b/daffodil-core/src/test/resources/test/example_a02_targetnamespace_unqualified.dfdl.xsd
new file mode 100644
index 0000000..1e6b980
--- /dev/null
+++ b/daffodil-core/src/test/resources/test/example_a02_targetnamespace_unqualified.dfdl.xsd
@@ -0,0 +1,48 @@
+<?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 targetNamespace="http://a02.com"
+ 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:annotation>
+ <xs:appinfo source="http://www.ogf.org/dfdl/">
+ <dfdl:format ref="GeneralFormat"
+ separator=""
+ initiator=""
+ separatorPosition="infix"
+ ignoreCase="no"
+ separatorSuppressionPolicy="anyEmpty"
+ terminator=""
+ occursCountKind="parsed"
+ initiatedContent="no"
+ representation="text"
+ textNumberRep="standard"
+ encoding="ASCII"
+ textTrimKind="none"
+ leadingSkip='0'/>
+ </xs:appinfo>
+ </xs:annotation>
+
+ <xs:element name="inty" type="xs:int" dfdl:lengthKind="delimited"/>
+ <xs:element name="intx" type="xs:int" nillable="true" dfdl:nilKind="literalValue" dfdl:nilValue="^"/>
+
+
+</xs:schema>
diff --git a/daffodil-core/src/test/resources/test/example_c02_targetnamespace_qualified.dfdl.xsd b/daffodil-core/src/test/resources/test/example_c02_targetnamespace_qualified.dfdl.xsd
new file mode 100644
index 0000000..b3de514
--- /dev/null
+++ b/daffodil-core/src/test/resources/test/example_c02_targetnamespace_qualified.dfdl.xsd
@@ -0,0 +1,57 @@
+<?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 targetNamespace="http://c02.com"
+ xmlns="http://c02.com"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:dfdl="http://www.ogf.org/dfdl/dfdl-1.0/"
+ elementFormDefault="qualified">
+
+ <xs:include schemaLocation="org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd"/>
+
+ <xs:annotation>
+ <xs:appinfo source="http://www.ogf.org/dfdl/">
+ <dfdl:format ref="GeneralFormat"
+ separator=""
+ initiator=""
+ separatorPosition="infix"
+ ignoreCase="no"
+ separatorSuppressionPolicy="anyEmpty"
+ terminator=""
+ occursCountKind="parsed"
+ initiatedContent="no"
+ representation="text"
+ textNumberRep="standard"
+ encoding="ASCII"
+ textTrimKind="none"
+ leadingSkip='0'/>
+ </xs:appinfo>
+ </xs:annotation>
+
+ <xs:element name="c">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="d" type="xs:string" dfdl:lengthKind="pattern" dfdl:lengthPattern="[A-Za-z^]{1,5}"
+ nillable="true" dfdl:nilKind="literalValue" dfdl:nilValue="^"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+
+
+</xs:schema>
diff --git a/daffodil-core/src/test/resources/test/example_nested_namespaces_qualified.dfdl.xsd b/daffodil-core/src/test/resources/test/example_nested_namespaces_qualified.dfdl.xsd
new file mode 100644
index 0000000..9ea4952
--- /dev/null
+++ b/daffodil-core/src/test/resources/test/example_nested_namespaces_qualified.dfdl.xsd
@@ -0,0 +1,71 @@
+<?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 targetNamespace="http://b02.com"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:dfdl="http://www.ogf.org/dfdl/dfdl-1.0/"
+ xmlns:a02="http://a02.com"
+ xmlns:b02="http://b02.com"
+ elementFormDefault="qualified">
+
+ <xs:include schemaLocation="org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd"/>
+
+ <xs:annotation>
+ <xs:appinfo source="http://www.ogf.org/dfdl/">
+ <dfdl:format ref="b02:GeneralFormat"
+ separator="."
+ lengthKind="delimited"
+ ignoreCase="no"
+ separatorPosition="infix"
+ separatorSuppressionPolicy="anyEmpty"
+ leadingSkip='0'
+ initiator=""
+ terminator=""
+ occursCountKind="parsed"
+ initiatedContent="no"
+ representation="text"
+ textNumberRep="standard"
+ encoding="ASCII"
+ textTrimKind="none"
+ alignment="implicit"
+ alignmentUnits="bytes"
+ trailingSkip="0"/>
+ </xs:appinfo>
+ </xs:annotation>
+
+ <xs:include schemaLocation="/test/example_no_targetnamespace.dfdl.xsd"/>
+ <xs:import namespace="http://a02.com" schemaLocation="/test/example_a02_targetnamespace_unqualified.dfdl.xsd"/>
+
+ <xs:element name="seq">
+ <xs:complexType>
+ <xs:sequence dfdl:separator=".">
+ <xs:element name="seq2" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:choice dfdl:choiceLengthKind="implicit">
+ <xs:element ref="a02:inty" dfdl:initiator="-" />
+ <xs:element ref="b02:inty" dfdl:initiator="*"/>
+ <xs:element ref="a02:intx"/>
+ </xs:choice>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+
+</xs:schema>
diff --git a/daffodil-core/src/test/resources/test/example_nested_namespaces_qualified_with_default.dfdl.xsd b/daffodil-core/src/test/resources/test/example_nested_namespaces_qualified_with_default.dfdl.xsd
new file mode 100644
index 0000000..8829d98
--- /dev/null
+++ b/daffodil-core/src/test/resources/test/example_nested_namespaces_qualified_with_default.dfdl.xsd
@@ -0,0 +1,69 @@
+<?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 targetNamespace="http://b02.com"
+ xmlns="http://b02.com"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:dfdl="http://www.ogf.org/dfdl/dfdl-1.0/"
+ xmlns:c02="http://c02.com"
+ xmlns:b02="http://b02.com"
+ elementFormDefault="qualified">
+
+ <xs:include schemaLocation="org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd"/>
+
+ <xs:annotation>
+ <xs:appinfo source="http://www.ogf.org/dfdl/">
+ <dfdl:format ref="b02:GeneralFormat"
+ separator="."
+ lengthKind="delimited"
+ ignoreCase="no"
+ separatorPosition="infix"
+ separatorSuppressionPolicy="anyEmpty"
+ leadingSkip='0'
+ initiator=""
+ terminator=""
+ occursCountKind="parsed"
+ initiatedContent="no"
+ representation="text"
+ textNumberRep="standard"
+ encoding="ASCII"
+ textTrimKind="none"
+ alignment="implicit"
+ alignmentUnits="bytes"
+ trailingSkip="0"/>
+ </xs:appinfo>
+ </xs:annotation>
+
+ <xs:import namespace="http://c02.com" schemaLocation="/test/example_c02_targetnamespace_qualified.dfdl.xsd"/>
+
+ <xs:element name="a">
+ <xs:complexType>
+ <xs:sequence dfdl:separator=".">
+ <xs:element name="b" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element ref="c02:c"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+
+</xs:schema>
diff --git a/daffodil-core/src/test/resources/test/example_nested_namespaces_unqualified.dfdl.xsd b/daffodil-core/src/test/resources/test/example_nested_namespaces_unqualified.dfdl.xsd
new file mode 100644
index 0000000..2595695
--- /dev/null
+++ b/daffodil-core/src/test/resources/test/example_nested_namespaces_unqualified.dfdl.xsd
@@ -0,0 +1,67 @@
+<?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 targetNamespace="http://b02.com"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:dfdl="http://www.ogf.org/dfdl/dfdl-1.0/"
+ xmlns:c02="http://c02.com"
+ xmlns:b02="http://b02.com">
+
+ <xs:include schemaLocation="org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd"/>
+
+ <xs:annotation>
+ <xs:appinfo source="http://www.ogf.org/dfdl/">
+ <dfdl:format ref="b02:GeneralFormat"
+ separator="."
+ lengthKind="delimited"
+ ignoreCase="no"
+ separatorPosition="infix"
+ separatorSuppressionPolicy="anyEmpty"
+ leadingSkip='0'
+ initiator=""
+ terminator=""
+ occursCountKind="parsed"
+ initiatedContent="no"
+ representation="text"
+ textNumberRep="standard"
+ encoding="ASCII"
+ textTrimKind="none"
+ alignment="implicit"
+ alignmentUnits="bytes"
+ trailingSkip="0"/>
+ </xs:appinfo>
+ </xs:annotation>
+
+ <xs:import namespace="http://c02.com" schemaLocation="/test/example_c02_targetnamespace_qualified.dfdl.xsd"/>
+
+ <xs:element name="a">
+ <xs:complexType>
+ <xs:sequence dfdl:separator=".">
+ <xs:element name="b" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element ref="c02:c"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+
+</xs:schema>
diff --git a/daffodil-core/src/test/resources/test/example_no_targetnamespace.dfdl.xsd b/daffodil-core/src/test/resources/test/example_no_targetnamespace.dfdl.xsd
new file mode 100644
index 0000000..d43916d
--- /dev/null
+++ b/daffodil-core/src/test/resources/test/example_no_targetnamespace.dfdl.xsd
@@ -0,0 +1,54 @@
+<?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.
+-->
+<!-- copied from multi_C_02.dfdl.xsd since daffodil-test is not a test dependency,
+ but daffodil-core is a dependency for daffodil-test; as this is just 1 file,
+ we decided to copy it instead of trying to go the dependency route-->
+<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:annotation>
+ <xs:appinfo source="http://www.ogf.org/dfdl/">
+ <dfdl:format ref="GeneralFormat"
+ separator=""
+ initiator=""
+ separatorPosition="infix"
+ ignoreCase="no"
+ separatorSuppressionPolicy="anyEmpty"
+ terminator=""
+ occursCountKind="parsed"
+ initiatedContent="no"
+ representation="text"
+ textNumberRep="standard"
+ encoding="ASCII"
+ textTrimKind="none"
+ leadingSkip='0'/>
+ </xs:appinfo>
+ </xs:annotation>
+
+ <xs:element name="x">
+ <xs:complexType>
+ <xs:sequence dfdl:separator=".">
+ <xs:element name="y" type="xs:string" dfdl:lengthKind="pattern" dfdl:lengthPattern="[A-Za-z^]{1,5}"
+ nillable="true" dfdl:nilKind="literalValue" dfdl:nilValue="^" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="inty" type="xs:int" dfdl:lengthKind="delimited"/>
+
+</xs:schema>
diff --git a/daffodil-core/src/test/scala/org/apache/daffodil/processor/TestSAXParseAPI.scala b/daffodil-core/src/test/scala/org/apache/daffodil/processor/TestSAXParseAPI.scala
index 2e15aa0..a3aba83 100644
--- a/daffodil-core/src/test/scala/org/apache/daffodil/processor/TestSAXParseAPI.scala
+++ b/daffodil-core/src/test/scala/org/apache/daffodil/processor/TestSAXParseAPI.scala
@@ -24,6 +24,7 @@ import java.io.IOException
import scala.xml.SAXParseException
import org.apache.daffodil.Implicits.intercept
+import org.apache.daffodil.api.DFDL
import org.apache.daffodil.processors.DaffodilParseOutputStreamContentHandler
import org.apache.daffodil.processors.ParseResult
import org.apache.daffodil.xml.XMLUtils
@@ -40,9 +41,12 @@ import org.xml.sax.SAXNotRecognizedException
import org.xml.sax.SAXNotSupportedException
class TestSAXParseAPI {
- import TestSAXParseUnparseAPI._
+ import TestSAXUtils._
- @Test def testDaffodilParseXMLReader_setFeatureUnsupported(): Unit = {
+ /**
+ * tests the case where we attempt to set an unsupported feature
+ */
+ @Test def testDaffodilParseXMLReader_setFeature_unsupported(): Unit = {
val xmlReader = dp.newXMLReaderInstance
val snr = intercept[SAXNotRecognizedException] {
xmlReader.setFeature("http://xml.org/sax/features/validation", true)
@@ -51,9 +55,24 @@ class TestSAXParseAPI {
assertTrue(snr.getMessage.contains("Supported features are:"))
}
+ /**
+ * tests the case where we attempt to get an unsupported feature
+ */
+ @Test def testDaffodilParseXMLReader_getFeature_unsupported(): Unit = {
+ val xmlReader = dp.newXMLReaderInstance
+ val snr = intercept[SAXNotRecognizedException] {
+ xmlReader.getFeature("http://xml.org/sax/features/validation")
+ }
+ assertTrue(snr.getMessage.contains("Feature unsupported"))
+ assertTrue(snr.getMessage.contains("Supported features are:"))
+ }
+
+ /**
+ * tests that we can set and get a supported feature
+ */
@Test def testDaffodilParseXMLReader_get_setFeature(): Unit = {
val xmlReader = dp.newXMLReaderInstance
- val feature = "http://xml.org/sax/features/namespace-prefixes"
+ val feature = XMLUtils.SAX_NAMESPACE_PREFIXES_FEATURE
val origValue = xmlReader.getFeature(feature)
assertFalse(origValue)
xmlReader.setFeature(feature, true)
@@ -61,6 +80,27 @@ class TestSAXParseAPI {
assertTrue(newValue)
}
+ /*
+ * tests the case where both supported features are set to false, as it is an illegal state
+ */
+ @Test def testDaffodilParseXMLReader_supportedFeaturesNotFalse(): Unit = {
+ val xmlReader = dp.newXMLReaderInstance
+ val baos = new ByteArrayOutputStream()
+ val parseOutputStreamContentHandler = new DaffodilParseOutputStreamContentHandler(baos)
+ xmlReader.setFeature(XMLUtils.SAX_NAMESPACES_FEATURE, false)
+ xmlReader.setFeature(XMLUtils.SAX_NAMESPACE_PREFIXES_FEATURE, false)
+ xmlReader.setContentHandler(parseOutputStreamContentHandler)
+ val inArray = testData.getBytes()
+ val snr = intercept[org.xml.sax.SAXException] {
+ xmlReader.parse(inArray)
+ }
+ assertTrue(snr.getMessage.contains("Namespaces and NamespacePrefixes"))
+ assertTrue(snr.getMessage.contains("cannot both be false"))
+ }
+
+ /**
+ * tests the case where we attempt to set an unsupported property
+ */
@Test def testDaffodilParseXMLReader_setProperty_unsupported(): Unit = {
val xmlReader = dp.newXMLReaderInstance
val property: AnyRef = "Hello"
@@ -70,6 +110,20 @@ class TestSAXParseAPI {
assertTrue(snr.getMessage.contains("Property unsupported"))
}
+ /**
+ * tests the case where we attempt to get an unsupported property
+ */
+ @Test def testDaffodilParseXMLReader_getProperty_unsupported(): Unit = {
+ val xmlReader = dp.newXMLReaderInstance
+ val snr = intercept[SAXNotRecognizedException] {
+ xmlReader.getProperty("http://xml.org/sax/properties/xml-string")
+ }
+ assertTrue(snr.getMessage.contains("Property unsupported"))
+ }
+
+ /**
+ * tests the case where we attempt to set an invalid value for a supported property
+ */
@Test def testDaffodilParseXMLReader_setProperty_badValue(): Unit = {
val xmlReader = dp.newXMLReaderInstance
val property: String = XMLUtils.DAFFODIL_SAX_URN_BLOBDIRECTORY
@@ -80,6 +134,9 @@ class TestSAXParseAPI {
assertTrue(sns.getMessage.contains("Unsupported value for property"))
}
+ /**
+ * tests that we can set and get a supported property
+ */
@Test def testDaffodilParseXMLReader_get_setProperty(): Unit = {
val xmlReader = dp.newXMLReaderInstance
val property: String = XMLUtils.DAFFODIL_SAX_URN_BLOBPREFIX
@@ -91,6 +148,9 @@ class TestSAXParseAPI {
assertEquals(propertyVal, newValue.asInstanceOf[String])
}
+ /**
+ * test that we can get and set a contentHandler
+ */
@Test def testDaffodilParseXMLReader_get_setContentHandler(): Unit = {
val xmlReader = dp.newXMLReaderInstance
val parseContentHandler = new SAXHandler()
@@ -101,6 +161,9 @@ class TestSAXParseAPI {
assertTrue(newValue.isInstanceOf[SAXHandler])
}
+ /**
+ * test that we can get and set a errorHandler
+ */
@Test def testDaffodilParseXMLReader_get_setErrorHandler(): Unit = {
val xmlReader = dp.newXMLReaderInstance
val eh = new BuilderErrorHandler()
@@ -111,6 +174,9 @@ class TestSAXParseAPI {
assertTrue(newValue.isInstanceOf[BuilderErrorHandler])
}
+ /**
+ * tests that an exception occurs if we try to parse an inputSource with no backing inputStream
+ */
@Test def testDaffodilParseXMLReader_parse_inputSource_no_backing_stream(): Unit = {
val xmlReader = dp.newXMLReaderInstance
val input = new InputSource()
@@ -120,53 +186,59 @@ class TestSAXParseAPI {
assertTrue(ioe.getMessage.contains("InputSource must be backed by InputStream"))
}
+ /**
+ * tests that we can parse using an inputSource with a backing inputStream
+ */
@Test def testDaffodilParseXMLReader_parse_inputSource_with_backing_stream(): Unit = {
- val xmlReader = dp.newXMLReaderInstance
- val baos = new ByteArrayOutputStream()
- val parseOutputStreamContentHandler = new DaffodilParseOutputStreamContentHandler(baos)
- xmlReader.setContentHandler(parseOutputStreamContentHandler)
- val inArray = testData.getBytes()
+ val (xmlReader: DFDL.DaffodilParseXMLReader,
+ baos: ByteArrayOutputStream,
+ inArray: Array[Byte]) = setupSAXParserTest(dp, testData)
val bais = new ByteArrayInputStream(inArray)
val input = new InputSource(bais)
xmlReader.parse(input)
val pr = xmlReader.getProperty(XMLUtils.DAFFODIL_SAX_URN_PARSERESULT).asInstanceOf[ParseResult]
+ val actualInfoset = scala.xml.XML.loadString(baos.toString)
assertTrue(!pr.isError)
- assertEquals(testInfoset, scala.xml.XML.loadString(baos.toString))
+ assertEquals(expectedInfoset, actualInfoset)
}
+ /**
+ * tests that we can parse using an inputStream
+ */
@Test def testDaffodilParseXMLReader_parse_inputStream(): Unit = {
- val xmlReader = dp.newXMLReaderInstance
- val baos = new ByteArrayOutputStream()
- val parseOutputStreamContentHandler = new DaffodilParseOutputStreamContentHandler(baos)
- xmlReader.setContentHandler(parseOutputStreamContentHandler)
- val inArray = testData.getBytes()
+ val (xmlReader: DFDL.DaffodilParseXMLReader,
+ baos: ByteArrayOutputStream,
+ inArray: Array[Byte]) = setupSAXParserTest(dp, testData)
val bais = new ByteArrayInputStream(inArray)
xmlReader.parse(bais)
val pr = xmlReader.getProperty(XMLUtils.DAFFODIL_SAX_URN_PARSERESULT).asInstanceOf[ParseResult]
+ val actualInfoset = scala.xml.XML.loadString(baos.toString)
assertTrue(!pr.isError)
- assertEquals(testInfoset, scala.xml.XML.loadString(baos.toString))
+ assertEquals(expectedInfoset, actualInfoset)
}
+ /**
+ * tests that we can parse using a byte array
+ */
@Test def testDaffodilParseXMLReader_parse_byteArray(): Unit = {
- val xmlReader = dp.newXMLReaderInstance
- val baos = new ByteArrayOutputStream()
- val parseOutputStreamContentHandler = new DaffodilParseOutputStreamContentHandler(baos)
- xmlReader.setContentHandler(parseOutputStreamContentHandler)
- val inArray = testData.getBytes()
+ val (xmlReader: DFDL.DaffodilParseXMLReader,
+ baos: ByteArrayOutputStream,
+ inArray: Array[Byte]) = setupSAXParserTest(dp, testData)
xmlReader.parse(inArray)
+ val actualInfoset = scala.xml.XML.loadString(baos.toString)
val pr = xmlReader.getProperty(XMLUtils.DAFFODIL_SAX_URN_PARSERESULT).asInstanceOf[ParseResult]
assertTrue(!pr.isError)
- assertEquals(testInfoset, scala.xml.XML.loadString(baos.toString))
+ assertEquals(expectedInfoset, actualInfoset)
}
+ /**
+ * tests that the error handler is populated if we try to parse an empty input
+ */
@Test def testDaffodilParseXMLReader_parse_errorHandler_empty_byteArray(): Unit = {
- val xmlReader = dp.newXMLReaderInstance
- val baos = new ByteArrayOutputStream()
- val parseOutputStreamContentHandler = new DaffodilParseOutputStreamContentHandler(baos)
- xmlReader.setContentHandler(parseOutputStreamContentHandler)
+ val (xmlReader: DFDL.DaffodilParseXMLReader, _, inArray: Array[Byte]) =
+ setupSAXParserTest(dp, "")
val eh = new BuilderErrorHandler
xmlReader.setErrorHandler(eh)
- val inArray = "".getBytes()
val spe = intercept[SAXParseException](
xmlReader.parse(inArray)
)
@@ -174,4 +246,395 @@ class TestSAXParseAPI {
assertTrue(pr.isError)
assertTrue(spe.getMessage.contains("Insufficient bits in data"))
}
+
+ /*
+ * tests that the output from the parser is as expected, when the namespaces feature is set
+ * to false and the namespace prefix feature is set to true, for a data that generates an infoset
+ * with nested elements from different namespaces, including nil elements
+ */
+ @Test def testDaffodilParseXMLReader_parse_features_prefixes_only1(): Unit = {
+ val (pr, actualInfoset) = saxParseWithFeatures(dpQualifiedWithNestedSchemas, qualifiedWithNestedSchemasData,
+ namespaces = false, namespacePrefixes = true)
+ assertTrue(!pr.isError)
+ assertEquals(qualifiedWithNestedSchemasExpectedInfoset, actualInfoset)
+ }
+
+ /*
+ * tests that the output from the parser is as expected, when the namespaces feature is set
+ * to false and the namespace prefix feature is set to true, qnames are populated for elements,
+ * but there not uris and localnames; attributes contain prefix mappings where the qname has the
+ * xmlns* and the value contains the associated uri. Regular elements are also provided by attributes
+ */
+ @Test def testDaffodilParseXMLReader_parse_features_prefixes_only2(): Unit = {
+ val (pr, actualInfoset) = saxParseWithFeatures(dpUnqualifiedNoNamespaces, unqualifiedNoNamespacesData,
+ namespaces = false, namespacePrefixes = true)
+ assertTrue(!pr.isError)
+ assertEquals(unqualifiedNoNamespacesExpectedInfoset, actualInfoset)
+ }
+
+ /*
+ * tests that the output from the parser is as expected, when the namespaces feature is set
+ * to false and the namespace prefix feature is set to true., for data that generates an infoset
+ * with nested elements
+ */
+ @Test def testDaffodilParseXMLReader_parse_features_prefixes_only3(): Unit = {
+ val (pr, actualInfoset) = saxParseWithFeatures(dpUnqualifiedWithNestedQualified, unqualifiedWithNestedQualifiedData,
+ namespaces = false, namespacePrefixes = true)
+ assertTrue(!pr.isError)
+ assertEquals(unqualifiedWithNestedQualifiedExpectedInfoset, actualInfoset)
+ }
+
+ /*
+ * tests that the output from the parser is as expected, when the namespaces feature is set
+ * to false and the namespace prefix feature is set to true.
+ */
+ @Test def testDaffodilParseXMLReader_parse_features_prefixes_only4(): Unit = {
+ val (pr, actualInfoset) = saxParseWithFeatures(dpQualifiedWithDefaultNamespaceSchemas, qualifiedWithDefaultNamespaceData,
+ namespaces = false, namespacePrefixes = true)
+ assertTrue(!pr.isError)
+ assertEquals(qualifiedWithDefaultNamespaceExpectedInfoset, actualInfoset)
+ }
+
+ /*
+ * tests that the output from the parser is as expected, when the namespaces feature is set
+ * to false and the namespace prefix feature is set to true.
+ */
+ @Test def testDaffodilParseXMLReader_parse_features_prefixes_only5(): Unit = {
+ val (pr, actualInfoset) = saxParseWithFeatures(dpQualifiedWithDefaultAndNestedSchemas, qualifiedWithDefaultAndNestedSchemasData,
+ namespaces = false, namespacePrefixes = true)
+ assertTrue(!pr.isError)
+ assertEquals(qualifiedWithDefaultAndNestedSchemasExpectedInfoset, actualInfoset)
+ }
+
+ /*
+ * tests that the output from the parser is as expected, when the namespaces feature is set
+ * to true and the namespace prefix false is set to false.
+ */
+ @Test def testDaffodilParseXMLReader_parse_features_namespace_only1(): Unit = {
+ val (pr, actualInfoset) = saxParseWithFeatures(dpQualifiedWithNestedSchemas, qualifiedWithNestedSchemasData,
+ namespaces = true, namespacePrefixes = false)
+ assertTrue(!pr.isError)
+ assertEquals(qualifiedWithNestedSchemasExpectedInfoset, actualInfoset)
+ }
+
+ /*
+ * tests that the output from the parser is as expected, when the namespaces feature is set
+ * to true and the namespace prefix is set to false.
+ */
+ @Test def testDaffodilParseXMLReader_parse_features_namespace_only2(): Unit = {
+ val (pr, actualInfoset) = saxParseWithFeatures(dpUnqualifiedNoNamespaces, unqualifiedNoNamespacesData,
+ namespaces = true, namespacePrefixes = false
+ )
+ assertTrue(!pr.isError)
+ assertEquals(unqualifiedNoNamespacesExpectedInfoset, actualInfoset)
+ }
+
+ /*
+ * tests that the output from the parser is as expected, when the namespaces feature is set
+ * to true and the namespace prefix false is set to false.
+ */
+ @Test def testDaffodilParseXMLReader_parse_features_namespace_only3(): Unit = {
+ val (pr, actualInfoset) = saxParseWithFeatures(dpUnqualifiedWithNestedQualified, unqualifiedWithNestedQualifiedData,
+ namespaces = true, namespacePrefixes = false)
+ assertTrue(!pr.isError)
+ assertEquals(unqualifiedWithNestedQualifiedExpectedInfoset, actualInfoset)
+ }
+
+ /*
+ * tests that the output from the parser is as expected, when the namespaces feature is set
+ * to true and the namespace prefix false is set to false.
+ */
+ @Test def testDaffodilParseXMLReader_parse_features_namespace_only4(): Unit = {
+ val (pr, actualInfoset) = saxParseWithFeatures(dpQualifiedWithDefaultNamespaceSchemas, qualifiedWithDefaultNamespaceData,
+ namespaces = true, namespacePrefixes = false)
+ assertTrue(!pr.isError)
+ assertEquals(qualifiedWithDefaultNamespaceExpectedInfoset, actualInfoset)
+ }
+
+ /*
+ * tests that the output from the parser is as expected, when the namespaces feature is set
+ * to true and the namespace prefix false is set to false.
+ */
+ @Test def testDaffodilParseXMLReader_parse_features_namespace_only5(): Unit = {
+ val (pr, actualInfoset) = saxParseWithFeatures(dpQualifiedWithDefaultAndNestedSchemas, qualifiedWithDefaultAndNestedSchemasData,
+ namespaces = true, namespacePrefixes = false)
+ assertTrue(!pr.isError)
+ assertEquals(qualifiedWithDefaultAndNestedSchemasExpectedInfoset, actualInfoset)
+ }
+
+
+ /*
+ * tests that the output from the parser is as expected, when the namespaces and the namespace
+ * prefix feature is set to true.
+ */
+ @Test def testDaffodilParseXMLReader_parse_features_both1(): Unit = {
+ val (pr, actualInfoset) = saxParseWithFeatures(dpQualifiedWithNestedSchemas, qualifiedWithNestedSchemasData,
+ namespaces = true, namespacePrefixes = true)
+ assertTrue(!pr.isError)
+ assertEquals(qualifiedWithNestedSchemasExpectedInfoset, actualInfoset)
+ }
+
+ /*
+ * tests that the output from the parser is as expected, when the namespaces and the namespace
+ * prefix feature is set to true.
+ */
+ @Test def testDaffodilParseXMLReader_parse_features_both2(): Unit = {
+ val (pr, actualInfoset) = saxParseWithFeatures(dpUnqualifiedNoNamespaces, unqualifiedNoNamespacesData,
+ namespaces = true, namespacePrefixes = true)
+ assertTrue(!pr.isError)
+ assertEquals(unqualifiedNoNamespacesExpectedInfoset, actualInfoset)
+ }
+
+ /*
+ * tests that the output from the parser is as expected, when the namespaces and the namespace
+ * prefix feature is set to true.
+ */
+ @Test def testDaffodilParseXMLReader_parse_features_both3(): Unit = {
+ val (pr, actualInfoset) = saxParseWithFeatures(dpUnqualifiedWithNestedQualified, unqualifiedWithNestedQualifiedData,
+ namespaces = true, namespacePrefixes = true)
+ assertTrue(!pr.isError)
+ assertEquals(unqualifiedWithNestedQualifiedExpectedInfoset, actualInfoset)
+ }
+
+ /*
+ * tests that the output from the parser is as expected, when the namespaces and the namespace
+ * prefix feature is set to true.
+ */
+ @Test def testDaffodilParseXMLReader_parse_features_both4(): Unit = {
+ val (pr, actualInfoset) = saxParseWithFeatures(dpQualifiedWithDefaultNamespaceSchemas, qualifiedWithDefaultNamespaceData,
+ namespaces = true, namespacePrefixes = true)
+ assertTrue(!pr.isError)
+ assertEquals(qualifiedWithDefaultNamespaceExpectedInfoset, actualInfoset)
+ }
+
+ /*
+ * tests that the output from the parser is as expected, when the namespaces and the namespace
+ * prefix feature is set to true.
+ */
+ @Test def testDaffodilParseXMLReader_parse_features_both5(): Unit = {
+ val (pr, actualInfoset) = saxParseWithFeatures(dpQualifiedWithDefaultAndNestedSchemas, qualifiedWithDefaultAndNestedSchemasData,
+ namespaces = true, namespacePrefixes = true)
+ assertTrue(!pr.isError)
+ assertEquals(qualifiedWithDefaultAndNestedSchemasExpectedInfoset, actualInfoset)
+ }
+
+ /*
+ * tests that the output from the parser is as expected, when the namespaces feature is set
+ * to true and the namespace prefix feature is set to false.
+ */
+ @Test def testDaffodilParseXMLReader_trace_features_default(): Unit = {
+ val baos = saxTraceParseWithFeatures(dpQualifiedWithNestedSchemas, nillableElementData,
+ namespaces = true, namespacePrefixes = false)
+ val actualOutput = baos.toString
+ val xsiUri = XMLUtils.XSI_NAMESPACE
+ val a02Uri = "http://a02.com"
+ val b02Uri = "http://b02.com"
+ val expectedOutput =
+ s"""startDocument
+ |startPrefixMapping(a02, $a02Uri)
+ |startPrefixMapping(b02, $b02Uri)
+ |startPrefixMapping(xsi, $xsiUri)
+ |startElement($b02Uri, seq, , Attributes())
+ |startElement($b02Uri, seq2, , Attributes())
+ |startElement($a02Uri, intx, , Attributes(($xsiUri,nil,,true)))
+ |endElement($a02Uri, intx, )
+ |endElement($b02Uri, seq2, )
+ |startElement($b02Uri, seq2, , Attributes())
+ |startElement($a02Uri, inty, , Attributes())
+ |character(Array(3), 0, 1)
+ |endElement($a02Uri, inty, )
+ |endElement($b02Uri, seq2, )
+ |startElement($b02Uri, seq2, , Attributes())
+ |startElement($b02Uri, inty, , Attributes())
+ |character(Array(4), 0, 1)
+ |endElement($b02Uri, inty, )
+ |endElement($b02Uri, seq2, )
+ |startElement($b02Uri, seq2, , Attributes())
+ |startElement($a02Uri, intx, , Attributes())
+ |character(Array(7), 0, 1)
+ |endElement($a02Uri, intx, )
+ |endElement($b02Uri, seq2, )
+ |endElement($b02Uri, seq, )
+ |endPrefixMapping(xsi)
+ |endPrefixMapping(b02)
+ |endPrefixMapping(a02)
+ |endDocument
+ |""".stripMargin
+ assertEquals(expectedOutput, actualOutput)
+ }
+
+ /*
+ * tests that the output from the parser is as expected, when the namespaces feature is set
+ * to true and the namespace prefix feature is set to true.
+ */
+ @Test def testDaffodilParseXMLReader_trace_features_namespace_and_prefixes(): Unit = {
+ val baos = saxTraceParseWithFeatures(dpQualifiedWithNestedSchemas, nillableElementData,
+ namespaces = true, namespacePrefixes = true)
+ val actualOutput = baos.toString
+ val xsiUri = XMLUtils.XSI_NAMESPACE
+ val a02Uri = "http://a02.com"
+ val b02Uri = "http://b02.com"
+ val expectedOutput =
+ s"""startDocument
+ |startPrefixMapping(a02, $a02Uri)
+ |startPrefixMapping(b02, $b02Uri)
+ |startPrefixMapping(xsi, $xsiUri)
+ |startElement($b02Uri, seq, b02:seq, Attributes((,,xmlns:xsi,$xsiUri)(,,xmlns:b02,$b02Uri)(,,xmlns:a02,$a02Uri)))
+ |startElement($b02Uri, seq2, b02:seq2, Attributes())
+ |startElement($a02Uri, intx, a02:intx, Attributes(($xsiUri,nil,xsi:nil,true)))
+ |endElement($a02Uri, intx, a02:intx)
+ |endElement($b02Uri, seq2, b02:seq2)
+ |startElement($b02Uri, seq2, b02:seq2, Attributes())
+ |startElement($a02Uri, inty, a02:inty, Attributes())
+ |character(Array(3), 0, 1)
+ |endElement($a02Uri, inty, a02:inty)
+ |endElement($b02Uri, seq2, b02:seq2)
+ |startElement($b02Uri, seq2, b02:seq2, Attributes())
+ |startElement($b02Uri, inty, b02:inty, Attributes())
+ |character(Array(4), 0, 1)
+ |endElement($b02Uri, inty, b02:inty)
+ |endElement($b02Uri, seq2, b02:seq2)
+ |startElement($b02Uri, seq2, b02:seq2, Attributes())
+ |startElement($a02Uri, intx, a02:intx, Attributes())
+ |character(Array(7), 0, 1)
+ |endElement($a02Uri, intx, a02:intx)
+ |endElement($b02Uri, seq2, b02:seq2)
+ |endElement($b02Uri, seq, b02:seq)
+ |endPrefixMapping(xsi)
+ |endPrefixMapping(b02)
+ |endPrefixMapping(a02)
+ |endDocument
+ |""".stripMargin
+ assertEquals(expectedOutput, actualOutput)
+ }
+
+ /*
+ * tests that the output from the parser is as expected, when the namespaces feature is set
+ * to false and the namespace prefix feature is set to true.
+ */
+ @Test def testDaffodilParseXMLReader_trace_features_prefixes_only(): Unit = {
+ val baos = saxTraceParseWithFeatures(dpQualifiedWithNestedSchemas, nillableElementData,
+ namespaces = false, namespacePrefixes = true)
+ val actualOutput = baos.toString
+ val xsiUri = XMLUtils.XSI_NAMESPACE
+ val a02Uri = "http://a02.com"
+ val b02Uri = "http://b02.com"
+ val expectedOutput =
+ s"""startDocument
+ |startElement(, , b02:seq, Attributes((,,xmlns:xsi,$xsiUri)(,,xmlns:b02,$b02Uri)(,,xmlns:a02,$a02Uri)))
+ |startElement(, , b02:seq2, Attributes())
+ |startElement(, , a02:intx, Attributes((,,xsi:nil,true)))
+ |endElement(, , a02:intx)
+ |endElement(, , b02:seq2)
+ |startElement(, , b02:seq2, Attributes())
+ |startElement(, , a02:inty, Attributes())
+ |character(Array(3), 0, 1)
+ |endElement(, , a02:inty)
+ |endElement(, , b02:seq2)
+ |startElement(, , b02:seq2, Attributes())
+ |startElement(, , b02:inty, Attributes())
+ |character(Array(4), 0, 1)
+ |endElement(, , b02:inty)
+ |endElement(, , b02:seq2)
+ |startElement(, , b02:seq2, Attributes())
+ |startElement(, , a02:intx, Attributes())
+ |character(Array(7), 0, 1)
+ |endElement(, , a02:intx)
+ |endElement(, , b02:seq2)
+ |endElement(, , b02:seq)
+ |endDocument
+ |""".stripMargin
+ assertEquals(expectedOutput, actualOutput)
+ }
+
+ /*
+ * tests that the output from the parser is as expected, when the namespaces feature is set
+ * to true and the namespace prefix feature is set to false.
+ */
+ @Test def testDaffodilParseXMLReader_trace_features_default_2(): Unit = {
+ val baos = saxTraceParseWithFeatures(dpUnqualifiedNoNamespaces, unqualifiedNoNamespacesData,
+ namespaces = true, namespacePrefixes = false)
+ val actualOutput = baos.toString
+ val xsiUri = XMLUtils.XSI_NAMESPACE
+ val expectedOutput =
+ s"""startDocument
+ |startPrefixMapping(xsi, $xsiUri)
+ |startElement(, x, , Attributes())
+ |startElement(, y, , Attributes())
+ |character(Array(w,o,r,l,d), 0, 5)
+ |endElement(, y, )
+ |startElement(, y, , Attributes())
+ |character(Array(n,o), 0, 2)
+ |endElement(, y, )
+ |startElement(, y, , Attributes(($xsiUri,nil,,true)))
+ |endElement(, y, )
+ |startElement(, y, , Attributes())
+ |character(Array(t,e,a), 0, 3)
+ |endElement(, y, )
+ |endElement(, x, )
+ |endPrefixMapping(xsi)
+ |endDocument
+ |""".stripMargin
+ assertEquals(expectedOutput, actualOutput)
+ }
+
+ /*
+ * tests that the output from the parser is as expected, when the namespaces feature is set
+ * to true and the namespace prefix feature is set to true.
+ */
+ @Test def testDaffodilParseXMLReader_trace_features_namespace_and_prefixes_2(): Unit = {
+ val baos = saxTraceParseWithFeatures(dpUnqualifiedNoNamespaces, unqualifiedNoNamespacesData,
+ namespaces = true, namespacePrefixes = true)
+ val actualOutput = baos.toString
+ val xsiUri = XMLUtils.XSI_NAMESPACE
+ val expectedOutput =
+ s"""startDocument
+ |startPrefixMapping(xsi, $xsiUri)
+ |startElement(, x, x, Attributes((,,xmlns:xsi,$xsiUri)))
+ |startElement(, y, y, Attributes())
+ |character(Array(w,o,r,l,d), 0, 5)
+ |endElement(, y, y)
+ |startElement(, y, y, Attributes())
+ |character(Array(n,o), 0, 2)
+ |endElement(, y, y)
+ |startElement(, y, y, Attributes(($xsiUri,nil,xsi:nil,true)))
+ |endElement(, y, y)
+ |startElement(, y, y, Attributes())
+ |character(Array(t,e,a), 0, 3)
+ |endElement(, y, y)
+ |endElement(, x, x)
+ |endPrefixMapping(xsi)
+ |endDocument
+ |""".stripMargin
+ assertEquals(expectedOutput, actualOutput)
+ }
+
+ /*
+ * tests that the output from the parser is as expected, when the namespaces feature is set
+ * to false and the namespace prefix feature is set to true.
+ */
+ @Test def testDaffodilParseXMLReader_trace_features_prefixes_only_2(): Unit = {
+ val baos = saxTraceParseWithFeatures(dpUnqualifiedNoNamespaces, unqualifiedNoNamespacesData,
+ namespaces = false, namespacePrefixes = true)
+ val actualOutput = baos.toString
+ val xsiUri = XMLUtils.XSI_NAMESPACE
+ val expectedOutput =
+ s"""startDocument
+ |startElement(, , x, Attributes((,,xmlns:xsi,$xsiUri)))
+ |startElement(, , y, Attributes())
+ |character(Array(w,o,r,l,d), 0, 5)
+ |endElement(, , y)
+ |startElement(, , y, Attributes())
+ |character(Array(n,o), 0, 2)
+ |endElement(, , y)
+ |startElement(, , y, Attributes((,,xsi:nil,true)))
+ |endElement(, , y)
+ |startElement(, , y, Attributes())
+ |character(Array(t,e,a), 0, 3)
+ |endElement(, , y)
+ |endElement(, , x)
+ |endDocument
+ |""".stripMargin
+ assertEquals(expectedOutput, actualOutput)
+ }
}
diff --git a/daffodil-core/src/test/scala/org/apache/daffodil/processor/TestSAXParseUnparseAPI.scala b/daffodil-core/src/test/scala/org/apache/daffodil/processor/TestSAXParseUnparseAPI.scala
index 347bbe2..27ec152 100644
--- a/daffodil-core/src/test/scala/org/apache/daffodil/processor/TestSAXParseUnparseAPI.scala
+++ b/daffodil-core/src/test/scala/org/apache/daffodil/processor/TestSAXParseUnparseAPI.scala
@@ -20,74 +20,34 @@ package org.apache.daffodil.processor
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
-import scala.xml.Elem
-
import javax.xml.parsers.SAXParserFactory
-import org.apache.daffodil.compiler.Compiler
+import org.apache.daffodil.api.DFDL
import org.apache.daffodil.infoset.ScalaXMLInfosetInputter
import org.apache.daffodil.infoset.ScalaXMLInfosetOutputter
import org.apache.daffodil.io.InputSourceDataInputStream
-import org.apache.daffodil.processors.DaffodilParseOutputStreamContentHandler
-import org.apache.daffodil.processors.DataProcessor
import org.apache.daffodil.processors.ParseResult
-import org.apache.daffodil.util.SchemaUtils
import org.apache.daffodil.xml.XMLUtils
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
-import org.junit.Assert.fail
import org.junit.Test
import org.xml.sax.InputSource
-object TestSAXParseUnparseAPI {
- val testSchema: Elem = SchemaUtils.dfdlTestSchema(
- <xs:include schemaLocation="org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd"/>,
- <dfdl:format ref="tns:GeneralFormat"/>,
- <xs:element name="list" type="tns:example1"/>
- <xs:complexType name="example1">
- <xs:sequence>
- <xs:element name="w" type="xs:int" dfdl:length="1" dfdl:lengthKind="explicit" maxOccurs="unbounded"/>
- </xs:sequence>
- </xs:complexType>
- )
- val testInfoset: Elem = <list xmlns="http://example.com"><w>9</w><w>1</w><w>0</w></list>
- val testInfosetString: String = testInfoset.toString()
- val testData = "910"
-
- lazy val dp: DataProcessor = testDataProcessor(testSchema)
-
- def testDataProcessor(testSchema: scala.xml.Elem, tunablesArg: Map[String, String] = Map.empty): DataProcessor = {
- val schemaCompiler = Compiler().withTunables(tunablesArg)
-
- val pf = schemaCompiler.compileNode(testSchema)
- if (pf.isError) {
- val msgs = pf.getDiagnostics.map { _.getMessage() }.mkString("\n")
- fail("pf compile errors: " + msgs)
- }
- pf.sset.root.erd.preSerialization // force evaluation of all compile-time constructs
- val dp = pf.onPath("/").asInstanceOf[DataProcessor]
- if (dp.isError) {
- val msgs = dp.getDiagnostics.map { _.getMessage() }.mkString("\n")
- fail("dp compile errors: " + msgs)
- }
- dp
- }
-}
-
class TestSAXParseUnparseAPI {
- import TestSAXParseUnparseAPI._
+ import TestSAXUtils._
+ /**
+ * Tests the case where we use SAX to parse data and SAX unparse to unparse the parsed data
+ */
@Test def test_DaffodilParseXMLReader_parse_DaffodilUnparseContentHandler_unparse(): Unit = {
- val parseXMLReader = dp.newXMLReaderInstance
- val baosParse = new ByteArrayOutputStream()
- val parseOutputStreamContentHandler = new DaffodilParseOutputStreamContentHandler(baosParse)
- parseXMLReader.setContentHandler(parseOutputStreamContentHandler)
- val inArray = testData.getBytes()
+ val (parseXMLReader: DFDL.DaffodilParseXMLReader,
+ baosParse: ByteArrayOutputStream,
+ inArray: Array[Byte]) = setupSAXParserTest(dp, testData)
val baisParse = new ByteArrayInputStream(inArray)
val inputSourceParse = new InputSource(baisParse)
parseXMLReader.parse(inputSourceParse)
val pr = parseXMLReader.getProperty(XMLUtils.DAFFODIL_SAX_URN_PARSERESULT).asInstanceOf[ParseResult]
assertTrue(!pr.isError)
- assertEquals(testInfoset, scala.xml.XML.loadString(baosParse.toString))
+ assertEquals(expectedInfoset, scala.xml.XML.loadString(baosParse.toString))
val unparseXMLReader = SAXParserFactory.newInstance().newSAXParser().getXMLReader
unparseXMLReader.setFeature(XMLUtils.SAX_NAMESPACES_FEATURE, true)
@@ -104,6 +64,9 @@ class TestSAXParseUnparseAPI {
assertEquals(testData, unparsedData)
}
+ /**
+ * Tests the case where we use StAX to parse data and SAX to unparse the parse data
+ */
@Test def test_DataProcessor_parse_DaffodilUnparseContentHandler_unparse(): Unit = {
val inArray = testData.getBytes()
val isdis = InputSourceDataInputStream(inArray)
@@ -111,7 +74,7 @@ class TestSAXParseUnparseAPI {
val pr = dp.parse(isdis, sioo)
val parsedData = sioo.getResult()
assertTrue(!pr.isError)
- assertEquals(testInfoset, parsedData)
+ assertEquals(expectedInfoset, parsedData)
val unparseXMLReader = SAXParserFactory.newInstance().newSAXParser().getXMLReader
unparseXMLReader.setFeature(XMLUtils.SAX_NAMESPACES_FEATURE, true)
@@ -128,6 +91,9 @@ class TestSAXParseUnparseAPI {
assertEquals(testData, unparsedData)
}
+ /**
+ * test the case where we use SAX to unparse data and SAX to parse the unparsed data
+ */
@Test def test_DaffodilUnparseContentHandler_unparse_DaffodilParseXMLReader_parse(): Unit = {
val unparseXMLReader = SAXParserFactory.newInstance().newSAXParser().getXMLReader
unparseXMLReader.setFeature(XMLUtils.SAX_NAMESPACES_FEATURE, true)
@@ -143,19 +109,20 @@ class TestSAXParseUnparseAPI {
assertTrue(!ur.isError)
assertEquals(testData, unparsedData)
- val parseXMLReader = dp.newXMLReaderInstance
- val baosParse = new ByteArrayOutputStream()
- val parseOutputStreamContentHandler = new DaffodilParseOutputStreamContentHandler(baosParse)
- parseXMLReader.setContentHandler(parseOutputStreamContentHandler)
- val inArray = baosUnparse.toByteArray
+ val (parseXMLReader: DFDL.DaffodilParseXMLReader,
+ baosParse: ByteArrayOutputStream,
+ inArray: Array[Byte]) = setupSAXParserTest(dp, baosUnparse.toString)
val baisParse = new ByteArrayInputStream(inArray)
val inputSourceParse = new InputSource(baisParse)
parseXMLReader.parse(inputSourceParse)
val pr = parseXMLReader.getProperty(XMLUtils.DAFFODIL_SAX_URN_PARSERESULT).asInstanceOf[ParseResult]
assertTrue(!pr.isError)
- assertEquals(testInfoset, scala.xml.XML.loadString(baosParse.toString))
+ assertEquals(expectedInfoset, scala.xml.XML.loadString(baosParse.toString))
}
+ /**
+ * tests the case where we use SAX to unparse data and StAX to parse the unparsed data
+ */
@Test def test_DaffodilUnparseContentHandler_unparse_DataProcessor_parse(): Unit = {
val unparseXMLReader = SAXParserFactory.newInstance().newSAXParser().getXMLReader
unparseXMLReader.setFeature(XMLUtils.SAX_NAMESPACES_FEATURE, true)
@@ -177,22 +144,20 @@ class TestSAXParseUnparseAPI {
val pr = dp.parse(isdis, sioo)
val parsedData = sioo.getResult()
assertTrue(!pr.isError)
- assertEquals(testInfoset, parsedData)
+ assertEquals(expectedInfoset, parsedData)
}
@Test def test_DaffodilParseXMLReader_parse_DataProcessor_unparse(): Unit = {
- val parseXMLReader = dp.newXMLReaderInstance
- val baosParse = new ByteArrayOutputStream()
- val parseOutputStreamContentHandler = new DaffodilParseOutputStreamContentHandler(baosParse)
- parseXMLReader.setContentHandler(parseOutputStreamContentHandler)
- val inArray = testData.getBytes()
+ val (parseXMLReader: DFDL.DaffodilParseXMLReader,
+ baosParse: ByteArrayOutputStream,
+ inArray: Array[Byte]) = setupSAXParserTest(dp, testData)
val baisParse = new ByteArrayInputStream(inArray)
val inputSourceParse = new InputSource(baisParse)
parseXMLReader.parse(inputSourceParse)
val parsedNode = scala.xml.XML.loadString(baosParse.toString)
val pr = parseXMLReader.getProperty(XMLUtils.DAFFODIL_SAX_URN_PARSERESULT).asInstanceOf[ParseResult]
assertTrue(!pr.isError)
- assertEquals(testInfoset, parsedNode)
+ assertEquals(expectedInfoset, parsedNode)
val baosUnparse = new ByteArrayOutputStream()
val wbcUnparse = java.nio.channels.Channels.newChannel(baosUnparse)
@@ -206,21 +171,19 @@ class TestSAXParseUnparseAPI {
@Test def test_DataProcessor_unparse_DaffodilParseXMLReader_parse(): Unit = {
val baosUnparse = new ByteArrayOutputStream()
val wbcUnparse = java.nio.channels.Channels.newChannel(baosUnparse)
- val sii = new ScalaXMLInfosetInputter(testInfoset)
+ val sii = new ScalaXMLInfosetInputter(expectedInfoset)
val ur = dp.unparse(sii, wbcUnparse)
assertTrue(!ur.isError)
assertEquals(testData, baosUnparse.toString)
- val parseXMLReader = dp.newXMLReaderInstance
- val baosParse = new ByteArrayOutputStream()
- val parseOutputStreamContentHandler = new DaffodilParseOutputStreamContentHandler(baosParse)
- parseXMLReader.setContentHandler(parseOutputStreamContentHandler)
- val inArray = baosUnparse.toByteArray
+ val (parseXMLReader: DFDL.DaffodilParseXMLReader,
+ baosParse: ByteArrayOutputStream,
+ inArray: Array[Byte]) = setupSAXParserTest(dp, baosUnparse.toString)
val baisParse = new ByteArrayInputStream(inArray)
val inputSourceParse = new InputSource(baisParse)
parseXMLReader.parse(inputSourceParse)
val pr = parseXMLReader.getProperty(XMLUtils.DAFFODIL_SAX_URN_PARSERESULT).asInstanceOf[ParseResult]
assertTrue(!pr.isError)
- assertEquals(testInfoset, scala.xml.XML.loadString(baosParse.toString))
+ assertEquals(expectedInfoset, scala.xml.XML.loadString(baosParse.toString))
}
}
diff --git a/daffodil-core/src/test/scala/org/apache/daffodil/processor/TestSAXUnparseAPI.scala b/daffodil-core/src/test/scala/org/apache/daffodil/processor/TestSAXUnparseAPI.scala
index afd3937..61175b2 100644
--- a/daffodil-core/src/test/scala/org/apache/daffodil/processor/TestSAXUnparseAPI.scala
+++ b/daffodil-core/src/test/scala/org/apache/daffodil/processor/TestSAXUnparseAPI.scala
@@ -30,8 +30,12 @@ import org.xml.sax.InputSource
import org.xml.sax.XMLReader
class TestSAXUnparseAPI {
- import TestSAXParseUnparseAPI._
+ import TestSAXUtils._
+ /**
+ * tests the base case of unparsing error free using SAX. Default for namespace features/prefixes
+ * is true/true for SAXParserFactory
+ */
@Test def testUnparseContentHandler_unparse(): Unit = {
val xmlReader: XMLReader = SAXParserFactory.newInstance.newSAXParser.getXMLReader
val bao = new ByteArrayOutputStream()
@@ -53,13 +57,16 @@ class TestSAXUnparseAPI {
*/
@Test def testUnparseContentHandler_unparse_saxUnparseEventBatchSize_0(): Unit = {
val e = intercept[java.lang.IllegalArgumentException] {
- testDataProcessor(testSchema, Map("saxUnparseEventBatchSize" -> "0"))
+ testDataProcessor(testSchema1, Map("saxUnparseEventBatchSize" -> "0"))
}
val eMsg = e.getMessage
assertTrue(eMsg.contains("saxUnparseEventBatchSize"))
assertTrue(eMsg.contains("0"))
}
+ /**
+ * tests the case of unparsing with the namespace features/prefixes set to true/false
+ */
@Test def testUnparseContentHandler_unparse_namespace_feature(): Unit = {
val xmlReader: XMLReader = SAXParserFactory.newInstance.newSAXParser.getXMLReader
val bao = new ByteArrayOutputStream()
@@ -75,6 +82,9 @@ class TestSAXUnparseAPI {
assertEquals(testData, bao.toString)
}
+ /**
+ * tests the case of unparsing with the namespace features/prefixes set to false/true
+ */
@Test def testUnparseContentHandler_unparse_namespace_prefix_feature(): Unit = {
val xmlReader: XMLReader = SAXParserFactory.newInstance.newSAXParser.getXMLReader
val bao = new ByteArrayOutputStream()
diff --git a/daffodil-core/src/test/scala/org/apache/daffodil/processor/TestSAXUtils.scala b/daffodil-core/src/test/scala/org/apache/daffodil/processor/TestSAXUtils.scala
new file mode 100644
index 0000000..5294b7a
--- /dev/null
+++ b/daffodil-core/src/test/scala/org/apache/daffodil/processor/TestSAXUtils.scala
@@ -0,0 +1,356 @@
+/*
+ * 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.processor
+
+import java.io.ByteArrayOutputStream
+import java.io.File
+import java.io.OutputStream
+import java.io.OutputStreamWriter
+
+import scala.xml.Elem
+
+import org.apache.daffodil.api.DFDL
+import org.apache.daffodil.compiler.Compiler
+import org.apache.daffodil.processors.DaffodilParseOutputStreamContentHandler
+import org.apache.daffodil.processors.DataProcessor
+import org.apache.daffodil.processors.ParseResult
+import org.apache.daffodil.util.Misc
+import org.apache.daffodil.util.SchemaUtils
+import org.apache.daffodil.xml.XMLUtils
+import org.jdom2.input.sax.BuilderErrorHandler
+import org.junit.Assert.fail
+import org.xml.sax.Attributes
+import org.xml.sax.ContentHandler
+import org.xml.sax.Locator
+
+object TestSAXUtils {
+ lazy val testSchema1: Elem = SchemaUtils.dfdlTestSchema(
+ <xs:include schemaLocation="org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd"/>,
+ <dfdl:format ref="tns:GeneralFormat"/>,
+ <xs:element name="list" type="tns:example1"/>
+ <xs:complexType name="example1">
+ <xs:sequence>
+ <xs:element name="w" type="xs:int" dfdl:length="1" dfdl:lengthKind="explicit" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ )
+ lazy val dp: DataProcessor = testDataProcessor(testSchema1)
+ lazy val expectedInfoset: Elem = <list xmlns="http://example.com"><w>9</w><w>1</w><w>0</w></list>
+ lazy val testInfosetString: String = expectedInfoset.toString()
+ lazy val testData: String = "910"
+
+
+ lazy val qualifiedWithNestedSchemasFile: File = new File(
+ Misc.getRequiredResource("/test/example_nested_namespaces_qualified.dfdl.xsd"))
+ lazy val qualifiedWithNestedSchemasElem: Elem = scala.xml.XML.loadFile(qualifiedWithNestedSchemasFile)
+ lazy val dpQualifiedWithNestedSchemas: DataProcessor = testDataProcessor(qualifiedWithNestedSchemasElem)
+ lazy val qualifiedWithNestedSchemasExpectedInfoset: Elem = {
+<b02:seq xmlns:xsi={XMLUtils.XSI_NAMESPACE} xmlns:b02="http://b02.com" xmlns:a02="http://a02.com">
+ <b02:seq2>
+ <a02:inty>3</a02:inty>
+ </b02:seq2>
+ <b02:seq2>
+ <b02:inty>4</b02:inty>
+ </b02:seq2>
+ <b02:seq2>
+ <a02:inty>2</a02:inty>
+ </b02:seq2>
+ <b02:seq2>
+ <a02:intx xsi:nil="true"/>
+ </b02:seq2>
+ <b02:seq2>
+ <b02:inty>1</b02:inty>
+ </b02:seq2>
+ <b02:seq2>
+ <b02:inty>44</b02:inty>
+ </b02:seq2>
+ <b02:seq2>
+ <a02:intx xsi:nil="true"/>
+ </b02:seq2>
+ <b02:seq2>
+ <b02:inty>643</b02:inty>
+ </b02:seq2>
+ <b02:seq2>
+ <a02:inty>3</a02:inty>
+ </b02:seq2>
+ <b02:seq2>
+ <a02:intx xsi:nil="true"/>
+ </b02:seq2>
+ <b02:seq2>
+ <a02:inty>5</a02:inty>
+ </b02:seq2>
+ <b02:seq2>
+ <b02:inty>1</b02:inty>
+ </b02:seq2>
+</b02:seq>
+ }
+ lazy val qualifiedWithNestedSchemasExpectedString: String = qualifiedWithNestedSchemasExpectedInfoset.toString()
+ lazy val qualifiedWithNestedSchemasData: String = "-3.*4.-2.^.*1.*44.^.*643.-3.^.-5.*1"
+
+ lazy val nillableElementExpectedInfoset: Elem = {
+ <b02:seq xmlns:xsi={ XMLUtils.XSI_NAMESPACE } xmlns:b02="http://b02.com" xmlns:a02="http://a02.com">
+ <b02:seq2>
+ <a02:intx xsi:nil="true"/>
+ </b02:seq2>
+ <b02:seq2>
+ <a02:inty>3</a02:inty>
+ </b02:seq2>
+ <b02:seq2>
+ <b02:inty>4</b02:inty>
+ </b02:seq2>
+ <b02:seq2>
+ <a02:intx>7</a02:intx>
+ </b02:seq2>
+ </b02:seq>
+ }
+ lazy val nillableElementExpectedString: String = nillableElementExpectedInfoset.toString()
+ lazy val nillableElementData: String = "^.-3.*4.7"
+
+ lazy val unqualifiedNoNamespacesFile: File = new File(
+ Misc.getRequiredResource("/test/example_no_targetnamespace.dfdl.xsd"))
+ lazy val unqualifiedNoNamespacesElem: Elem = scala.xml.XML.loadFile(unqualifiedNoNamespacesFile)
+ /**
+ * For an unqualified schemas with no targetnamespace and no default namespace, which means its
+ * elements are not in any namespace and there are no prefixes
+ * That schema references an element in a qualified namespace with a default
+ * namespace, which means it will have no prefix (default) but be in its default namespace
+ */
+ lazy val dpUnqualifiedNoNamespaces: DataProcessor = testDataProcessor(unqualifiedNoNamespacesElem)
+ lazy val unqualifiedNoNamespacesExpectedInfoset: Elem = {
+<x xmlns:xsi={ XMLUtils.XSI_NAMESPACE }>
+ <y>world</y>
+ <y>no</y>
+ <y xsi:nil="true"/>
+ <y>tea</y>
+</x>
+ }
+ lazy val unqualifiedNoNamespacesExpectedString: String = unqualifiedNoNamespacesExpectedInfoset.toString()
+ lazy val unqualifiedNoNamespacesData: String = "world.no.^.tea"
+
+ lazy val unqualifiedWithNestedQualifiedFile: File = new File(
+ Misc.getRequiredResource("/test/example_nested_namespaces_unqualified.dfdl.xsd"))
+ lazy val unqualifiedWithNestedQualifiedElem: Elem = scala.xml.XML.loadFile(unqualifiedWithNestedQualifiedFile)
+ /**
+ * For an unqualified schemas with a targetnamespace and no default namespace, which means its
+ * elements are in that targetnamespace, and only global elements need a prefix (unqualified).
+ * That schema references an element in a qualified namespace with a default
+ * namespace, which means it will have no prefix (default) but be in its default namespace
+ */
+ lazy val dpUnqualifiedWithNestedQualified: DataProcessor = testDataProcessor(unqualifiedWithNestedQualifiedElem)
+ lazy val unqualifiedWithNestedQualifiedExpectedInfoset: Elem = {
+<b02:a xmlns:xsi={ XMLUtils.XSI_NAMESPACE } xmlns:b02="http://b02.com" xmlns:c02="http://c02.com">
+ <b>
+ <c xmlns="http://c02.com">
+ <d>hello</d>
+ </c>
+ </b>
+ <b>
+ <c xmlns="http://c02.com">
+ <d xsi:nil="true"/>
+ </c>
+ </b>
+ <b>
+ <c xmlns="http://c02.com">
+ <d>bye</d>
+ </c>
+ </b>
+</b02:a>
+ }
+ lazy val unqualifiedWithNestedQualifiedExpectedString: String = unqualifiedWithNestedQualifiedExpectedInfoset.toString()
+ lazy val unqualifiedWithNestedQualifiedData: String = "hello.^.bye"
+
+ lazy val qualifiedWithDefaultNamespaceFile: File = new File(
+ Misc.getRequiredResource("/test/example_c02_targetnamespace_qualified.dfdl.xsd"))
+ lazy val qualifiedWithDefaultNamespaceElem: Elem = scala.xml.XML.loadFile(qualifiedWithDefaultNamespaceFile)
+ lazy val dpQualifiedWithDefaultNamespaceSchemas: DataProcessor = testDataProcessor(qualifiedWithDefaultNamespaceElem)
+ lazy val qualifiedWithDefaultNamespaceExpectedInfoset: Elem = {
+<c xmlns="http://c02.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <d>hello</d>
+</c>
+ }
+ lazy val qualifiedWithDefaultNamespaceExpectedString: String = qualifiedWithDefaultNamespaceExpectedInfoset.toString()
+ lazy val qualifiedWithDefaultNamespaceData: String = "hello"
+
+ lazy val qualifiedWithDefaultAndNestedSchemasFile: File = new File(
+ Misc.getRequiredResource("/test/example_nested_namespaces_qualified_with_default.dfdl.xsd"))
+ lazy val qualifiedWithDefaultAndNestedSchemasElem: Elem = scala.xml.XML.loadFile(qualifiedWithDefaultAndNestedSchemasFile)
+ lazy val dpQualifiedWithDefaultAndNestedSchemas: DataProcessor = testDataProcessor(qualifiedWithDefaultAndNestedSchemasElem)
+ lazy val qualifiedWithDefaultAndNestedSchemasExpectedInfoset: Elem = {
+<a xmlns="http://b02.com" xmlns:xsi={XMLUtils.XSI_NAMESPACE} xmlns:c02="http://c02.com">
+ <b>
+ <c xmlns="http://c02.com">
+ <d>test</d>
+ </c>
+ </b>
+ <b>
+ <c xmlns="http://c02.com">
+ <d>ting</d>
+ </c>
+ </b>
+</a>
+ }
+ lazy val qualifiedWithDefaultAndNestedSchemasExpectedString: String = qualifiedWithDefaultAndNestedSchemasExpectedInfoset.toString()
+ lazy val qualifiedWithDefaultAndNestedSchemasData: String = "test.ting"
+
+
+
+ def testDataProcessor(testSchema: scala.xml.Elem, tunablesArg: Map[String, String] = Map.empty): DataProcessor = {
+ val schemaCompiler = Compiler().withTunables(tunablesArg)
+
+ val pf = schemaCompiler.compileNode(testSchema)
+ if (pf.isError) {
+ val msgs = pf.getDiagnostics.map { _.getMessage() }.mkString("\n")
+ fail("pf compile errors: " + msgs)
+ }
+ pf.sset.root.erd.preSerialization // force evaluation of all compile-time constructs
+ val dp = pf.onPath("/").asInstanceOf[DataProcessor]
+ if (dp.isError) {
+ val msgs = dp.getDiagnostics.map { _.getMessage() }.mkString("\n")
+ fail("dp compile errors: " + msgs)
+ }
+ dp
+ }
+
+ def saxParseWithFeatures(
+ dp: DataProcessor,
+ data: String,
+ namespaces: Boolean,
+ namespacePrefixes: Boolean): (ParseResult, scala.xml.Elem) = {
+ val (xmlReader: DFDL.DaffodilParseXMLReader,
+ baos: ByteArrayOutputStream,
+ inArray: Array[Byte]) = setupSAXParserTest(dp, data, pretty = true)
+ xmlReader.setFeature(XMLUtils.SAX_NAMESPACES_FEATURE, namespaces)
+ xmlReader.setFeature(XMLUtils.SAX_NAMESPACE_PREFIXES_FEATURE, namespacePrefixes)
+ xmlReader.parse(inArray)
+ val pr = xmlReader.getProperty(XMLUtils.DAFFODIL_SAX_URN_PARSERESULT).asInstanceOf[ParseResult]
+ val actualInfoset = scala.xml.XML.loadString(baos.toString)
+ (pr, actualInfoset)
+ }
+
+ def saxTraceParseWithFeatures(
+ dp: DataProcessor,
+ data: String,
+ namespaces: Boolean,
+ namespacePrefixes: Boolean): ByteArrayOutputStream = {
+ val (xmlReader: DFDL.DaffodilParseXMLReader,
+ baos: ByteArrayOutputStream,
+ inArray: Array[Byte]) = setupTraceSAXParserTest(dp, data, pretty = true)
+ xmlReader.setFeature(XMLUtils.SAX_NAMESPACES_FEATURE, namespaces)
+ xmlReader.setFeature(XMLUtils.SAX_NAMESPACE_PREFIXES_FEATURE, namespacePrefixes)
+ xmlReader.parse(inArray)
+ val traceContentHandler = xmlReader.getContentHandler.asInstanceOf[TestContentHandler]
+ traceContentHandler.fini()
+ baos
+ }
+
+ def setupSAXParserTest(dp: DFDL.DataProcessor, data: String, pretty: Boolean = false):
+ (DFDL.DaffodilParseXMLReader, ByteArrayOutputStream, Array[Byte]) = {
+ val xmlReader = dp.newXMLReaderInstance
+ val baos = new ByteArrayOutputStream()
+ val parseContentHandler = new DaffodilParseOutputStreamContentHandler(baos, pretty = pretty)
+ val eh = new BuilderErrorHandler
+ xmlReader.setErrorHandler(eh)
+ xmlReader.setContentHandler(parseContentHandler)
+ val inArray = data.getBytes()
+ (xmlReader, baos, inArray)
+ }
+
+ def setupTraceSAXParserTest(dp: DFDL.DataProcessor, data: String, pretty: Boolean = false):
+ (DFDL.DaffodilParseXMLReader, ByteArrayOutputStream, Array[Byte]) = {
+ val xmlReader = dp.newXMLReaderInstance
+ val baos = new ByteArrayOutputStream()
+ val parseContentHandler = new TestContentHandler(baos)
+ val eh = new BuilderErrorHandler
+ xmlReader.setErrorHandler(eh)
+ xmlReader.setContentHandler(parseContentHandler)
+ val inArray = data.getBytes()
+ (xmlReader, baos, inArray)
+ }
+
+}
+
+/**
+ * Test ContentHandler class that is used to test that XMLReader provides the expected input
+ * to ContentHandler classes
+ *
+ * @param out output Stream of choice that the trace will be written to
+ */
+class TestContentHandler(out: OutputStream) extends ContentHandler {
+ val sb: StringBuilder = new StringBuilder
+ private val writer = new OutputStreamWriter(out)
+ /**
+ * platform specific newline
+ */
+ private val newLine = System.lineSeparator()
+
+ override def startDocument(): Unit = writer.write(s"startDocument$newLine")
+
+ override def endDocument(): Unit = writer.write(s"endDocument$newLine")
+
+ override def startPrefixMapping(prefix: String, uri: String): Unit = {
+ writer.write(s"startPrefixMapping($prefix, $uri)$newLine")
+ }
+
+ override def endPrefixMapping(prefix: String): Unit = {
+ writer.write(s"endPrefixMapping($prefix)$newLine")
+ }
+
+ override def startElement(uri: String, localName: String, qName: String, atts: Attributes): Unit = {
+ writer.write(s"startElement($uri, $localName, $qName, ${attributesToString(atts)})$newLine")
+ }
+
+ override def endElement(uri: String, localName: String, qName: String): Unit = {
+ writer.write(s"endElement($uri, $localName, $qName)$newLine")
+ }
+
+ override def characters(ch: Array[Char], start: Int, length: Int): Unit = {
+ writer.write(s"character(${ch.mkString("Array(", ",", ")")}, $start, $length)$newLine")
+ }
+
+ override def setDocumentLocator(locator: Locator): Unit = {
+ // do nothing
+ }
+
+ override def ignorableWhitespace(ch: Array[Char], start: Int, length: Int): Unit = {
+ // do nothing
+ }
+
+ override def processingInstruction( target: String, data: String): Unit = {
+ // do nothing
+ }
+
+ override def skippedEntity(name: String): Unit = {
+ // do nothing
+ }
+
+ def attributesToString(atts: Attributes): String = {
+ sb.setLength(0)
+ val len = atts.getLength
+ sb ++= "Attributes("
+ for (i <- 0 until len) {
+ sb ++= s"(${atts.getURI(i)},${atts.getLocalName(i)},${atts.getQName(i)},${atts.getValue(i)})"
+ }
+ sb ++= ")"
+ sb.toString()
+ }
+
+ def fini(): Unit = {
+ writer.flush()
+ }
+
+}
diff --git a/daffodil-japi/src/main/java/org/apache/daffodil/japi/package-info.java b/daffodil-japi/src/main/java/org/apache/daffodil/japi/package-info.java
index 2c00eb1..1eaa6a0 100644
--- a/daffodil-japi/src/main/java/org/apache/daffodil/japi/package-info.java
+++ b/daffodil-japi/src/main/java/org/apache/daffodil/japi/package-info.java
@@ -200,6 +200,11 @@
* }
* </pre>
*
+ * The value of the supported features cannot be changed during a parse, and the parse will run
+ * with the value of the features as they were when the parse was kicked off. To run a parse with
+ * different feature values, one must wait until the running parse finishes, set the feature values
+ * using the XMLReader's setFeature and run the parse again.
+ *
* One can repeat calls to parse() using the same InputSourceDataInputStream to continue parsing
* where the previous parse ended. For example:
*
diff --git a/daffodil-japi/src/test/java/org/apache/daffodil/example/TestJavaAPI.java b/daffodil-japi/src/test/java/org/apache/daffodil/example/TestJavaAPI.java
index 99647e5..64aa384 100644
--- a/daffodil-japi/src/test/java/org/apache/daffodil/example/TestJavaAPI.java
+++ b/daffodil-japi/src/test/java/org/apache/daffodil/example/TestJavaAPI.java
@@ -980,6 +980,9 @@ public class TestJavaAPI {
org.jdom2.input.sax.SAXHandler contentHandler = new org.jdom2.input.sax.SAXHandler();
SAXErrorHandlerForJAPITest errorHandler = new SAXErrorHandlerForJAPITest();
+ // since SAXHandler uses a blank prefix when the below isn't set to true, it introduces
+ // an undesired no-prefixed xmlns mapping
+ parseXMLReader.setFeature(SAX_NAMESPACE_PREFIXES_FEATURE, true);
parseXMLReader.setContentHandler(contentHandler);
parseXMLReader.setErrorHandler(errorHandler);
parseXMLReader.setProperty(DaffodilParseXMLReader.DAFFODIL_SAX_URN_BLOBDIRECTORY(),
diff --git a/daffodil-lib/src/main/scala/org/apache/daffodil/xml/QNameBase.scala b/daffodil-lib/src/main/scala/org/apache/daffodil/xml/QNameBase.scala
index 4d35706..809faec 100644
--- a/daffodil-lib/src/main/scala/org/apache/daffodil/xml/QNameBase.scala
+++ b/daffodil-lib/src/main/scala/org/apache/daffodil/xml/QNameBase.scala
@@ -225,7 +225,6 @@ trait QNameBase extends Serializable {
* or by omitting one, are very common.
*/
def prefix: Option[String]
- def prefixOrNull: String = prefix.orNull
def local: String
def namespace: NS // No namespace is represented by the NoNamespace object.
diff --git a/daffodil-lib/src/main/scala/org/apache/daffodil/xml/XMLUtils.scala b/daffodil-lib/src/main/scala/org/apache/daffodil/xml/XMLUtils.scala
index b517a90..872daa2 100644
--- a/daffodil-lib/src/main/scala/org/apache/daffodil/xml/XMLUtils.scala
+++ b/daffodil-lib/src/main/scala/org/apache/daffodil/xml/XMLUtils.scala
@@ -22,6 +22,7 @@ import java.nio.file.Files
import java.nio.file.Paths
import java.nio.file.StandardOpenOption
+import scala.annotation.tailrec
import scala.collection.mutable
import scala.collection.mutable.ArrayBuilder
import scala.xml.NamespaceBinding
@@ -33,6 +34,7 @@ import org.apache.daffodil.calendar.DFDLDateTimeConversion
import org.apache.daffodil.calendar.DFDLTimeConversion
import org.apache.daffodil.exceptions._
import org.apache.daffodil.schema.annotation.props.LookupLocation
+import org.apache.daffodil.util.Maybe
import org.apache.daffodil.util.Misc
/**
@@ -849,15 +851,25 @@ object XMLUtils {
checkPrefixes,
checkNamespaces)
if (diffs.length > 0) {
+ val attributesProperty = if(checkPrefixes || checkNamespaces) {
+ "attributes not ignored for diff"
+ } else {
+ "attributes ignored for diff"
+ }
throw new XMLDifferenceException("""
Comparison failed.
-Expected (attributes stripped)
+Expected (attributes %s)
%s
-Actual (attributes ignored for diff)
+Actual (attributes %s for diff)
%s
Differences were (path, expected, actual):
%s""".format(
- removeAttributes(expected).toString,
+ (if (checkPrefixes || checkNamespaces) "compared for diff"
+ else "stripped"),
+ (if (checkPrefixes || checkNamespaces) expected
+ else removeAttributes(expected).toString),
+ (if (checkPrefixes || checkNamespaces) "compared"
+ else "ignored"),
actual,
diffs.map { _.toString }.mkString("- ", "\n- ", "\n")))
}
@@ -913,9 +925,6 @@ Differences were (path, expected, actual):
val maybeType: Option[String] = Option(typeA.getOrElse(typeB.getOrElse(null)))
val nilledA = a.attribute(XSI_NAMESPACE.toString, "nil")
val nilledB = b.attribute(XSI_NAMESPACE.toString, "nil")
- // we sort here, since sameElements is not order independent
- val nsbACompare = nsbA.toString().trim.split(" ").sorted
- val nsbBCompare = nsbB.toString().trim.split(" ").sorted
if (labelA != labelB) {
// different label
@@ -923,7 +932,7 @@ Differences were (path, expected, actual):
} else if (checkPrefixes && prefixA != prefixB) {
// different prefix
List((zPath, prefixA, prefixB))
- } else if (checkNamespaces && !nsbACompare.sameElements(nsbBCompare)) {
+ } else if (checkNamespaces && nsbA != nsbB ) {
// different namespace bindings
List((zPath, nsbA.toString(), nsbB.toString()))
} else if (nilledA != nilledB) {
@@ -1255,6 +1264,46 @@ Differences were (path, expected, actual):
sb.append(s)
sb.append(";")
}
+
+ /**
+ * Return a Maybe(URI) from NamespaceBinding based on some input prefix. There is a
+ * NamespaceBinding equivalent of this called getURI, but that does not handle the null case
+ * and will throw a NullPointerException when uri can't be found
+ *
+ * @param nsb NamespaceBinding we wish to search for the prefix's uri
+ * @param prefix Prefix whose URI we search through the NamespaceBinding for
+ * @return the uri string wrapped in a Maybe.One, or Maybe.Nope, if not found
+ */
+ @tailrec
+def maybeURI(nsb: NamespaceBinding, prefix: String): Maybe[String] = {
+ if (nsb == null) Maybe.Nope
+ else if (nsb.prefix == prefix) Maybe.One(nsb.uri)
+ else maybeURI(nsb.parent, prefix)
+ }
+
+ /**
+ * Return Maybe(prefix) from NamespaceBinding based on some input uri. There is a
+ * NamespaceBinding equivalent of this called gePrefix, but that does not handle the null case
+ * and will throw a NullPointerException when uri can't be found
+ *
+ * @param nsb NamespaceBinding we wish to search for the uri's prefix
+ * @param uri Prefix whose URI we search through the NamespaceBinding for
+ * @return the prefix string wrapped in a Maybe.One, or Maybe.Nope if not found or prefix is null
+ */
+ @tailrec
+ def maybePrefix(nsb: NamespaceBinding, uri: String): Maybe[String] = {
+
+ if (nsb == null) Maybe.Nope
+ else if (nsb.uri == uri) {
+ if (nsb.prefix == null) {
+ // the case of xmlns="some-uri"
+ Maybe.Nope
+ } else {
+ Maybe.One(nsb.prefix)
+ }
+ }
+ else maybePrefix(nsb.parent, uri)
+ }
}
trait GetAttributesMixin extends ThrowsSDE {
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/infoset/JDOMInfosetOutputter.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/infoset/JDOMInfosetOutputter.scala
index 18c03de..f0f1ba1 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/infoset/JDOMInfosetOutputter.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/infoset/JDOMInfosetOutputter.scala
@@ -102,7 +102,7 @@ class JDOMInfosetOutputter extends InfosetOutputter
if(diElement.erd.namedQName.namespace.isNoNamespace)
new org.jdom2.Element(diElement.erd.name)
else
- new org.jdom2.Element(diElement.erd.name, diElement.erd.namedQName.prefixOrNull,
+ new org.jdom2.Element(diElement.erd.name, diElement.erd.prefix,
diElement.erd.namedQName.namespace)
if (isNilled(diElement)) {
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/infoset/SAXInfosetOutputter.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/infoset/SAXInfosetOutputter.scala
index d2be4ba..f7df299 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/infoset/SAXInfosetOutputter.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/infoset/SAXInfosetOutputter.scala
@@ -17,6 +17,8 @@
package org.apache.daffodil.infoset
+import scala.xml.NamespaceBinding
+
import org.apache.daffodil.api.DFDL
import org.apache.daffodil.dpath.NodeInfo
import org.apache.daffodil.xml.XMLUtils
@@ -24,9 +26,12 @@ import org.xml.sax.ContentHandler
import org.xml.sax.SAXException
import org.xml.sax.helpers.AttributesImpl
-class SAXInfosetOutputter(xmlReader: DFDL.DaffodilParseXMLReader)
+class SAXInfosetOutputter(xmlReader: DFDL.DaffodilParseXMLReader,
+ val namespacesFeature: Boolean,
+ val namespacePrefixesFeature: Boolean)
extends InfosetOutputter
with XMLInfosetOutputter {
+
/**
* Reset the internal state of this InfosetOutputter. This should be called
* inbetween calls to the parse method.
@@ -137,64 +142,106 @@ class SAXInfosetOutputter(xmlReader: DFDL.DaffodilParseXMLReader)
override def endArray(diArray: DIArray): Boolean = true // not applicable
- private def createNilAttribute(): AttributesImpl = {
- val attrs = new AttributesImpl()
- attrs.addAttribute(XMLUtils.XSI_NAMESPACE, "nil", "xsi:nil", "", "true")
- attrs
- }
-
private def doStartPrefixMapping(diElem: DIElement, contentHandler: ContentHandler): Unit = {
- val nsbStart = diElem.erd.minimizedScope
- val nsbEnd = if (diElem.isRoot) {
- scala.xml.TopScope
- } else {
- diElem.diParent.erd.minimizedScope
- }
+ val (nsbStart: NamespaceBinding, nsbEnd: NamespaceBinding) = getNsbStartAndEnd(diElem)
var n = nsbStart
- while (n != nsbEnd && n != null && n != scala.xml.TopScope) {
+ var mappingsList: Seq[(String, String)] = Seq()
+ while (n.ne(nsbEnd) && n.ne(null) && n.ne(scala.xml.TopScope)) {
val prefix = if (n.prefix == null) "" else n.prefix
val uri = if (n.uri == null) "" else n.uri
- contentHandler.startPrefixMapping(prefix, uri)
+ // we generate a list here by prepending so can build the prefixMapping in the
+ // same order as it is in minimizedScope when we call startPrefixMapping; we do this because
+ // getPrefix in the contentHandler is order dependent
+ mappingsList +:= (prefix, uri)
n = n.parent
}
+ mappingsList.foreach{ case (prefix, uri) =>
+ contentHandler.startPrefixMapping(prefix, uri)
+ }
}
private def doEndPrefixMapping(diElem: DIElement, contentHandler: ContentHandler): Unit = {
- val nsbStart = diElem.erd.minimizedScope
- val nsbEnd = if (diElem.isRoot) {
- scala.xml.TopScope
- } else {
- diElem.diParent.erd
- .minimizedScope
- }
+ val (nsbStart: NamespaceBinding, nsbEnd: NamespaceBinding) = getNsbStartAndEnd(diElem)
var n = nsbStart
- while (n != nsbEnd && n != null && n != scala.xml.TopScope) {
+ while (n.ne(nsbEnd) && n.ne(null) && n.ne(scala.xml.TopScope)) {
val prefix = if (n.prefix == null) "" else n.prefix
contentHandler.endPrefixMapping(prefix)
n = n.parent
}
}
- private def doStartElement(diElem: DIElement, contentHandler: ContentHandler): Unit = {
- val (ns: String, elemName: String, qName: String) = getNameSpaceElemNameAndQName(diElem)
- doStartPrefixMapping(diElem, contentHandler)
+ /**
+ * Add the prefixes and uris from the element's NamespaceBinding to Attributes,
+ * when namespacePrefixes feature is true
+ */
+ private def doAttributesPrefixMapping(diElem: DIElement, attrs: AttributesImpl): AttributesImpl = {
+ val (nsbStart: NamespaceBinding, nsbEnd: NamespaceBinding) = getNsbStartAndEnd(diElem)
+ var n = nsbStart
+ while (n.ne(nsbEnd) && n.ne(null) && n.ne(scala.xml.TopScope)) {
+ val prefix = if (n.prefix == null) "xmlns" else s"xmlns:${n.prefix}"
+ val uri = if (n.uri == null) "" else n.uri
+ // uri and localname are always empty for NamespaceBinding attributes
+ attrs.addAttribute("", "", prefix, "CDATA", uri)
+ n = n.parent
+ }
+ attrs
+ }
- val attrs = if (isNilled(diElem)) {
- createNilAttribute()
+ private def getNsbStartAndEnd(diElem: DIElement) = {
+ val nsbStart = diElem.erd.minimizedScope
+ val nsbEnd = if (diElem.isRoot) {
+ scala.xml.TopScope
} else {
- new AttributesImpl()
+ diElem.diParent.erd.minimizedScope
}
+ (nsbStart, nsbEnd)
+ }
- contentHandler.startElement(ns, elemName, qName, attrs)
+ private def doStartElement(diElem: DIElement, contentHandler: ContentHandler): Unit = {
+ val (ns: String, localName: String, qName: String) = getNamespaceLocalNameAndQName(diElem)
+ val attrs = new AttributesImpl()
+ val elemUri: String = if (namespacesFeature) ns else ""
+ val elemLocalName: String = if (namespacesFeature) localName else ""
+ val elemQname: String = if (namespacePrefixesFeature) qName else ""
+
+ if (namespacesFeature) {
+ // only when this feature is true do we use prefix mappings
+ doStartPrefixMapping(diElem, contentHandler)
+ }
+
+ if (namespacePrefixesFeature) {
+ // handle prefix attribute
+ doAttributesPrefixMapping(diElem, attrs)
+ }
+
+ // handle xsi:nil attribute
+ if (diElem.isNilled) {
+ val isNilled = "true"
+ val nType: String = "CDATA"
+ val nValue: String = isNilled
+ val nQname = if (namespacePrefixesFeature) "xsi:nil" else ""
+ val nUri: String = if (namespacesFeature) XMLUtils.XSI_NAMESPACE else ""
+ val nLocalName: String = if (namespacesFeature) "nil" else ""
+
+ attrs.addAttribute(nUri, nLocalName, nQname, nType, nValue)
+ }
+
+ contentHandler.startElement(elemUri, elemLocalName, elemQname, attrs)
}
private def doEndElement (diElem: DIElement, contentHandler: ContentHandler): Unit = {
- val (ns: String, elemName: String, qName: String) = getNameSpaceElemNameAndQName(diElem)
- contentHandler.endElement(ns, elemName, qName)
- doEndPrefixMapping(diElem, contentHandler)
+ val (ns: String, localName: String, qName: String) = getNamespaceLocalNameAndQName(diElem)
+ val elemUri: String = if (namespacesFeature) ns else ""
+ val elemLocalName = if (namespacesFeature) localName else ""
+ val elemQname = if (namespacePrefixesFeature) qName else ""
+
+ contentHandler.endElement(elemUri, elemLocalName, elemQname)
+
+ // only when this feature is true do we use prefix mappings
+ if (namespacesFeature) doEndPrefixMapping(diElem, contentHandler)
}
- private def getNameSpaceElemNameAndQName(
+ private def getNamespaceLocalNameAndQName(
diElem: DIElement): (String, String, String) = {
val ns: String =
if (diElem.erd.namedQName.namespace.isNoNamespace) {
@@ -203,7 +250,7 @@ class SAXInfosetOutputter(xmlReader: DFDL.DaffodilParseXMLReader)
diElem.erd.namedQName.namespace.toString
}
val elemName = diElem.erd.namedQName.local
- val qName = diElem.erd.namedQName.toQNameString
+ val qName = diElem.erd.prefixedName
(ns, elemName, qName)
}
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/infoset/ScalaXMLInfosetOutputter.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/infoset/ScalaXMLInfosetOutputter.scala
index 63c330b..2e037f5 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/infoset/ScalaXMLInfosetOutputter.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/infoset/ScalaXMLInfosetOutputter.scala
@@ -94,7 +94,7 @@ class ScalaXMLInfosetOutputter(showFormatInfo: Boolean = false, showFreedInfo: B
val elem =
scala.xml.Elem(
- diSimple.erd.namedQName.prefixOrNull,
+ diSimple.erd.prefix,
diSimple.erd.name,
attributes,
diSimple.erd.minimizedScope,
@@ -122,7 +122,7 @@ class ScalaXMLInfosetOutputter(showFormatInfo: Boolean = false, showFreedInfo: B
val elem =
scala.xml.Elem(
- diComplex.erd.namedQName.prefixOrNull,
+ diComplex.erd.prefix,
diComplex.erd.name,
attributes,
diComplex.erd.minimizedScope,
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/infoset/XMLTextInfosetOutputter.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/infoset/XMLTextInfosetOutputter.scala
index a2487dc..4925871 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/infoset/XMLTextInfosetOutputter.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/infoset/XMLTextInfosetOutputter.scala
@@ -48,7 +48,7 @@ class XMLTextInfosetOutputter private (writer: java.io.Writer, pretty: Boolean,
}
private def outputTagName(elem: DIElement): Unit = {
- val prefix = elem.erd.namedQName.prefixOrNull
+ val prefix = elem.erd.prefix
if (prefix != null && prefix != "") {
writer.write(prefix)
writer.write(":")
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/DaffodilParseOutputStreamContentHandler.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/DaffodilParseOutputStreamContentHandler.scala
index 3255c03..0c71a5f 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/DaffodilParseOutputStreamContentHandler.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/DaffodilParseOutputStreamContentHandler.scala
@@ -22,17 +22,44 @@ import java.io.OutputStreamWriter
import scala.xml.NamespaceBinding
-import org.apache.daffodil.infoset.XMLInfosetOutputter
+import org.apache.daffodil.exceptions.Assert
import org.apache.daffodil.util.Indentable
+import org.apache.daffodil.util.MStackOf
import org.apache.daffodil.util.MStackOfBoolean
+import org.apache.daffodil.util.Maybe
+import org.apache.daffodil.util.Maybe.Nope
+import org.apache.daffodil.xml.XMLUtils
import org.xml.sax.Attributes
import org.xml.sax.ContentHandler
import org.xml.sax.Locator
+/**
+ * ContentHandler implementation that receives SAX events from DaffodilParseXMLReader to output
+ * XML to the specified outputStream. Depending on the features set in the XMLReader, it uses either
+ * prefixMappings or attributes to determine the prefix of the XML element. This means it will always
+ * try to find and print a prefix if an element has a URI.
+ *
+ * @param out outputStream object to write generated XML to
+ * @param pretty boolean to pretty print XML if true, or not if false
+ */
class DaffodilParseOutputStreamContentHandler(out: OutputStream, pretty: Boolean = false)
- extends ContentHandler with Indentable with XMLInfosetOutputter {
+ extends ContentHandler with Indentable {
private val writer = new OutputStreamWriter(out)
- private var prefixMapping: NamespaceBinding = null
+ /**
+ * represents the currently active prefix mappings (i.e all mappings include from parent element),
+ * which is usefully for doing lookups
+ */
+ private var activePrefixMapping: NamespaceBinding = null
+ /**
+ * represents only the prefix mapping of the current element. We use this to generate the prefix mappings
+ * when outputting the element tag
+ */
+ private var currentElementPrefixMapping: NamespaceBinding = null
+ /**
+ * used to maintain the correct scope of activePrefixMapping throughout processing. It is also used
+ * to reset the activePrefixMapping after processing each element.
+ */
+ private lazy val activePrefixMappingContextStack = new MStackOf[NamespaceBinding]
private val outputNewlineStack: MStackOfBoolean = {
val s = MStackOfBoolean()
s.push(false)
@@ -45,7 +72,9 @@ class DaffodilParseOutputStreamContentHandler(out: OutputStream, pretty: Boolean
def reset(): Unit = {
resetIndentation()
writer.flush()
- prefixMapping = null
+ activePrefixMapping = null
+ currentElementPrefixMapping = null
+ activePrefixMappingContextStack.clear()
outputNewlineStack.clear()
outputNewlineStack.push(false) //to match initialization state
out.flush()
@@ -66,13 +95,80 @@ class DaffodilParseOutputStreamContentHandler(out: OutputStream, pretty: Boolean
override def startPrefixMapping(prefix: String, uri: String): Unit = {
val _prefix = if (prefix == "") null else prefix
- prefixMapping = NamespaceBinding(_prefix, uri, prefixMapping)
+ activePrefixMapping = NamespaceBinding(_prefix, uri, activePrefixMapping)
+ currentElementPrefixMapping = NamespaceBinding(_prefix, uri, currentElementPrefixMapping)
}
override def endPrefixMapping(prefix: String): Unit = {
// do nothing
}
+ /**
+ * Uses Attributes, which is passed in to the startElement callback, to gather element attributes
+ * or in the case where namespacePrefixes is true, prefix mappings. Any new prefix mappings are used
+ * to update the activePrefixMapping and currentElementPrefixMapping.
+ *
+ * @return sequence of string attribute=val pairings
+ */
+ def processAttributes(atts: Attributes): Seq[String] = {
+ var attrPairings: Seq[String] = Seq()
+ var i = 0
+ var newMappingsList: Seq[(String, String)] = Seq()
+ while (i < atts.getLength) {
+ val qName = atts.getQName(i)
+ val attrVal = atts.getValue(i)
+ if (qName.nonEmpty) {
+ // if qName is populated; as in when namespacePrefixes == true
+ // describing namespace mapping
+ if (qName.startsWith("xmlns:") || qName == "xmlns") {
+ // get prefix
+ val pre = if (qName.startsWith("xmlns:")) {
+ qName.substring(6)
+ } else {
+ null
+ }
+ // we make this call to check if the prefix already exists. If it doesn't exist, we get a
+ // Nope, so we can add it to our list, but if it does exist, nothing happens and it doesn't
+ // get re-added and we instead proceed to the next item in Attributes
+ val maybeUri = XMLUtils.maybeURI(activePrefixMapping, pre)
+ if (maybeUri.isEmpty || maybeUri.get != attrVal) { // not found yet, add it
+ newMappingsList +:= (pre, attrVal)
+ }
+ } else {
+ // regular attribute with qname such as xsi:nil
+ attrPairings +:= s""" ${qName}="${attrVal}""""
+ }
+ } else {
+ // no qname, so namespacePrefixes == false, which means we get no
+ // prefix mappings in the attributes, only regular attributes such as xsi:nil
+ // though not in qname form
+ val uri = atts.getURI(i)
+ val localName = atts.getLocalName(i)
+ // prefixed attribute, not prefix mapping, as they only show up as qnames
+ if (uri.nonEmpty && localName.nonEmpty) {
+ val maybePrefix = XMLUtils.maybePrefix(activePrefixMapping, uri)
+ // found a prefix; add to attribute pairings
+ if (maybePrefix.isDefined) {
+ val prefix = maybePrefix.get
+ attrPairings +:= s""" $prefix:$localName="${attrVal}""""
+ } else {
+ // if an attribute has a URI, we must have a prefix, even if it is null
+ Assert.invariantFailed("Cannot have URI with no prefix mapping")
+ }
+ } else {
+ // non prefixed attribute don't exist in Daffodil
+ Assert.invariantFailed("Cannot have an attribute with no qname, uri or localname")
+ }
+ }
+ i += 1
+ }
+ newMappingsList.foreach{ case (prefix, uri) =>
+ activePrefixMapping = NamespaceBinding(prefix, uri, activePrefixMapping)
+ currentElementPrefixMapping = NamespaceBinding(prefix, uri, currentElementPrefixMapping)
+ }
+ attrPairings.reverse
+ }
+
override def startElement(
uri: String, localName: String, qName: String, atts: Attributes): Unit = {
// the pop/true removes whatever is on the stack which is our previous guess for whether we
@@ -84,21 +180,34 @@ class DaffodilParseOutputStreamContentHandler(out: OutputStream, pretty: Boolean
writer.write(System.lineSeparator())
outputIndentation(writer)
}
+
+ /**
+ * represents the attributes for the current element. We use this to generate the attributes list
+ * within the start tag
+ */
+ val currentElementAttributes = processAttributes(atts)
+ // we always push, but activePrefixMapping won't always be populated with new information
+ // from startPrefixMapping or processAttributes
+ activePrefixMappingContextStack.push(activePrefixMapping)
+
// handle start of tag
writer.write("<")
- writer.write(qName)
- // handle attributes
- for (i <- 0 until atts.getLength) {
- val attsValue = atts.getValue(i)
- val attsQName = atts.getQName(i)
- writer.write(s""" $attsQName="$attsValue"""")
- }
- // handle namespaces
- if (prefixMapping != null) {
- val pm = prefixMapping.toString()
+ outputTagName(uri, localName, qName, Some(atts))
+
+ // this contains only xmlns prefixes and are populated via the start/endPrefixMappings
+ // or Attributes via processAttributes()
+ if (currentElementPrefixMapping != null) {
+ val pm = currentElementPrefixMapping.toString()
writer.write(pm)
- prefixMapping = null
+ currentElementPrefixMapping = null
}
+
+ // handles attributes from the Attributes object. Example attributes is xsi:nil
+ if (currentElementAttributes.nonEmpty) {
+ val attrs = currentElementAttributes.mkString(" ")
+ writer.write(attrs)
+ }
+
// handle end of tag
writer.write(">")
incrementIndentation()
@@ -107,6 +216,29 @@ class DaffodilParseOutputStreamContentHandler(out: OutputStream, pretty: Boolean
outputNewlineStack.push(false)
}
+ private def outputTagName(uri: String, localName: String, qName: String, atts: Maybe[Attributes] = Nope): Unit = {
+ val tagName = {
+ if (qName.nonEmpty) {
+ // namespacePrefixes == true, so qName is populated
+ qName
+ } else {
+ // namespacePrefixes == false, so uri and localName are populated, but not qname
+ // and attributes don't have prefix mapping information
+ // if we have no qName, we need to use activePrefixMapping to get the prefix of the uri
+ // to build the qname
+ val sanitizedUri = if (uri.isEmpty) null else uri
+ val maybePrefix = XMLUtils.maybePrefix(activePrefixMapping, sanitizedUri)
+ if (maybePrefix.isDefined) {
+ val pre = maybePrefix.get
+ s"$pre:$localName"
+ } else {
+ localName
+ }
+ }
+ }
+ writer.write(tagName)
+ }
+
override def endElement(uri: String, localName: String, qName: String): Unit = {
decrementIndentation()
if (outputNewline) {
@@ -116,9 +248,20 @@ class DaffodilParseOutputStreamContentHandler(out: OutputStream, pretty: Boolean
}
}
writer.write("</")
- writer.write(qName)
+ outputTagName(uri, localName, qName)
writer.write(">")
outputNewlineStack.pop()
+
+ Assert.invariant(!activePrefixMappingContextStack.isEmpty)
+ // throw out current prefix mapping context as we're done with it
+ activePrefixMappingContextStack.pop
+
+ // set the activePrefixMapping to the next mapping in the stack if the stack isn't empty
+ if (activePrefixMappingContextStack.isEmpty) {
+ activePrefixMapping = null
+ } else {
+ activePrefixMapping = activePrefixMappingContextStack.top
+ }
}
override def characters(ch: Array[Char], start: Int, length: Int): Unit = {
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/DaffodilParseXMLReader.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/DaffodilParseXMLReader.scala
index 71c98af..8bc29d4 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/DaffodilParseXMLReader.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/DaffodilParseXMLReader.scala
@@ -22,8 +22,6 @@ import java.io.InputStream
import java.nio.file.Path
import java.nio.file.Paths
-import scala.collection.mutable
-
import org.apache.daffodil.api.DFDL
import org.apache.daffodil.exceptions.SchemaFileLocation
import org.apache.daffodil.infoset.SAXInfosetOutputter
@@ -34,44 +32,44 @@ import org.xml.sax.DTDHandler
import org.xml.sax.EntityResolver
import org.xml.sax.ErrorHandler
import org.xml.sax.InputSource
+import org.xml.sax.SAXException
import org.xml.sax.SAXNotRecognizedException
import org.xml.sax.SAXNotSupportedException
import org.xml.sax.SAXParseException
+/**
+ * XMLReader implementation that interfaces with the DataProcessor and SAXInfosetOutputter to parse
+ * data into an XML infoset
+ *
+ * @param dp dataprocessor object that will be used to call the parse
+ */
class DaffodilParseXMLReader(dp: DataProcessor) extends DFDL.DaffodilParseXMLReader {
private var contentHandler: ContentHandler = _
private var errorHandler: ErrorHandler = _
private var dtdHandler: DTDHandler = _
private var entityResolver: EntityResolver = _
- var saxParseResultPropertyValue: ParseResult = _
- var saxBlobDirectoryPropertyValue: Path = Paths.get(System.getProperty("java.io.tmpdir"))
- var saxBlobPrefixPropertyValue: String = "daffodil-sax-"
- var saxBlobSuffixPropertyValue: String = ".blob"
-
- private val featureMap = mutable.Map[String, Boolean](
- XMLUtils.SAX_NAMESPACES_FEATURE -> false,
- XMLUtils.SAX_NAMESPACE_PREFIXES_FEATURE -> false
- )
+ private var saxParseResultPropertyValue: ParseResult = _
+ private var saxBlobDirectoryPropertyValue: Path = Paths.get(System.getProperty("java.io.tmpdir"))
+ private var saxBlobPrefixPropertyValue: String = "daffodil-sax-"
+ private var saxBlobSuffixPropertyValue: String = ".blob"
+ private var saxNamespaceFeatureValue: Boolean = true
+ private var saxNamespacePrefixesFeatureValue: Boolean = false
override def getFeature(name: String): Boolean = {
- if (name == XMLUtils.SAX_NAMESPACES_FEATURE ||
- name == XMLUtils.SAX_NAMESPACE_PREFIXES_FEATURE) {
- featureMap(name)
- } else {
- throw new SAXNotRecognizedException("Feature unsupported: " + name + ".\n" +
- "Supported features are: " + featureMap.keys.mkString(", ")
- )
+ name match {
+ case XMLUtils.SAX_NAMESPACES_FEATURE => saxNamespaceFeatureValue
+ case XMLUtils.SAX_NAMESPACE_PREFIXES_FEATURE => saxNamespacePrefixesFeatureValue
+ case _ =>
+ throwFeatureSAXNotRecogizedException(name, "Feature unsupported")
}
}
override def setFeature(name: String, value: Boolean): Unit = {
- if (name == XMLUtils.SAX_NAMESPACES_FEATURE ||
- name == XMLUtils.SAX_NAMESPACE_PREFIXES_FEATURE) {
- featureMap(name) = value
- } else {
- throw new SAXNotRecognizedException("Feature unsupported: " + name + ".\n" +
- "Supported features are: " + featureMap.keys.mkString(", ")
- )
+ name match {
+ case XMLUtils.SAX_NAMESPACES_FEATURE => saxNamespaceFeatureValue = value
+ case XMLUtils.SAX_NAMESPACE_PREFIXES_FEATURE => saxNamespacePrefixesFeatureValue = value
+ case _ =>
+ throwFeatureSAXNotRecogizedException(name, "Feature unsupported")
}
}
@@ -144,7 +142,18 @@ class DaffodilParseXMLReader(dp: DataProcessor) extends DFDL.DaffodilParseXMLRea
}
def parse(isdis: InputSourceDataInputStream): Unit = {
- val sio = createSAXInfosetOutputter(this)
+ // validate that the features are not false/false
+ if (!saxNamespaceFeatureValue && !saxNamespacePrefixesFeatureValue) {
+ throw new SAXException("Illegal State: Namespaces and NamespacePrefixes features cannot both be false")
+ }
+ // creates SAXInfosetOutputter object and calls setBlobAttributes on it
+ val sio = new SAXInfosetOutputter(this,
+ saxNamespaceFeatureValue,
+ saxNamespacePrefixesFeatureValue)
+ sio.setBlobAttributes(saxBlobDirectoryPropertyValue,
+ saxBlobPrefixPropertyValue,
+ saxBlobSuffixPropertyValue
+ )
val pr = dp.parse(isdis, sio)
saxParseResultPropertyValue = pr.asInstanceOf[ParseResult]
handleDiagnostics(pr)
@@ -188,22 +197,10 @@ class DaffodilParseXMLReader(dp: DataProcessor) extends DFDL.DaffodilParseXMLRea
}
}
- /**
- * Creates SAXInfosetOutputter object and attempts to setBlobAttributes on it if
- * it has at least the blobDirectory property set
- *
- * @return SAXInfosetOutputter object with or without blob Attributes set
- */
- private def createSAXInfosetOutputter(xmlReader: DaffodilParseXMLReader): SAXInfosetOutputter = {
- val sioo = new SAXInfosetOutputter(xmlReader)
- val siof = try {
- sioo.setBlobAttributes(saxBlobDirectoryPropertyValue, saxBlobPrefixPropertyValue,
- saxBlobSuffixPropertyValue
- )
- sioo
- } catch {
- case e: SAXNotSupportedException => sioo
- }
- siof
+ def throwFeatureSAXNotRecogizedException(name: String, message: String): Boolean = {
+ throw new SAXNotRecognizedException(message + ": " + name + ".\n" +
+ "Supported features are: " +
+ Seq(XMLUtils.SAX_NAMESPACES_FEATURE,
+ XMLUtils.SAX_NAMESPACE_PREFIXES_FEATURE).mkString(", "))
}
}
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/RuntimeData.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/RuntimeData.scala
index 8e941dd..6e93846 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/RuntimeData.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/RuntimeData.scala
@@ -680,9 +680,11 @@ sealed class ElementRuntimeData(
def isComplexType = !isSimpleType
+ def prefix = this.minimizedScope.getPrefix(namedQName.namespace)
+
def prefixedName = {
- if (namedQName.prefixOrNull != null) {
- namedQName.prefixOrNull + ":" + name
+ if (prefix != null) {
+ prefix + ":" + name
} else {
name
}
diff --git a/daffodil-sapi/src/main/scala/org/apache/daffodil/sapi/package.scala b/daffodil-sapi/src/main/scala/org/apache/daffodil/sapi/package.scala
index 47b1726..0a5076c 100644
--- a/daffodil-sapi/src/main/scala/org/apache/daffodil/sapi/package.scala
+++ b/daffodil-sapi/src/main/scala/org/apache/daffodil/sapi/package.scala
@@ -180,6 +180,11 @@ package org.apache.daffodil
* }
* }}}
*
+ * The value of the supported features cannot be changed during a parse, and the parse will run
+ * with the value of the features as they were when the parse was kicked off. To run a parse with
+ * different feature values, one must wait until the running parse finishes, set the feature values
+ * using the XMLReader's setFeature and run the parse again.
+ *
* One can repeat calls to parse() using the same InputSourceDataInputStream to continue parsing
* where the previous parse ended. For example:
*
diff --git a/daffodil-sapi/src/test/scala/org/apache/daffodil/example/TestScalaAPI.scala b/daffodil-sapi/src/test/scala/org/apache/daffodil/example/TestScalaAPI.scala
index 45791ba..745d4e2 100644
--- a/daffodil-sapi/src/test/scala/org/apache/daffodil/example/TestScalaAPI.scala
+++ b/daffodil-sapi/src/test/scala/org/apache/daffodil/example/TestScalaAPI.scala
@@ -1003,6 +1003,9 @@ class TestScalaAPI {
val outputContentHandler = new org.jdom2.input.sax.SAXHandler()
val errorHandler = new SAXErrorHandlerForSAPITest()
+ // since SAXHandler uses a blank prefix when the below isn't set to true, it introduces
+ // a the no-prefixed xmlns mapping
+ parseXMLReader.setFeature(SAX_NAMESPACE_PREFIXES_FEATURE, true)
parseXMLReader.setContentHandler(outputContentHandler)
parseXMLReader.setErrorHandler(errorHandler)
parseXMLReader.setProperty(DaffodilParseXMLReader.DAFFODIL_SAX_URN_BLOBDIRECTORY,
diff --git a/daffodil-tdml-processor/src/main/scala/org/apache/daffodil/tdml/TDMLInfosetOutputter.scala b/daffodil-tdml-processor/src/main/scala/org/apache/daffodil/tdml/TDMLInfosetOutputter.scala
index 83dc0ae..0259c79 100644
--- a/daffodil-tdml-processor/src/main/scala/org/apache/daffodil/tdml/TDMLInfosetOutputter.scala
+++ b/daffodil-tdml-processor/src/main/scala/org/apache/daffodil/tdml/TDMLInfosetOutputter.scala
@@ -104,6 +104,8 @@ class TDMLInfosetOutputter() extends InfosetOutputter {
def getResult() = scalaOut.getResult
+ def getXmlString() = xmlStream.toString
+
def toInfosetInputter() = {
val scalaIn = new ScalaXMLInfosetInputter(scalaOut.getResult)
val jdomIn = new JDOMInfosetInputter(jdomOut.getResult)
diff --git a/daffodil-tdml-processor/src/main/scala/org/apache/daffodil/tdml/processor/DaffodilTDMLDFDLProcessor.scala b/daffodil-tdml-processor/src/main/scala/org/apache/daffodil/tdml/processor/DaffodilTDMLDFDLProcessor.scala
index 29f1452..2ab8437 100644
--- a/daffodil-tdml-processor/src/main/scala/org/apache/daffodil/tdml/processor/DaffodilTDMLDFDLProcessor.scala
+++ b/daffodil-tdml-processor/src/main/scala/org/apache/daffodil/tdml/processor/DaffodilTDMLDFDLProcessor.scala
@@ -379,14 +379,18 @@ class DaffodilTDMLDFDLProcessor private (private var dp: DataProcessor) extends
}
def verifySameParseOutput(dpOutputter: TDMLInfosetOutputter, outputStream: ByteArrayOutputStream): Unit = {
- val dpParseOutput = dpOutputter.getResult()
+ val dpParseOutputString = dpOutputter.getXmlString()
val saxParseOutputString = outputStream.toString
- val saxParseOutput = scala.xml.XML.loadString(saxParseOutputString)
+ val saxParseXMLNodeOutput = scala.xml.XML.loadString(saxParseOutputString)
+ // scala.xml.XML.loadString reverses the order of the namespace mappings, so we call it for the
+ // dpParseXMLNodeOutput as well so the reversal is mirrored and we can do a proper prefixes and namespaces
+ // comparison. dpOutputter.getOutput returns it in the right order, which is why we don't use it
+ val dpParseXMLNodeOutputReloaded = scala.xml.XML.loadString(dpParseOutputString)
try {
XMLUtils.compareAndReport(
- dpParseOutput,
- saxParseOutput,
+ dpParseXMLNodeOutputReloaded,
+ saxParseXMLNodeOutput,
checkNamespaces = true,
checkPrefixes = true)
} catch {