diff --git a/build.sbt b/build.sbt
index eb8ab9b6..9bc3a309 100644
--- a/build.sbt
+++ b/build.sbt
@@ -69,14 +69,12 @@ lazy val xml = crossProject(JSPlatform, JVMPlatform, NativePlatform)
// to previous-version artifacts that were built on 8. see scala/scala-xml#501
exclude[DirectMissingMethodProblem]("scala.xml.include.sax.XIncluder.declaration"),
- // caused by the switch from DefaultHandler to DefaultHandler2:
- exclude[MissingTypesProblem]("scala.xml.parsing.FactoryAdapter"),
- exclude[MissingTypesProblem]("scala.xml.parsing.NoBindingFactoryAdapter"),
+ // necessitated by the switch from DefaultHandler to DefaultHandler2 in FactoryAdapter:
+ exclude[MissingTypesProblem]("scala.xml.parsing.FactoryAdapter"), // see #549
- exclude[DirectMissingMethodProblem]("scala.xml.parsing.FactoryAdapter.comment"),
- exclude[ReversedMissingMethodProblem]("scala.xml.parsing.FactoryAdapter.createComment"),
- exclude[DirectMissingMethodProblem]("scala.xml.parsing.FactoryAdapter.createComment"),
- exclude[DirectMissingMethodProblem]("scala.xml.parsing.NoBindingFactoryAdapter.createComment")
+ // necessitated by the introduction of new abstract methods in FactoryAdapter:
+ exclude[ReversedMissingMethodProblem]("scala.xml.parsing.FactoryAdapter.createComment"), // see #549
+ exclude[ReversedMissingMethodProblem]("scala.xml.parsing.FactoryAdapter.createPCData") // see #558
)
},
diff --git a/jvm/src/test/scala/scala/xml/XMLTest.scala b/jvm/src/test/scala/scala/xml/XMLTest.scala
index 70b59a92..23dae29a 100644
--- a/jvm/src/test/scala/scala/xml/XMLTest.scala
+++ b/jvm/src/test/scala/scala/xml/XMLTest.scala
@@ -580,13 +580,23 @@ class XMLTestJVM {
XML.loadString(broken)
}
+ def roundtrip(xml: String): Unit = assertEquals(xml, XML.loadString(xml).toString)
+
@UnitTest
- def issue508: Unit = {
- def check(xml: String): Unit = assertEquals(xml, XML.loadString(xml).toString)
+ def issue508commentParsing: Unit = {
+ // confirm that comments are processed correctly now
+ roundtrip(" suffix")
+ roundtrip("prefix suffix")
+ roundtrip("prefix suffix")
+ roundtrip("prefix suffix")
+ roundtrip("""prefix suffix""".stripMargin)
- check(" suffix")
- check("prefix suffix")
- check("prefix suffix")
+ // confirm that processing instructions were always processed correctly
+ roundtrip(" suffix")
+ roundtrip("prefix suffix")
+ roundtrip("prefix suffix")
// TODO since XMLLoader retrieves FactoryAdapter.rootNode,
// capturing comments before and after the root element is not currently possible
@@ -595,6 +605,17 @@ class XMLTestJVM {
//check("text")
}
+ @UnitTest
+ def cdataParsing: Unit = {
+ roundtrip(" suffix")
+ roundtrip("prefix suffix")
+ roundtrip("prefix suffix")
+ roundtrip("""prefix suffix""".stripMargin)
+ }
+
@UnitTest
def nodeSeqNs: Unit = {
val x = {
diff --git a/shared/src/main/scala/scala/xml/factory/NodeFactory.scala b/shared/src/main/scala/scala/xml/factory/NodeFactory.scala
index 7ae0fd7e..c6b1704b 100644
--- a/shared/src/main/scala/scala/xml/factory/NodeFactory.scala
+++ b/shared/src/main/scala/scala/xml/factory/NodeFactory.scala
@@ -56,6 +56,8 @@ trait NodeFactory[A <: Node] {
}
def makeText(s: String): Text = Text(s)
+ def makePCData(s: String): PCData =
+ PCData(s)
def makeComment(s: String): Seq[Comment] =
if (ignoreComments) Nil else List(Comment(s))
def makeProcInstr(t: String, s: String): Seq[ProcInstr] =
diff --git a/shared/src/main/scala/scala/xml/parsing/FactoryAdapter.scala b/shared/src/main/scala/scala/xml/parsing/FactoryAdapter.scala
index c6c8849d..1ac7e9f0 100644
--- a/shared/src/main/scala/scala/xml/parsing/FactoryAdapter.scala
+++ b/shared/src/main/scala/scala/xml/parsing/FactoryAdapter.scala
@@ -43,6 +43,8 @@ abstract class FactoryAdapter extends DefaultHandler2 with factory.XMLLoader[Nod
var rootElem: Node = _
val buffer = new StringBuilder()
+ private var inCDATA: Boolean = false
+
/** List of attributes
*
* Previously was a mutable [[scala.collection.mutable.Stack Stack]], but is now a mutable reference to an immutable [[scala.collection.immutable.List List]].
@@ -100,6 +102,13 @@ abstract class FactoryAdapter extends DefaultHandler2 with factory.XMLLoader[Nod
*/
def createText(text: String): Text // abstract
+ /**
+ * creates a PCData node.
+ * @param text
+ * @return a new PCData node.
+ */
+ def createPCData(text: String): PCData // abstract
+
/**
* creates a new processing instruction node.
*/
@@ -117,7 +126,7 @@ abstract class FactoryAdapter extends DefaultHandler2 with factory.XMLLoader[Nod
val normalizeWhitespace = false
/**
- * Characters.
+ * Capture characters, possibly normalizing whitespace.
* @param ch
* @param offset
* @param length
@@ -139,7 +148,20 @@ abstract class FactoryAdapter extends DefaultHandler2 with factory.XMLLoader[Nod
}
}
- private def splitName(s: String) = {
+ /**
+ * Start of a CDATA section.
+ */
+ override def startCDATA(): Unit = {
+ captureText()
+ inCDATA = true
+ }
+
+ /**
+ * End of a CDATA section.
+ */
+ override def endCDATA(): Unit = captureText()
+
+ private def splitName(s: String): (String, String) = {
val idx = s indexOf ':'
if (idx < 0) (null, s)
else (s take idx, s drop (idx + 1))
@@ -185,13 +207,17 @@ abstract class FactoryAdapter extends DefaultHandler2 with factory.XMLLoader[Nod
}
/**
- * captures text, possibly normalizing whitespace
+ * Captures text or cdata.
*/
def captureText(): Unit = {
- if (capture && buffer.nonEmpty)
- hStack = createText(buffer.toString) :: hStack
+ if (capture && buffer.nonEmpty) {
+ val text: String = buffer.toString
+ val newNode: Node = if (inCDATA) createPCData(text) else createText(text)
+ hStack = newNode :: hStack
+ }
buffer.clear()
+ inCDATA = false
}
/**
@@ -232,6 +258,9 @@ abstract class FactoryAdapter extends DefaultHandler2 with factory.XMLLoader[Nod
hStack = hStack.reverse_:::(createProcInstr(target, data).toList)
}
+ /**
+ * Comment.
+ */
override def comment(ch: Array[Char], start: Int, length: Int): Unit = {
captureText()
val commentText: String = String.valueOf(ch.slice(start, start + length))
diff --git a/shared/src/main/scala/scala/xml/parsing/NoBindingFactoryAdapter.scala b/shared/src/main/scala/scala/xml/parsing/NoBindingFactoryAdapter.scala
index 6f1384fc..9e5e0a5c 100644
--- a/shared/src/main/scala/scala/xml/parsing/NoBindingFactoryAdapter.scala
+++ b/shared/src/main/scala/scala/xml/parsing/NoBindingFactoryAdapter.scala
@@ -42,4 +42,7 @@ class NoBindingFactoryAdapter extends FactoryAdapter with NodeFactory[Elem] {
/** Creates a comment. */
override def createComment(characters: String): Seq[Comment] = makeComment(characters)
+
+ /** Creates a cdata. */
+ override def createPCData(characters: String): PCData = makePCData(characters)
}
diff --git a/shared/src/test/scala/scala/xml/CommentTest.scala b/shared/src/test/scala/scala/xml/CommentTest.scala
index 3e7d1147..0e077a96 100644
--- a/shared/src/test/scala/scala/xml/CommentTest.scala
+++ b/shared/src/test/scala/scala/xml/CommentTest.scala
@@ -1,7 +1,6 @@
package scala.xml
import org.junit.Assert.assertEquals
-import org.junit.Assert.assertTrue
import org.junit.Test
final class CommentTest {