Skip to content

Commit 0ff5588

Browse files
authored
Merge pull request #659 from dubinsky/retain-systemId
Retain SystemId
2 parents 42a59a8 + aac142a commit 0ff5588

File tree

3 files changed

+69
-61
lines changed

3 files changed

+69
-61
lines changed

Diff for: jvm/src/test/scala/scala/xml/XMLTest.scala

+17-9
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ class XMLTestJVM {
2424
def Elem(prefix: String, label: String, attributes: MetaData, scope: NamespaceBinding, child: Node*): Elem =
2525
scala.xml.Elem.apply(prefix, label, attributes, scope, minimizeEmpty = true, child: _*)
2626

27-
lazy val parsedxml1: Elem = XML.load(new InputSource(new StringReader("<hello><world/></hello>")))
28-
lazy val parsedxml11: Elem = XML.load(new InputSource(new StringReader("<hello><world/></hello>")))
27+
lazy val parsedxml1: Elem = XML.loadString("<hello><world/></hello>")
28+
lazy val parsedxml11: Elem = XML.loadString("<hello><world/></hello>")
2929
val xmlFile2: String = "<bib><book><author>Peter Buneman</author><author>Dan Suciu</author><title>Data on ze web</title></book><book><author>John Mitchell</author><title>Foundations of Programming Languages</title></book></bib>"
30-
lazy val parsedxml2: Elem = XML.load(new InputSource(new StringReader(xmlFile2)))
30+
lazy val parsedxml2: Elem = XML.loadString(xmlFile2)
3131

3232
@UnitTest
3333
def equality(): Unit = {
@@ -46,9 +46,7 @@ class XMLTestJVM {
4646
assertTrue(Array(parsedxml1).toList sameElements List(parsedxml11))
4747

4848
val x2: String = "<book><author>Peter Buneman</author><author>Dan Suciu</author><title>Data on ze web</title></book>"
49-
50-
val i: InputSource = new InputSource(new StringReader(x2))
51-
val x2p: Elem = XML.load(i)
49+
val x2p: Elem = XML.loadString(x2)
5250

5351
assertEquals(Elem(null, "book", e, sc,
5452
Elem(null, "author", e, sc, Text("Peter Buneman")),
@@ -146,8 +144,7 @@ class XMLTestJVM {
146144
val xmlAttrValueNorm: String = "<personne id='p0003' nom='&#x015e;ahingšz' />"
147145

148146
{
149-
val isrcA: InputSource = new InputSource(new StringReader(xmlAttrValueNorm))
150-
val parsedxmlA: Elem = XML.load(isrcA)
147+
val parsedxmlA: Elem = XML.loadString(xmlAttrValueNorm)
151148
val c: Char = (parsedxmlA \ "@nom").text.charAt(0)
152149
assertTrue(c == '\u015e')
153150
}
@@ -689,6 +686,17 @@ class XMLTestJVM {
689686
assertTrue(gotAnError)
690687
}
691688

689+
// Here we see that opening InputStream prematurely, as was done previously, breaks XInclude.
690+
@UnitTest(expected = classOf[org.xml.sax.SAXParseException]) def xIncludeNeedsSystemId(): Unit = {
691+
val parserFactory = xercesInternal
692+
parserFactory.setNamespaceAware(true)
693+
parserFactory.setXIncludeAware(true)
694+
XML
695+
.withSAXParser(parserFactory.newSAXParser)
696+
.load(getClass.getResource("site.xml").openStream())
697+
.toString
698+
}
699+
692700
// Now that we can use XML parser configured to be namespace-aware,
693701
// we can also configure it to be XInclude-aware and process XML Includes:
694702
def check(
@@ -700,7 +708,7 @@ class XMLTestJVM {
700708
parserFactory.setXIncludeAware(true)
701709
val actual: String = XML
702710
.withSAXParser(parserFactory.newSAXParser)
703-
.load(getClass.getResource(resourceName).toString)
711+
.load(getClass.getResource(resourceName))
704712
.toString
705713

706714
assertEquals(expected, actual)

Diff for: shared/src/main/scala/scala/xml/XML.scala

+5-5
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ import java.nio.channels.Channels
1919
import scala.util.control.Exception.ultimately
2020

2121
object Source {
22-
def fromFile(file: File): InputSource = new InputSource(new FileInputStream(file))
23-
def fromFile(fd: FileDescriptor): InputSource = new InputSource(new FileInputStream(fd))
24-
def fromFile(name: String): InputSource = new InputSource(new FileInputStream(name))
25-
22+
def fromFile(name: String): InputSource = fromFile(new File(name))
23+
def fromFile(file: File): InputSource = fromUrl(file.toURI.toURL)
24+
def fromUrl(url: java.net.URL): InputSource = fromSysId(url.toString)
25+
def fromSysId(sysID: String): InputSource = new InputSource(sysID)
26+
def fromFile(fd: FileDescriptor): InputSource = fromInputStream(new FileInputStream(fd))
2627
def fromInputStream(is: InputStream): InputSource = new InputSource(is)
2728
def fromReader(reader: Reader): InputSource = new InputSource(reader)
28-
def fromSysId(sysID: String): InputSource = new InputSource(sysID)
2929
def fromString(string: String): InputSource = fromReader(new StringReader(string))
3030
}
3131

Diff for: shared/src/main/scala/scala/xml/factory/XMLLoader.scala

+47-47
Original file line numberDiff line numberDiff line change
@@ -14,32 +14,36 @@ package scala
1414
package xml
1515
package factory
1616

17-
import org.xml.sax.{SAXNotRecognizedException, XMLReader}
17+
import org.xml.sax.{SAXNotRecognizedException, SAXNotSupportedException, XMLReader}
1818
import javax.xml.parsers.SAXParserFactory
1919
import parsing.{FactoryAdapter, NoBindingFactoryAdapter}
2020
import java.io.{File, FileDescriptor, InputStream, Reader}
2121
import java.net.URL
2222

2323
/**
2424
* Presents collection of XML loading methods which use the parser
25-
* created by "def parser".
25+
* created by "def parser" or the reader created by "def reader".
2626
*/
2727
trait XMLLoader[T <: Node] {
2828
import scala.xml.Source._
2929
def adapter: FactoryAdapter = new NoBindingFactoryAdapter()
3030

31+
private def setSafeDefaults(parserFactory: SAXParserFactory): Unit = {
32+
parserFactory.setFeature("http://javax.xml.XMLConstants/feature/secure-processing", true)
33+
parserFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false)
34+
parserFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true)
35+
parserFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false)
36+
parserFactory.setFeature("http://xml.org/sax/features/external-general-entities", false)
37+
parserFactory.setFeature("http://xml.org/sax/features/resolve-dtd-uris", false)
38+
parserFactory.setXIncludeAware(false)
39+
parserFactory.setNamespaceAware(false)
40+
}
41+
3142
private lazy val parserInstance: ThreadLocal[SAXParser] = new ThreadLocal[SAXParser] {
3243
override def initialValue: SAXParser = {
33-
val parser: SAXParserFactory = SAXParserFactory.newInstance
34-
parser.setFeature("http://javax.xml.XMLConstants/feature/secure-processing", true)
35-
parser.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false)
36-
parser.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true)
37-
parser.setFeature("http://xml.org/sax/features/external-parameter-entities", false)
38-
parser.setFeature("http://xml.org/sax/features/external-general-entities", false)
39-
parser.setFeature("http://xml.org/sax/features/resolve-dtd-uris", false)
40-
parser.setXIncludeAware(false)
41-
parser.setNamespaceAware(false)
42-
parser.newSAXParser
44+
val parserFactory: SAXParserFactory = SAXParserFactory.newInstance
45+
setSafeDefaults(parserFactory)
46+
parserFactory.newSAXParser
4347
}
4448
}
4549

@@ -51,72 +55,68 @@ trait XMLLoader[T <: Node] {
5155

5256
/**
5357
* Loads XML from the given InputSource, using the supplied parser.
54-
* The methods available in scala.xml.XML use the XML parser in the JDK.
58+
* The methods available in scala.xml.XML use the XML parser in the JDK
59+
* (unless another parser is present on the classpath).
5560
*/
56-
def loadXML(source: InputSource, parser: SAXParser): T = loadXML(source, parser.getXMLReader)
61+
def loadXML(inputSource: InputSource, parser: SAXParser): T = loadXML(inputSource, parser.getXMLReader)
5762

58-
def loadXMLNodes(source: InputSource, parser: SAXParser): Seq[Node] = loadXMLNodes(source, parser.getXMLReader)
63+
def loadXMLNodes(inputSource: InputSource, parser: SAXParser): Seq[Node] = loadXMLNodes(inputSource, parser.getXMLReader)
5964

60-
private def loadXML(source: InputSource, reader: XMLReader): T = {
61-
val result: FactoryAdapter = parse(source, reader)
65+
private def loadXML(inputSource: InputSource, reader: XMLReader): T = {
66+
val result: FactoryAdapter = parse(inputSource, reader)
6267
result.rootElem.asInstanceOf[T]
6368
}
64-
65-
private def loadXMLNodes(source: InputSource, reader: XMLReader): Seq[Node] = {
66-
val result: FactoryAdapter = parse(source, reader)
69+
70+
private def loadXMLNodes(inputSource: InputSource, reader: XMLReader): Seq[Node] = {
71+
val result: FactoryAdapter = parse(inputSource, reader)
6772
result.prolog ++ (result.rootElem :: result.epilogue)
6873
}
6974

70-
private def parse(source: InputSource, reader: XMLReader): FactoryAdapter = {
71-
if (source == null) throw new IllegalArgumentException("InputSource cannot be null")
75+
private def parse(inputSource: InputSource, xmlReader: XMLReader): FactoryAdapter = {
76+
if (inputSource == null) throw new IllegalArgumentException("InputSource cannot be null")
7277

7378
val result: FactoryAdapter = adapter
7479

75-
reader.setContentHandler(result)
76-
reader.setDTDHandler(result)
80+
xmlReader.setContentHandler(result)
81+
xmlReader.setDTDHandler(result)
7782
/* Do not overwrite pre-configured EntityResolver. */
78-
if (reader.getEntityResolver == null) reader.setEntityResolver(result)
83+
if (xmlReader.getEntityResolver == null) xmlReader.setEntityResolver(result)
7984
/* Do not overwrite pre-configured ErrorHandler. */
80-
if (reader.getErrorHandler == null) reader.setErrorHandler(result)
85+
if (xmlReader.getErrorHandler == null) xmlReader.setErrorHandler(result)
8186

8287
try {
83-
reader.setProperty("http://xml.org/sax/properties/lexical-handler", result)
88+
xmlReader.setProperty("http://xml.org/sax/properties/lexical-handler", result)
8489
} catch {
8590
case _: SAXNotRecognizedException =>
91+
case _: SAXNotSupportedException =>
8692
}
8793

8894
result.scopeStack = TopScope :: result.scopeStack
89-
reader.parse(source)
95+
xmlReader.parse(inputSource)
9096
result.scopeStack = result.scopeStack.tail
9197

9298
result
9399
}
94100

95-
/** loads XML from given InputSource. */
96-
def load(source: InputSource): T = loadXML(source, reader)
97-
98-
/** Loads XML from the given file, file descriptor, or filename. */
101+
/** Loads XML. */
102+
def load(inputSource: InputSource): T = loadXML(inputSource, reader)
103+
def loadFile(fileName: String): T = load(fromFile(fileName))
99104
def loadFile(file: File): T = load(fromFile(file))
100-
def loadFile(fd: FileDescriptor): T = load(fromFile(fd))
101-
def loadFile(name: String): T = load(fromFile(name))
102-
103-
/** loads XML from given InputStream, Reader, sysID, or URL. */
104-
def load(is: InputStream): T = load(fromInputStream(is))
105+
def load(url: URL): T = load(fromUrl(url))
106+
def load(sysId: String): T = load(fromSysId(sysId))
107+
def loadFile(fileDescriptor: FileDescriptor): T = load(fromFile(fileDescriptor))
108+
def load(inputStream: InputStream): T = load(fromInputStream(inputStream))
105109
def load(reader: Reader): T = load(fromReader(reader))
106-
def load(sysID: String): T = load(fromSysId(sysID))
107-
def load(url: URL): T = load(fromInputStream(url.openStream()))
108-
109-
/** Loads XML from the given String. */
110110
def loadString(string: String): T = load(fromString(string))
111111

112112
/** Load XML nodes, including comments and processing instructions that precede and follow the root element. */
113-
def loadNodes(source: InputSource): Seq[Node] = loadXMLNodes(source, reader)
113+
def loadNodes(inputSource: InputSource): Seq[Node] = loadXMLNodes(inputSource, reader)
114+
def loadFileNodes(fileName: String): Seq[Node] = loadNodes(fromFile(fileName))
114115
def loadFileNodes(file: File): Seq[Node] = loadNodes(fromFile(file))
115-
def loadFileNodes(fd: FileDescriptor): Seq[Node] = loadNodes(fromFile(fd))
116-
def loadFileNodes(name: String): Seq[Node] = loadNodes(fromFile(name))
117-
def loadNodes(is: InputStream): Seq[Node] = loadNodes(fromInputStream(is))
116+
def loadNodes(url: URL): Seq[Node] = loadNodes(fromUrl(url))
117+
def loadNodes(sysId: String): Seq[Node] = loadNodes(fromSysId(sysId))
118+
def loadFileNodes(fileDescriptor: FileDescriptor): Seq[Node] = loadNodes(fromFile(fileDescriptor))
119+
def loadNodes(inputStream: InputStream): Seq[Node] = loadNodes(fromInputStream(inputStream))
118120
def loadNodes(reader: Reader): Seq[Node] = loadNodes(fromReader(reader))
119-
def loadNodes(sysID: String): Seq[Node] = loadNodes(fromSysId(sysID))
120-
def loadNodes(url: URL): Seq[Node] = loadNodes(fromInputStream(url.openStream()))
121121
def loadStringNodes(string: String): Seq[Node] = loadNodes(fromString(string))
122122
}

0 commit comments

Comments
 (0)