[Git][java-team/dom4j][upstream] New upstream version 2.1.1
Emmanuel Bourg
gitlab at salsa.debian.org
Mon Jul 30 18:48:34 BST 2018
Emmanuel Bourg pushed to branch upstream at Debian Java Maintainers / dom4j
Commits:
fc1e5d4e by Emmanuel Bourg at 2018-07-30T16:20:03Z
New upstream version 2.1.1
- - - - -
15 changed files:
- .gitignore
- build.gradle
- src/main/java/org/dom4j/DocumentHelper.java
- src/main/java/org/dom4j/Namespace.java
- src/main/java/org/dom4j/QName.java
- src/main/java/org/dom4j/datatype/SchemaParser.java
- src/main/java/org/dom4j/io/SAXHelper.java
- src/main/java/org/dom4j/io/SAXReader.java
- src/main/java/org/dom4j/io/XMLWriter.java
- src/main/java/org/dom4j/tree/QNameCache.java
- + src/test/java/org/dom4j/AllowedCharsTest.java
- src/test/java/org/dom4j/IteratorTest.java
- src/test/java/org/dom4j/XMLWriterTest.java
- src/test/java/org/dom4j/dom/DOMTest.java
- src/test/java/org/dom4j/io/DTDTest.java
Changes:
=====================================
.gitignore
=====================================
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
/build
+/out
/.gradle
/gradle.properties
/.idea/workspace.xml
=====================================
build.gradle
=====================================
--- a/build.gradle
+++ b/build.gradle
@@ -1,6 +1,6 @@
-apply plugin: 'java'
+apply plugin: 'java-library'
apply plugin: 'jacoco'
-apply plugin: 'maven'
+apply plugin: 'maven-publish'
apply plugin: 'signing'
group = 'org.dom4j'
@@ -9,120 +9,129 @@ archivesBaseName = 'dom4j'
sourceCompatibility = 1.8
tasks.withType(JavaCompile) + tasks.withType(Javadoc) {
- options.encoding = 'UTF-8'
- options.charSet = options.encoding
+ options.encoding = 'UTF-8'
+ options.charSet = options.encoding
}
repositories {
- mavenCentral()
+ mavenCentral()
}
dependencies {
- compile(
- 'jaxen:jaxen:1.1.6',
- )
-
- compileOnly(
- 'javax.xml.stream:stax-api:1.0-2',
- 'net.java.dev.msv:xsdlib:2013.6.1',
- 'xpp3:xpp3:1.1.4c',
- 'pull-parser:pull-parser:2',
- 'javax.xml.bind:jaxb-api:2.2.12',
- )
-
-
- testCompile(
- 'org.testng:testng:6.8.21',
-
- 'xerces:xercesImpl:2.11.0',
- 'xalan:xalan:2.7.2',
- )
+ implementation(
+ 'jaxen:jaxen:1.1.6',
+ 'javax.xml.stream:stax-api:1.0-2',
+ 'net.java.dev.msv:xsdlib:2013.6.1',
+ 'javax.xml.bind:jaxb-api:2.2.12',
+ 'pull-parser:pull-parser:2',
+ 'xpp3:xpp3:1.1.4c',
+ )
+
+ testImplementation(
+ 'org.testng:testng:6.8.21',
+
+ 'xerces:xercesImpl:2.11.0',
+ 'xalan:xalan:2.7.2',
+ )
}
sourceSets {
- test {
- compileClasspath += configurations.compileOnly
- runtimeClasspath += configurations.compileOnly
- }
+ test {
+ compileClasspath += configurations.compileOnly
+ runtimeClasspath += configurations.compileOnly
+ }
}
task sourcesJar(type: Jar, dependsOn: classes) {
- classifier = 'sources'
- from sourceSets.main.allSource
+ classifier = 'sources'
+ from sourceSets.main.allSource
}
task javadocJar(type: Jar, dependsOn: javadoc) {
- classifier = 'javadoc'
- from javadoc.destinationDir
+ classifier = 'javadoc'
+ from javadoc.destinationDir
}
-artifacts {
- archives sourcesJar
- archives javadocJar
+publishing {
+ publications {
+ mavenJava(MavenPublication) {
+ from components.java
+
+ artifact sourcesJar {
+ classifier "sources"
+ }
+
+ artifact javadocJar {
+ classifier "javadoc"
+ }
+
+ pom {
+ name = 'dom4j'
+ description = 'flexible XML framework for Java'
+ url = 'http://dom4j.github.io/'
+ licenses {
+ license {
+ name = 'BSD 3-clause New License'
+ url = 'https://github.com/dom4j/dom4j/blob/master/LICENSE'
+ }
+ }
+ developers {
+ developer {
+ name = 'Filip Jirsák'
+ email = 'filip at jirsak.org'
+ url = 'https://github.com/FilipJirsak'
+ }
+ }
+ scm {
+ connection = 'scm:git:git at github.com:dom4j/dom4j.git'
+ developerConnection = 'scm:git:git at github.com:dom4j/dom4j.git'
+ url = 'git at github.com:dom4j/dom4j.git'
+ }
+
+ withXml {
+ asNode().dependencies.dependency.findAll { xmlDep ->
+ xmlDep.appendNode('optional').value = 'true'
+ }
+ }
+ }
+ }
+ }
}
test {
- useTestNG()
+ useTestNG()
}
jacocoTestReport {
- reports {
- xml.enabled true
- }
+ reports {
+ xml.enabled true
+ }
}
check.dependsOn 'jacocoTestReport'
if (project.hasProperty('ossrhUsername') && project.hasProperty('ossrhPassword')) {
- signing {
- sign configurations.archives
- }
-
- uploadArchives {
- repositories {
- mavenDeployer {
- beforeDeployment {
- deployment -> signing.signPom(deployment)
- }
-
- repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
- authentication(userName: ossrhUsername, password: ossrhPassword)
- }
-
- snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") {
- authentication(userName: ossrhUsername, password: ossrhPassword)
- }
-
- pom.project {
- name 'dom4j'
- packaging 'jar'
- description 'flexible XML framework for Java'
- url 'http://dom4j.github.io/'
- licenses {
- license {
- name 'BSD 3-clause New License'
- url 'https://github.com/dom4j/dom4j/blob/master/LICENSE'
- }
- }
- developers {
- developer {
- name 'Filip Jirsák'
- email 'filip at jirsak.org'
- url 'https://github.com/FilipJirsak'
- }
- }
- scm {
- connection 'scm:git:git at github.com:dom4j/dom4j.git'
- developerConnection 'scm:git:git at github.com:dom4j/dom4j.git'
- url 'git at github.com:dom4j/dom4j.git'
- }
- }
- }
- }
- }
+ publishing {
+ repositories {
+ maven {
+ url 'https://oss.sonatype.org/service/local/staging/deploy/maven2/'
+ credentials {
+ username = ossrhUsername
+ password = ossrhPassword
+ }
+ }
+
+// mavenSnapshot{
+// url "https://oss.sonatype.org/content/repositories/snapshots/"
+// authentication(userName: ossrhUsername, password: ossrhPassword)
+// }
+ }
+ }
}
-task wrapper(type: Wrapper) {
- gradleVersion = '4.1'
-}
+if (project.hasProperty('signing.keyId')) {
+ signing {
+ sign configurations.archives
+ }
+}
\ No newline at end of file
=====================================
src/main/java/org/dom4j/DocumentHelper.java
=====================================
--- a/src/main/java/org/dom4j/DocumentHelper.java
+++ b/src/main/java/org/dom4j/DocumentHelper.java
@@ -18,6 +18,7 @@ import org.dom4j.rule.Pattern;
import org.jaxen.VariableContext;
import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
/**
* <code>DocumentHelper</code> is a collection of helper methods for using
@@ -256,6 +257,8 @@ public final class DocumentHelper {
* <code>parseText</code> parses the given text as an XML document and
* returns the newly created Document.
* </p>
+ *
+ * Loading external DTD and entities is disabled (if it is possible) for security reasons.
*
* @param text
* the XML text to be parsed
@@ -267,6 +270,14 @@ public final class DocumentHelper {
*/
public static Document parseText(String text) throws DocumentException {
SAXReader reader = new SAXReader();
+ try {
+ reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
+ reader.setFeature("http://xml.org/sax/features/external-general-entities", false);
+ reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
+ } catch (SAXException e) {
+ //Parse with external resources downloading allowed.
+ }
+
String encoding = getEncoding(text);
InputSource source = new InputSource(new StringReader(text));
=====================================
src/main/java/org/dom4j/Namespace.java
=====================================
--- a/src/main/java/org/dom4j/Namespace.java
+++ b/src/main/java/org/dom4j/Namespace.java
@@ -49,6 +49,10 @@ public class Namespace extends AbstractNode {
public Namespace(String prefix, String uri) {
this.prefix = (prefix != null) ? prefix : "";
this.uri = (uri != null) ? uri : "";
+
+ if (!this.prefix.isEmpty()) {
+ QName.validateNCName(this.prefix);
+ }
}
/**
=====================================
src/main/java/org/dom4j/QName.java
=====================================
--- a/src/main/java/org/dom4j/QName.java
+++ b/src/main/java/org/dom4j/QName.java
@@ -11,6 +11,7 @@ import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
+import java.util.regex.Pattern;
import org.dom4j.tree.QNameCache;
import org.dom4j.util.SingletonStrategy;
@@ -21,11 +22,86 @@ import org.dom4j.util.SingletonStrategy;
* object is immutable.
*
* @author <a href="mailto:jstrachan at apache.org">James Strachan </a>
+ * @author Filip Jirsák
*/
public class QName implements Serializable {
/** The Singleton instance */
private static SingletonStrategy<QNameCache> singleton = null;
+ /**
+ * {@code NameStartChar} without colon.
+ *
+ * <pre>NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]</pre>
+ *
+ * @see <a href="https://www.w3.org/TR/xml/#sec-common-syn">XML 1.0 – 2.3 Common Syntactic Constructs</a>
+ * @see <a href="https://www.w3.org/TR/2006/REC-xml11-20060816/#sec-common-syn">XML 1.1 – 2.3 Common Syntactic Constructs</a>
+ */
+ private static final String NAME_START_CHAR = "_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD";
+
+ /**
+ * {@code NameChar} without colon.
+ *
+ * <pre>NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]</pre>
+ *
+ * @see <a href="https://www.w3.org/TR/xml/#sec-common-syn">XML 1.0 – 2.3 Common Syntactic Constructs</a>
+ * @see <a href="https://www.w3.org/TR/2006/REC-xml11-20060816/#sec-common-syn">XML 1.1 – 2.3 Common Syntactic Constructs</a>
+ */
+ private static final String NAME_CHAR = NAME_START_CHAR + "-.0-9\u00B7\u0300-\u036F\u203F-\u2040";
+
+ /**
+ * {@code NCName}
+ *
+ * <pre>
+ * NCName ::= NCNameStartChar NCNameChar* (An XML Name, minus the ":")
+ * NCNameChar ::= NameChar -':'
+ * NCNameStartChar ::= NameStartChar -':'
+ * </pre>
+ *
+ * @see <a href="https://www.w3.org/TR/xml-names/#ns-qualnames">Namespaces in XML 1.0 – 4 Qualified Names</a>
+ * @see <a href="https://www.w3.org/TR/2006/REC-xml-names11-20060816/#ns-qualnames">Namespaces in XML 1.1 – 4 Qualified Names</a>
+ */
+ private static final String NCNAME = "["+NAME_START_CHAR+"]["+NAME_CHAR+"]*";
+
+ /**
+ * Regular expression for {@code Name} (with colon).
+ *
+ * <pre>Name ::= NameStartChar (NameChar)*</pre>
+ *
+ * @see <a href="https://www.w3.org/TR/xml/#sec-common-syn">XML 1.0 – 2.3 Common Syntactic Constructs</a>
+ * @see <a href="https://www.w3.org/TR/2006/REC-xml11-20060816/#sec-common-syn">XML 1.1 – 2.3 Common Syntactic Constructs</a>
+ */
+ private static final Pattern RE_NAME = Pattern.compile("[:"+NAME_START_CHAR+"][:"+NAME_CHAR+"]*");
+
+ /**
+ * Regular expression for {@code NCName}.
+ *
+ * <pre>
+ * NCName ::= NCNameStartChar NCNameChar* (An XML Name, minus the ":")
+ * NCNameChar ::= NameChar -':'
+ * NCNameStartChar ::= NameStartChar -':'
+ * </pre>
+ *
+ * @see <a href="https://www.w3.org/TR/xml-names/#ns-qualnames">Namespaces in XML 1.0 – 4 Qualified Names</a>
+ * @see <a href="https://www.w3.org/TR/2006/REC-xml-names11-20060816/#ns-qualnames">Namespaces in XML 1.1 – 4 Qualified Names</a>
+ */
+ private static final Pattern RE_NCNAME = Pattern.compile(NCNAME);
+
+ /**
+ * Regular expression for {@code QName}.
+ *
+ * <pre>
+ * QName ::= PrefixedName | UnprefixedName
+ * PrefixedName ::= Prefix ':' LocalPart
+ * UnprefixedName ::= LocalPart
+ * Prefix ::= NCName
+ * LocalPart ::= NCName
+ * </pre>
+ *
+ * @see <a href="https://www.w3.org/TR/xml-names/#ns-qualnames">Namespaces in XML 1.0 – 4 Qualified Names</a>
+ * @see <a href="https://www.w3.org/TR/2006/REC-xml-names11-20060816/#ns-qualnames">Namespaces in XML 1.1 – 4 Qualified Names</a>
+ */
+ private static final Pattern RE_QNAME = Pattern.compile("(?:"+NCNAME+":)?"+NCNAME);
+
static {
try {
String defaultSingletonClass = "org.dom4j.util.SimpleSingleton";
@@ -71,6 +147,11 @@ public class QName implements Serializable {
this.name = (name == null) ? "" : name;
this.namespace = (namespace == null) ? Namespace.NO_NAMESPACE
: namespace;
+ if (this.namespace.equals(Namespace.NO_NAMESPACE)) {
+ validateName(this.name);
+ } else {
+ validateNCName(this.name);
+ }
}
public QName(String name, Namespace namespace, String qualifiedName) {
@@ -78,6 +159,8 @@ public class QName implements Serializable {
this.qualifiedName = qualifiedName;
this.namespace = (namespace == null) ? Namespace.NO_NAMESPACE
: namespace;
+ validateNCName(this.name);
+ validateQName(this.qualifiedName);
}
public static QName get(String name) {
@@ -251,6 +334,24 @@ public class QName implements Serializable {
QNameCache cache = singleton.instance();
return cache;
}
+
+ private static void validateName(String name) {
+ if (!RE_NAME.matcher(name).matches()) {
+ throw new IllegalArgumentException(String.format("Illegal character in name: '%s'.", name));
+ }
+ }
+
+ protected static void validateNCName(String ncname) {
+ if (!RE_NCNAME.matcher(ncname).matches()) {
+ throw new IllegalArgumentException(String.format("Illegal character in local name: '%s'.", ncname));
+ }
+ }
+
+ private static void validateQName(String qname) {
+ if (!RE_QNAME.matcher(qname).matches()) {
+ throw new IllegalArgumentException(String.format("Illegal character in qualified name: '%s'.", qname));
+ }
+ }
}
=====================================
src/main/java/org/dom4j/datatype/SchemaParser.java
=====================================
--- a/src/main/java/org/dom4j/datatype/SchemaParser.java
+++ b/src/main/java/org/dom4j/datatype/SchemaParser.java
@@ -180,15 +180,19 @@ public class SchemaParser {
DocumentFactory parentFactory) {
String name = xsdElement.attributeValue("name");
String type = xsdElement.attributeValue("type");
- QName qname = getQName(name);
- DatatypeElementFactory factory = getDatatypeElementFactory(qname);
+ QName qname = null;
+ DatatypeElementFactory factory = null;
+ if (name != null) {
+ qname = getQName(name);
+ factory = getDatatypeElementFactory(qname);
+ }
if (type != null) {
// register type with this element name
XSDatatype dataType = getTypeByName(type);
- if (dataType != null) {
+ if (dataType != null && factory != null) {
factory.setChildElementXSDatatype(qname, dataType);
} else {
QName typeQName = getQName(type);
@@ -205,24 +209,25 @@ public class SchemaParser {
if (xsdSimpleType != null) {
XSDatatype dataType = loadXSDatatypeFromSimpleType(xsdSimpleType);
- if (dataType != null) {
+ if (dataType != null && factory != null) {
factory.setChildElementXSDatatype(qname, dataType);
}
}
Element schemaComplexType = xsdElement.element(XSD_COMPLEXTYPE);
- if (schemaComplexType != null) {
+ if (schemaComplexType != null && factory != null) {
onSchemaComplexType(schemaComplexType, factory);
}
- Iterator<Element> iter = xsdElement.elementIterator(XSD_ATTRIBUTE);
-
- if (iter.hasNext()) {
- do {
- onDatatypeAttribute(xsdElement, factory, iter
- .next());
- } while (iter.hasNext());
+ if (factory != null) {
+ Iterator<Element> iter = xsdElement.elementIterator(XSD_ATTRIBUTE);
+ if (iter.hasNext()) {
+ do {
+ onDatatypeAttribute(xsdElement, factory, iter
+ .next());
+ } while (iter.hasNext());
+ }
}
}
=====================================
src/main/java/org/dom4j/io/SAXHelper.java
=====================================
--- a/src/main/java/org/dom4j/io/SAXHelper.java
+++ b/src/main/java/org/dom4j/io/SAXHelper.java
@@ -103,6 +103,21 @@ class SAXHelper {
throw new SAXException("Couldn't create SAX reader");
}
+ // configure namespace support
+ SAXHelper.setParserFeature(reader, "http://xml.org/sax/features/namespaces", true);
+ SAXHelper.setParserFeature(reader, "http://xml.org/sax/features/namespace-prefixes", false);
+
+ // external entites
+ SAXHelper.setParserFeature(reader, "http://xml.org/sax/properties/external-general-entities", false);
+ SAXHelper.setParserFeature(reader, "http://xml.org/sax/properties/external-parameter-entities", false);
+
+ // external DTD
+ SAXHelper.setParserFeature(reader,"http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
+
+
+ // use Locator2 if possible
+ SAXHelper.setParserFeature(reader,"http://xml.org/sax/features/use-locator2", true);
+
return reader;
}
=====================================
src/main/java/org/dom4j/io/SAXReader.java
=====================================
--- a/src/main/java/org/dom4j/io/SAXReader.java
+++ b/src/main/java/org/dom4j/io/SAXReader.java
@@ -65,11 +65,7 @@ import org.xml.sax.helpers.XMLReaderFactory;
public class SAXReader {
private static final String SAX_STRING_INTERNING =
"http://xml.org/sax/features/string-interning";
- private static final String SAX_NAMESPACE_PREFIXES =
- "http://xml.org/sax/features/namespace-prefixes";
- private static final String SAX_NAMESPACES =
- "http://xml.org/sax/features/namespaces";
- private static final String SAX_DECL_HANDLER =
+ private static final String SAX_DECL_HANDLER =
"http://xml.org/sax/properties/declaration-handler";
private static final String SAX_LEXICAL_HANDLER =
"http://xml.org/sax/properties/lexical-handler";
@@ -902,27 +898,10 @@ public class SAXReader {
SAXHelper.setParserProperty(reader, SAX_DECL_HANDLER, handler);
}
- // configure namespace support
- SAXHelper.setParserFeature(reader, SAX_NAMESPACES, true);
-
- SAXHelper.setParserFeature(reader, SAX_NAMESPACE_PREFIXES, false);
-
// string interning
SAXHelper.setParserFeature(reader, SAX_STRING_INTERNING,
isStringInternEnabled());
- // external entites
- /*
- * SAXHelper.setParserFeature( reader,
- * "http://xml.org/sax/properties/external-general-entities",
- * includeExternalGeneralEntities ); SAXHelper.setParserFeature( reader,
- * "http://xml.org/sax/properties/external-parameter-entities",
- * includeExternalParameterEntities );
- */
- // use Locator2 if possible
- SAXHelper.setParserFeature(reader,
- "http://xml.org/sax/features/use-locator2", true);
-
try {
// configure validation support
reader.setFeature("http://xml.org/sax/features/validation",
=====================================
src/main/java/org/dom4j/io/XMLWriter.java
=====================================
--- a/src/main/java/org/dom4j/io/XMLWriter.java
+++ b/src/main/java/org/dom4j/io/XMLWriter.java
@@ -574,6 +574,7 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
public void writeOpen(Element element) throws IOException {
writer.write("<");
writer.write(element.getQualifiedName());
+ writeNamespaces(element);
writeAttributes(element);
writer.write(">");
}
@@ -1206,6 +1207,19 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
writer.write("\"");
}
+ /**
+ * Writes all namespaces declared directly on element.
+ *
+ * @throws IOException
+ */
+ protected void writeNamespaces(Element element) throws IOException {
+ assert element != null;
+ for (Namespace ns : element.declaredNamespaces()) {
+ writeNamespace(ns);
+ namespaceStack.push(ns);
+ }
+ }
+
protected void writeProcessingInstruction(ProcessingInstruction pi)
throws IOException {
// indent();
@@ -1631,44 +1645,37 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
for (i = 0; i < size; i++) {
String entity = null;
- char c = text.charAt(i);
+ int c = text.codePointAt(i);
switch (c) {
case '<':
entity = "<";
-
break;
-
case '>':
entity = ">";
-
break;
-
case '&':
entity = "&";
-
break;
-
case '\t':
case '\n':
case '\r':
-
// don't encode standard whitespace characters
if (preserve) {
- entity = String.valueOf(c);
+ entity = String.valueOf((char) c);
}
-
break;
default:
if ((c < 32) || shouldEncodeChar(c)) {
- entity = "&#" + (int) c + ";";
+ entity = "&#" + c + ";";
}
break;
}
+
if (entity != null) {
if (block == null) {
block = text.toCharArray();
@@ -1677,6 +1684,12 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
buffer.append(block, last, i - last);
buffer.append(entity);
last = i + 1;
+ if (Character.isSupplementaryCodePoint(c)) {
+ last++;
+ }
+ }
+ if (Character.isSupplementaryCodePoint(c)) {
+ i++;
}
}
@@ -1725,53 +1738,37 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
for (i = 0; i < size; i++) {
String entity = null;
- char c = text.charAt(i);
+ int c = text.codePointAt(i);
switch (c) {
case '<':
entity = "<";
-
break;
-
case '>':
entity = ">";
-
break;
-
case '\'':
-
if (quote == '\'') {
entity = "'";
}
-
break;
-
case '\"':
-
if (quote == '\"') {
entity = """;
}
-
break;
-
case '&':
entity = "&";
-
break;
-
case '\t':
case '\n':
case '\r':
-
// don't encode standard whitespace characters
break;
-
default:
-
if ((c < 32) || shouldEncodeChar(c)) {
- entity = "&#" + (int) c + ";";
+ entity = "&#" + c + ";";
}
-
break;
}
@@ -1783,6 +1780,12 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
buffer.append(block, last, i - last);
buffer.append(entity);
last = i + 1;
+ if(Character.isSupplementaryCodePoint(c)) {
+ last++;
+ }
+ }
+ if(Character.isSupplementaryCodePoint(c)) {
+ i++;
}
}
@@ -1808,15 +1811,15 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
* Should the given character be escaped. This depends on the encoding of
* the document.
*
- * @param c
+ * @param codepoint Unicode codepoint.
* DOCUMENT ME!
*
* @return boolean
*/
- protected boolean shouldEncodeChar(char c) {
+ protected boolean shouldEncodeChar(int codepoint) {
int max = getMaximumAllowedCharacter();
- return (max > 0) && (c > max);
+ return (max > 0) && (codepoint > max);
}
/**
=====================================
src/main/java/org/dom4j/tree/QNameCache.java
=====================================
--- a/src/main/java/org/dom4j/tree/QNameCache.java
+++ b/src/main/java/org/dom4j/tree/QNameCache.java
@@ -52,11 +52,15 @@ public class QNameCache {
*/
public List<QName> getQNames() {
List<QName> answer = new ArrayList<QName>();
- answer.addAll(noNamespaceCache.values());
+ synchronized(noNamespaceCache) {
+ answer.addAll(noNamespaceCache.values());
+ }
- for (Map<String, QName> map : namespaceCache.values()) {
- answer.addAll(map.values());
- }
+ synchronized(namespaceCache) {
+ for (Map<String, QName> map : namespaceCache.values()) {
+ answer.addAll(map.values());
+ }
+ }
return answer;
}
@@ -152,6 +156,8 @@ public class QNameCache {
if (index < 0) {
return get(qualifiedName, Namespace.get(uri));
+ } else if (index == 0){
+ throw new IllegalArgumentException("Qualified name cannot start with ':'.");
} else {
String name = qualifiedName.substring(index + 1);
String prefix = qualifiedName.substring(0, index);
@@ -295,4 +301,4 @@ public class QNameCache {
* POSSIBILITY OF SUCH DAMAGE.
*
* Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
- */
\ No newline at end of file
+ */
=====================================
src/test/java/org/dom4j/AllowedCharsTest.java
=====================================
--- /dev/null
+++ b/src/test/java/org/dom4j/AllowedCharsTest.java
@@ -0,0 +1,78 @@
+package org.dom4j;
+
+import org.testng.annotations.Test;
+
+/**
+ * @author Filip Jirsák
+ */
+public class AllowedCharsTest {
+ @Test
+ public void localName() {
+ QName.get("element");
+ QName.get(":element");
+ QName.get("elem:ent");
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class)
+ public void localNameFail() {
+ QName.get("!element");
+ }
+
+ @Test
+ public void qname() {
+ QName.get("element", "http://example.com/namespace");
+ QName.get("ns:element", "http://example.com/namespace");
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class)
+ public void qnameFail1() {
+ QName.get("ns:elem:ent", "http://example.com/namespace");
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class)
+ public void qnameFail2() {
+ QName.get(":nselement", "http://example.com/namespace");
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class)
+ public void createElementLT() {
+ DocumentHelper.createElement("element<name");
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class)
+ public void createElementGT() {
+ DocumentHelper.createElement("element>name");
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class)
+ public void createElementAmpersand() {
+ DocumentHelper.createElement("element&name");
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class)
+ public void addElement() {
+ Element root = DocumentHelper.createElement("root");
+ root.addElement("element>name");
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class)
+ public void addElementQualified() {
+ Element root = DocumentHelper.createElement("root");
+ root.addElement("element>name", "http://example.com/namespace");
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class)
+ public void addElementQualifiedPrefix() {
+ Element root = DocumentHelper.createElement("root");
+ root.addElement("ns:element>name", "http://example.com/namespace");
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class)
+ public void addElementPrefix() {
+ Element root = DocumentHelper.createElement("root");
+ root.addElement("ns>:element", "http://example.com/namespace");
+ }
+
+ //TODO It is illegal to create element or attribute with namespace prefix and empty namespace IRI.
+ //See https://www.w3.org/TR/2006/REC-xml-names11-20060816/#scoping
+}
=====================================
src/test/java/org/dom4j/IteratorTest.java
=====================================
--- a/src/test/java/org/dom4j/IteratorTest.java
+++ b/src/test/java/org/dom4j/IteratorTest.java
@@ -31,7 +31,7 @@ public class IteratorTest extends AbstractTestCase {
Element root = iterDocument.addElement("root");
for (int i = 0; i < NUMELE; i++) {
- root.addElement("iterator test").addAttribute("instance",
+ root.addElement("iterator-test").addAttribute("instance",
Integer.toString(i));
}
}
@@ -42,7 +42,7 @@ public class IteratorTest extends AbstractTestCase {
Element root = iterDocument.getRootElement();
assertTrue("Has root element", root != null);
- List elements = root.elements("iterator test");
+ List elements = root.elements("iterator-test");
int elementSize = elements.size();
assertTrue("Root has " + elementSize + " children", (elements != null)
&& (elementSize == NUMELE));
@@ -50,8 +50,8 @@ public class IteratorTest extends AbstractTestCase {
public void testPlainIteration() throws Exception {
Element root = iterDocument.getRootElement();
- List elements = root.elements("iterator test");
- Iterator iter = root.elementIterator("iterator test");
+ List elements = root.elements("iterator-test");
+ Iterator iter = root.elementIterator("iterator-test");
int elementSize = elements.size();
int count = 0;
@@ -69,8 +69,8 @@ public class IteratorTest extends AbstractTestCase {
public void testSkipAlternates() throws Exception {
Element root = iterDocument.getRootElement();
- List elements = root.elements("iterator test");
- Iterator iter = root.elementIterator("iterator test");
+ List elements = root.elements("iterator-test");
+ Iterator iter = root.elementIterator("iterator-test");
int elementSize = elements.size();
int count = 0;
@@ -89,8 +89,8 @@ public class IteratorTest extends AbstractTestCase {
public void testNoHasNext() throws Exception {
Element root = iterDocument.getRootElement();
- List elements = root.elements("iterator test");
- Iterator iter = root.elementIterator("iterator test");
+ List elements = root.elements("iterator-test");
+ Iterator iter = root.elementIterator("iterator-test");
int elementSize = elements.size();
int count = 0;
Element e = null;
@@ -121,8 +121,8 @@ public class IteratorTest extends AbstractTestCase {
public void testExtraHasNexts() throws Exception {
Element root = iterDocument.getRootElement();
- List elements = root.elements("iterator test");
- Iterator iter = root.elementIterator("iterator test");
+ List elements = root.elements("iterator-test");
+ Iterator iter = root.elementIterator("iterator-test");
int elementSize = elements.size();
int count = 0;
=====================================
src/test/java/org/dom4j/XMLWriterTest.java
=====================================
--- a/src/test/java/org/dom4j/XMLWriterTest.java
+++ b/src/test/java/org/dom4j/XMLWriterTest.java
@@ -14,6 +14,7 @@ import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.dom4j.tree.BaseElement;
import org.dom4j.tree.DefaultDocument;
+import org.testng.Assert;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
@@ -577,6 +578,115 @@ public class XMLWriterTest extends AbstractTestCase {
new XMLWriter(new CharArrayWriter(128), format).write(element);
}
+ public void testElementNamespaceWriteDocument() throws IOException {
+ Document document = DocumentHelper.createDocument();
+ Element root = document.addElement("rss")
+ .addNamespace("g", "http://base.google.com/ns/1.0")
+ .addNamespace("c", "http://base.google.com/cns/1.0");
+
+ OutputFormat outputFormat = OutputFormat.createCompactFormat();
+ outputFormat.setSuppressDeclaration(true);
+
+ StringWriter stringWriter = new StringWriter();
+ XMLWriter writer = new XMLWriter(stringWriter, outputFormat);
+ writer.write(document);
+ writer.close();
+
+ Assert.assertEquals(stringWriter.toString(), "<rss xmlns:g=\"http://base.google.com/ns/1.0\" xmlns:c=\"http://base.google.com/cns/1.0\"></rss>");
+ }
+
+ public void testElementNamespaceWriteOpen() throws IOException {
+ Document document = DocumentHelper.createDocument();
+ Element root = document.addElement("rss")
+ .addNamespace("g", "http://base.google.com/ns/1.0")
+ .addNamespace("c", "http://base.google.com/cns/1.0");
+
+ OutputFormat outputFormat = OutputFormat.createCompactFormat();
+ outputFormat.setSuppressDeclaration(true);
+
+ StringWriter stringWriter = new StringWriter();
+ XMLWriter writer = new XMLWriter(stringWriter, outputFormat);
+ writer.writeOpen(root);
+ writer.close();
+
+ Assert.assertEquals(stringWriter.toString(), "<rss xmlns:g=\"http://base.google.com/ns/1.0\" xmlns:c=\"http://base.google.com/cns/1.0\">");
+ }
+
+ public void testElementNamespaceAttributesWriteOpen() throws IOException {
+ Document document = DocumentHelper.createDocument();
+ Element root = document.addElement("rss")
+ .addNamespace("g", "http://base.google.com/ns/1.0")
+ .addNamespace("c", "http://base.google.com/cns/1.0");
+ root.addAttribute("nons", "value");
+ root.addAttribute(QName.get("g:ns"), "value");
+
+ OutputFormat outputFormat = OutputFormat.createCompactFormat();
+ outputFormat.setSuppressDeclaration(true);
+
+ StringWriter stringWriter = new StringWriter();
+ XMLWriter writer = new XMLWriter(stringWriter, outputFormat);
+ writer.writeOpen(root);
+ writer.close();
+
+ Assert.assertEquals(stringWriter.toString(), "<rss xmlns:g=\"http://base.google.com/ns/1.0\" xmlns:c=\"http://base.google.com/cns/1.0\" nons=\"value\" g:ns=\"value\">");
+ }
+
+ public void testPenguin() throws IOException {
+ // U+1F427 PENGUIN
+ final String penguin = "\ud83d\udc27";
+
+ Document document = DocumentHelper.createDocument();
+ document.addElement("doc").setText(penguin);
+
+ OutputFormat outputFormat = OutputFormat.createCompactFormat();
+ outputFormat.setSuppressDeclaration(true);
+
+ StringWriter stringWriter = new StringWriter();
+ XMLWriter writer = new XMLWriter(stringWriter, outputFormat);
+ writer.write(document);
+ writer.close();
+
+ Assert.assertEquals(stringWriter.toString(), "<doc>"+penguin+"</doc>");
+ }
+
+ public void testSurrogatePairElement() throws IOException {
+ // U+1F427 PENGUIN
+ final String penguin = "\ud83d\udc27";
+
+ Document document = DocumentHelper.createDocument();
+ document.addElement("doc").setText(penguin);
+
+ OutputFormat outputFormat = OutputFormat.createCompactFormat();
+ outputFormat.setSuppressDeclaration(true);
+ outputFormat.setEncoding("US-ASCII");
+
+ StringWriter stringWriter = new StringWriter();
+ XMLWriter writer = new XMLWriter(stringWriter, outputFormat);
+ writer.write(document);
+ writer.close();
+
+ Assert.assertEquals(stringWriter.toString(), "<doc>🐧</doc>");
+ }
+
+ public void testSurrogatePairAttribute() throws IOException {
+ // U+1F427 PENGUIN
+ final String penguin = "\ud83d\udc27";
+
+ Document document = DocumentHelper.createDocument();
+ document.addElement("doc").addAttribute("penguin", penguin);
+
+ OutputFormat outputFormat = OutputFormat.createCompactFormat();
+ outputFormat.setSuppressDeclaration(true);
+ outputFormat.setEncoding("US-ASCII");
+
+ StringWriter stringWriter = new StringWriter();
+ XMLWriter writer = new XMLWriter(stringWriter, outputFormat);
+ writer.write(document);
+ writer.close();
+
+ Assert.assertEquals(stringWriter.toString(), "<doc penguin=\"🐧\"/>");
+ }
+
protected void generateXML(ContentHandler handler) throws SAXException {
handler.startDocument();
=====================================
src/test/java/org/dom4j/dom/DOMTest.java
=====================================
--- a/src/test/java/org/dom4j/dom/DOMTest.java
+++ b/src/test/java/org/dom4j/dom/DOMTest.java
@@ -109,7 +109,7 @@ public class DOMTest extends AbstractTestCase {
assertEquals(newFirst, firstChild);
/* try to replace a node that doesn't exist */
- org.w3c.dom.Element badNode = document.createElement("No Child");
+ org.w3c.dom.Element badNode = document.createElement("No-Child");
try {
parent.replaceChild(newFirst, badNode);
=====================================
src/test/java/org/dom4j/io/DTDTest.java
=====================================
--- a/src/test/java/org/dom4j/io/DTDTest.java
+++ b/src/test/java/org/dom4j/io/DTDTest.java
@@ -445,6 +445,8 @@ public class DTDTest extends AbstractTestCase {
reader.setEntityResolver(new MyEntityResolver(DTD_FILE,
DTD_PUBLICID, DTD_SYSTEM_ID));
+ reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", true);
+
return getDocument(resourceName, reader);
}
View it on GitLab: https://salsa.debian.org/java-team/dom4j/commit/fc1e5d4e924148668e94a9d48263a180b7231875
--
View it on GitLab: https://salsa.debian.org/java-team/dom4j/commit/fc1e5d4e924148668e94a9d48263a180b7231875
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20180730/eeb00786/attachment.html>
More information about the pkg-java-commits
mailing list