Improved StAX<->SAX bridge
Improved the SAX to StAX (and vice-versa) bridge exposed via StaxUtils. The old integration had some issues with namespace declaration attributes, brought to light in a XMLUnit upgrade. Issue: SPR-11549
This commit is contained in:
parent
a2f1169e82
commit
f2f355e76c
10
build.gradle
10
build.gradle
|
@ -242,7 +242,7 @@ project("spring-core") {
|
||||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||||
optional("net.sf.jopt-simple:jopt-simple:4.6")
|
optional("net.sf.jopt-simple:jopt-simple:4.6")
|
||||||
optional("log4j:log4j:1.2.17")
|
optional("log4j:log4j:1.2.17")
|
||||||
testCompile("xmlunit:xmlunit:1.3")
|
testCompile("xmlunit:xmlunit:1.5")
|
||||||
testCompile("org.codehaus.woodstox:wstx-asl:3.2.7") {
|
testCompile("org.codehaus.woodstox:wstx-asl:3.2.7") {
|
||||||
exclude group: "stax", module: "stax-api"
|
exclude group: "stax", module: "stax-api"
|
||||||
}
|
}
|
||||||
|
@ -460,7 +460,7 @@ project("spring-oxm") {
|
||||||
optional("org.codehaus.castor:castor-xml:1.3.2")
|
optional("org.codehaus.castor:castor-xml:1.3.2")
|
||||||
testCompile(project(":spring-context"))
|
testCompile(project(":spring-context"))
|
||||||
testCompile("org.codehaus.jettison:jettison:1.0.1")
|
testCompile("org.codehaus.jettison:jettison:1.0.1")
|
||||||
testCompile("xmlunit:xmlunit:1.3")
|
testCompile("xmlunit:xmlunit:1.5")
|
||||||
testCompile("xmlpull:xmlpull:1.1.3.4a")
|
testCompile("xmlpull:xmlpull:1.1.3.4a")
|
||||||
testCompile(files(genCastor.classesDir).builtBy(genCastor))
|
testCompile(files(genCastor.classesDir).builtBy(genCastor))
|
||||||
testCompile(files(genJaxb.classesDir).builtBy(genJaxb))
|
testCompile(files(genJaxb.classesDir).builtBy(genJaxb))
|
||||||
|
@ -567,7 +567,7 @@ project("spring-web") {
|
||||||
}
|
}
|
||||||
optional("log4j:log4j:1.2.17")
|
optional("log4j:log4j:1.2.17")
|
||||||
testCompile(project(":spring-context-support")) // for JafMediaTypeFactory
|
testCompile(project(":spring-context-support")) // for JafMediaTypeFactory
|
||||||
testCompile("xmlunit:xmlunit:1.3")
|
testCompile("xmlunit:xmlunit:1.5")
|
||||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -703,7 +703,7 @@ project("spring-webmvc") {
|
||||||
}
|
}
|
||||||
testCompile(project(":spring-aop"))
|
testCompile(project(":spring-aop"))
|
||||||
testCompile("rhino:js:1.7R1")
|
testCompile("rhino:js:1.7R1")
|
||||||
testCompile("xmlunit:xmlunit:1.3")
|
testCompile("xmlunit:xmlunit:1.5")
|
||||||
testCompile("dom4j:dom4j:1.6.1") {
|
testCompile("dom4j:dom4j:1.6.1") {
|
||||||
exclude group: "xml-apis", module: "xml-apis"
|
exclude group: "xml-apis", module: "xml-apis"
|
||||||
}
|
}
|
||||||
|
@ -806,7 +806,7 @@ project("spring-test") {
|
||||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||||
optional("org.hamcrest:hamcrest-core:1.3")
|
optional("org.hamcrest:hamcrest-core:1.3")
|
||||||
optional("com.jayway.jsonpath:json-path:0.9.0")
|
optional("com.jayway.jsonpath:json-path:0.9.0")
|
||||||
optional("xmlunit:xmlunit:1.3")
|
optional("xmlunit:xmlunit:1.5")
|
||||||
testCompile(project(":spring-context-support"))
|
testCompile(project(":spring-context-support"))
|
||||||
testCompile(project(":spring-oxm"))
|
testCompile(project(":spring-oxm"))
|
||||||
testCompile(project(":spring-webmvc-tiles3"))
|
testCompile(project(":spring-webmvc-tiles3"))
|
||||||
|
|
|
@ -1,185 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed 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.springframework.util.xml;
|
|
||||||
|
|
||||||
import javax.xml.namespace.QName;
|
|
||||||
import javax.xml.stream.XMLStreamException;
|
|
||||||
|
|
||||||
import org.xml.sax.Attributes;
|
|
||||||
import org.xml.sax.ContentHandler;
|
|
||||||
import org.xml.sax.SAXException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract base class for SAX {@code ContentHandler} implementations that use StAX as a basis. All methods
|
|
||||||
* delegate to internal template methods, capable of throwing a {@code XMLStreamException}. Additionally, an
|
|
||||||
* namespace context is used to keep track of declared namespaces.
|
|
||||||
*
|
|
||||||
* @author Arjen Poutsma
|
|
||||||
* @since 3.0
|
|
||||||
*/
|
|
||||||
abstract class AbstractStaxContentHandler implements ContentHandler {
|
|
||||||
|
|
||||||
private SimpleNamespaceContext namespaceContext = new SimpleNamespaceContext();
|
|
||||||
|
|
||||||
private boolean namespaceContextChanged = false;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void startDocument() throws SAXException {
|
|
||||||
namespaceContext.clear();
|
|
||||||
namespaceContextChanged = false;
|
|
||||||
try {
|
|
||||||
startDocumentInternal();
|
|
||||||
}
|
|
||||||
catch (XMLStreamException ex) {
|
|
||||||
throw new SAXException("Could not handle startDocument: " + ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void startDocumentInternal() throws XMLStreamException;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void endDocument() throws SAXException {
|
|
||||||
namespaceContext.clear();
|
|
||||||
namespaceContextChanged = false;
|
|
||||||
try {
|
|
||||||
endDocumentInternal();
|
|
||||||
}
|
|
||||||
catch (XMLStreamException ex) {
|
|
||||||
throw new SAXException("Could not handle startDocument: " + ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void endDocumentInternal() throws XMLStreamException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Binds the given prefix to the given namespaces.
|
|
||||||
*
|
|
||||||
* @see SimpleNamespaceContext#bindNamespaceUri(String,String)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final void startPrefixMapping(String prefix, String uri) {
|
|
||||||
namespaceContext.bindNamespaceUri(prefix, uri);
|
|
||||||
namespaceContextChanged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the binding for the given prefix.
|
|
||||||
*
|
|
||||||
* @see SimpleNamespaceContext#removeBinding(String)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final void endPrefixMapping(String prefix) {
|
|
||||||
namespaceContext.removeBinding(prefix);
|
|
||||||
namespaceContextChanged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
|
|
||||||
try {
|
|
||||||
startElementInternal(toQName(uri, qName), atts, namespaceContextChanged ? namespaceContext : null);
|
|
||||||
namespaceContextChanged = false;
|
|
||||||
}
|
|
||||||
catch (XMLStreamException ex) {
|
|
||||||
throw new SAXException("Could not handle startElement: " + ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void startElementInternal(QName name, Attributes atts, SimpleNamespaceContext namespaceContext)
|
|
||||||
throws XMLStreamException;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void endElement(String uri, String localName, String qName) throws SAXException {
|
|
||||||
try {
|
|
||||||
endElementInternal(toQName(uri, qName), namespaceContextChanged ? namespaceContext : null);
|
|
||||||
namespaceContextChanged = false;
|
|
||||||
}
|
|
||||||
catch (XMLStreamException ex) {
|
|
||||||
throw new SAXException("Could not handle endElement: " + ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void endElementInternal(QName name, SimpleNamespaceContext namespaceContext)
|
|
||||||
throws XMLStreamException;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void characters(char ch[], int start, int length) throws SAXException {
|
|
||||||
try {
|
|
||||||
charactersInternal(ch, start, length);
|
|
||||||
}
|
|
||||||
catch (XMLStreamException ex) {
|
|
||||||
throw new SAXException("Could not handle characters: " + ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void charactersInternal(char[] ch, int start, int length) throws XMLStreamException;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
|
|
||||||
try {
|
|
||||||
ignorableWhitespaceInternal(ch, start, length);
|
|
||||||
}
|
|
||||||
catch (XMLStreamException ex) {
|
|
||||||
throw new SAXException("Could not handle ignorableWhitespace:" + ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void ignorableWhitespaceInternal(char[] ch, int start, int length) throws XMLStreamException;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void processingInstruction(String target, String data) throws SAXException {
|
|
||||||
try {
|
|
||||||
processingInstructionInternal(target, data);
|
|
||||||
}
|
|
||||||
catch (XMLStreamException ex) {
|
|
||||||
throw new SAXException("Could not handle processingInstruction: " + ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void processingInstructionInternal(String target, String data) throws XMLStreamException;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void skippedEntity(String name) throws SAXException {
|
|
||||||
try {
|
|
||||||
skippedEntityInternal(name);
|
|
||||||
}
|
|
||||||
catch (XMLStreamException ex) {
|
|
||||||
throw new SAXException("Could not handle skippedEntity: " + ex.getMessage(), ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a namespace URI and DOM or SAX qualified name to a {@code QName}. The qualified name can have the form
|
|
||||||
* {@code prefix:localname} or {@code localName}.
|
|
||||||
*
|
|
||||||
* @param namespaceUri the namespace URI
|
|
||||||
* @param qualifiedName the qualified name
|
|
||||||
* @return a QName
|
|
||||||
*/
|
|
||||||
protected QName toQName(String namespaceUri, String qualifiedName) {
|
|
||||||
int idx = qualifiedName.indexOf(':');
|
|
||||||
if (idx == -1) {
|
|
||||||
return new QName(namespaceUri, qualifiedName);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
String prefix = qualifiedName.substring(0, idx);
|
|
||||||
String localPart = qualifiedName.substring(idx + 1);
|
|
||||||
return new QName(namespaceUri, localPart, prefix);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void skippedEntityInternal(String name) throws XMLStreamException;
|
|
||||||
}
|
|
|
@ -0,0 +1,273 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2014 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed 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.springframework.util.xml;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import javax.xml.XMLConstants;
|
||||||
|
import javax.xml.namespace.QName;
|
||||||
|
import javax.xml.stream.XMLStreamException;
|
||||||
|
|
||||||
|
import org.xml.sax.Attributes;
|
||||||
|
import org.xml.sax.ContentHandler;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
import org.xml.sax.ext.LexicalHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract base class for SAX {@code ContentHandler} and {@code LexicalHandler}
|
||||||
|
* implementations that use StAX as a basis. All methods delegate to internal template
|
||||||
|
* methods, capable of throwing a {@code XMLStreamException}. Additionally, an namespace
|
||||||
|
* context stack is used to keep track of declared namespaces.
|
||||||
|
*
|
||||||
|
* @author Arjen Poutsma
|
||||||
|
* @since 4.0.3
|
||||||
|
*/
|
||||||
|
abstract class AbstractStaxHandler implements ContentHandler, LexicalHandler {
|
||||||
|
|
||||||
|
private final List<Map<String, String>> namespaceMappings = new ArrayList<Map<String, String>>();
|
||||||
|
|
||||||
|
private boolean inCData;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void startDocument() throws SAXException {
|
||||||
|
removeAllNamespaceMappings();
|
||||||
|
newNamespaceMapping();
|
||||||
|
try {
|
||||||
|
startDocumentInternal();
|
||||||
|
}
|
||||||
|
catch (XMLStreamException ex) {
|
||||||
|
throw new SAXException("Could not handle startDocument: " + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void endDocument() throws SAXException {
|
||||||
|
removeAllNamespaceMappings();
|
||||||
|
try {
|
||||||
|
endDocumentInternal();
|
||||||
|
}
|
||||||
|
catch (XMLStreamException ex) {
|
||||||
|
throw new SAXException("Could not handle endDocument: " + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void startPrefixMapping(String prefix, String uri) {
|
||||||
|
currentNamespaceMapping().put(prefix, uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void endPrefixMapping(String prefix) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
|
||||||
|
try {
|
||||||
|
startElementInternal(toQName(uri, qName), atts, currentNamespaceMapping());
|
||||||
|
newNamespaceMapping();
|
||||||
|
}
|
||||||
|
catch (XMLStreamException ex) {
|
||||||
|
throw new SAXException("Could not handle startElement: " + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void endElement(String uri, String localName, String qName) throws SAXException {
|
||||||
|
try {
|
||||||
|
endElementInternal(toQName(uri, qName), currentNamespaceMapping());
|
||||||
|
removeNamespaceMapping();
|
||||||
|
}
|
||||||
|
catch (XMLStreamException ex) {
|
||||||
|
throw new SAXException("Could not handle endElement: " + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void characters(char ch[], int start, int length) throws SAXException {
|
||||||
|
try {
|
||||||
|
String data = new String(ch, start, length);
|
||||||
|
if (!this.inCData) {
|
||||||
|
charactersInternal(data);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cDataInternal(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (XMLStreamException ex) {
|
||||||
|
throw new SAXException("Could not handle characters: " + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
|
||||||
|
try {
|
||||||
|
ignorableWhitespaceInternal(new String(ch, start, length));
|
||||||
|
}
|
||||||
|
catch (XMLStreamException ex) {
|
||||||
|
throw new SAXException(
|
||||||
|
"Could not handle ignorableWhitespace:" + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void processingInstruction(String target, String data) throws SAXException {
|
||||||
|
try {
|
||||||
|
processingInstructionInternal(target, data);
|
||||||
|
}
|
||||||
|
catch (XMLStreamException ex) {
|
||||||
|
throw new SAXException("Could not handle processingInstruction: " + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void skippedEntity(String name) throws SAXException {
|
||||||
|
try {
|
||||||
|
skippedEntityInternal(name);
|
||||||
|
}
|
||||||
|
catch (XMLStreamException ex) {
|
||||||
|
throw new SAXException("Could not handle skippedEntity: " + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void startDTD(String name, String publicId, String systemId) throws SAXException {
|
||||||
|
try {
|
||||||
|
StringBuilder builder = new StringBuilder("<!DOCTYPE ");
|
||||||
|
builder.append(name);
|
||||||
|
if (publicId != null) {
|
||||||
|
builder.append(" PUBLIC \"");
|
||||||
|
builder.append(publicId);
|
||||||
|
builder.append("\" \"");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
builder.append(" SYSTEM \"");
|
||||||
|
}
|
||||||
|
builder.append(systemId);
|
||||||
|
builder.append("\">");
|
||||||
|
|
||||||
|
dtdInternal(builder.toString());
|
||||||
|
}
|
||||||
|
catch (XMLStreamException ex) {
|
||||||
|
throw new SAXException("Could not handle startDTD: " + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void endDTD() throws SAXException {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void startCDATA() throws SAXException {
|
||||||
|
this.inCData = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void endCDATA() throws SAXException {
|
||||||
|
this.inCData = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void comment(char[] ch, int start, int length) throws SAXException {
|
||||||
|
try {
|
||||||
|
commentInternal(new String(ch, start, length));
|
||||||
|
}
|
||||||
|
catch (XMLStreamException ex) {
|
||||||
|
throw new SAXException("Could not handle comment: " + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startEntity(String name) throws SAXException {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endEntity(String name) throws SAXException {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a namespace URI and DOM or SAX qualified name to a {@code QName}. The
|
||||||
|
* qualified name can have the form {@code prefix:localname} or {@code localName}.
|
||||||
|
* @param namespaceUri the namespace URI
|
||||||
|
* @param qualifiedName the qualified name
|
||||||
|
* @return a QName
|
||||||
|
*/
|
||||||
|
protected QName toQName(String namespaceUri, String qualifiedName) {
|
||||||
|
int idx = qualifiedName.indexOf(':');
|
||||||
|
if (idx == -1) {
|
||||||
|
return new QName(namespaceUri, qualifiedName);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
String prefix = qualifiedName.substring(0, idx);
|
||||||
|
String localPart = qualifiedName.substring(idx + 1);
|
||||||
|
return new QName(namespaceUri, localPart, prefix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isNamespaceDeclaration(QName qName) {
|
||||||
|
String prefix = qName.getPrefix();
|
||||||
|
String localPart = qName.getLocalPart();
|
||||||
|
return (XMLConstants.XMLNS_ATTRIBUTE.equals(localPart) && prefix.length() == 0) ||
|
||||||
|
(XMLConstants.XMLNS_ATTRIBUTE.equals(prefix) && localPart.length() != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Map<String, String> currentNamespaceMapping() {
|
||||||
|
return this.namespaceMappings.get(this.namespaceMappings.size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void newNamespaceMapping() {
|
||||||
|
this.namespaceMappings.add(new HashMap<String, String>());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeNamespaceMapping() {
|
||||||
|
this.namespaceMappings.remove(this.namespaceMappings.size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeAllNamespaceMappings() {
|
||||||
|
this.namespaceMappings.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected abstract void startDocumentInternal() throws XMLStreamException;
|
||||||
|
|
||||||
|
protected abstract void endDocumentInternal() throws XMLStreamException;
|
||||||
|
|
||||||
|
protected abstract void startElementInternal(QName name, Attributes attributes,
|
||||||
|
Map<String, String> namespaceMapping) throws XMLStreamException;
|
||||||
|
|
||||||
|
protected abstract void endElementInternal(QName name, Map<String, String> namespaceMapping)
|
||||||
|
throws XMLStreamException;
|
||||||
|
|
||||||
|
protected abstract void charactersInternal(String data) throws XMLStreamException;
|
||||||
|
|
||||||
|
protected abstract void cDataInternal(String data) throws XMLStreamException;
|
||||||
|
|
||||||
|
protected abstract void ignorableWhitespaceInternal(String data) throws XMLStreamException;
|
||||||
|
|
||||||
|
protected abstract void processingInstructionInternal(String target, String data)
|
||||||
|
throws XMLStreamException;
|
||||||
|
|
||||||
|
protected abstract void skippedEntityInternal(String name) throws XMLStreamException;
|
||||||
|
|
||||||
|
protected abstract void dtdInternal(String dtd) throws XMLStreamException;
|
||||||
|
|
||||||
|
protected abstract void commentInternal(String comment) throws XMLStreamException;
|
||||||
|
|
||||||
|
}
|
|
@ -1,198 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed 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.springframework.util.xml;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.xml.XMLConstants;
|
|
||||||
import javax.xml.namespace.QName;
|
|
||||||
import javax.xml.stream.Location;
|
|
||||||
import javax.xml.stream.XMLEventFactory;
|
|
||||||
import javax.xml.stream.XMLStreamException;
|
|
||||||
import javax.xml.stream.events.Attribute;
|
|
||||||
import javax.xml.stream.events.Namespace;
|
|
||||||
import javax.xml.stream.events.XMLEvent;
|
|
||||||
import javax.xml.stream.util.XMLEventConsumer;
|
|
||||||
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
import org.xml.sax.Attributes;
|
|
||||||
import org.xml.sax.Locator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SAX {@code ContentHandler} that transforms callback calls to {@code XMLEvent}s
|
|
||||||
* and writes them to a {@code XMLEventConsumer}.
|
|
||||||
*
|
|
||||||
* @author Arjen Poutsma
|
|
||||||
* @since 3.0
|
|
||||||
* @see XMLEvent
|
|
||||||
* @see XMLEventConsumer
|
|
||||||
*/
|
|
||||||
class StaxEventContentHandler extends AbstractStaxContentHandler {
|
|
||||||
|
|
||||||
private final XMLEventFactory eventFactory;
|
|
||||||
|
|
||||||
private final XMLEventConsumer eventConsumer;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a new instance of the {@code StaxEventContentHandler} that writes to the given
|
|
||||||
* {@code XMLEventConsumer}. A default {@code XMLEventFactory} will be created.
|
|
||||||
* @param consumer the consumer to write events to
|
|
||||||
*/
|
|
||||||
StaxEventContentHandler(XMLEventConsumer consumer) {
|
|
||||||
this.eventFactory = XMLEventFactory.newInstance();
|
|
||||||
this.eventConsumer = consumer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a new instance of the {@code StaxEventContentHandler} that uses the given
|
|
||||||
* event factory to create events and writes to the given {@code XMLEventConsumer}.
|
|
||||||
* @param consumer the consumer to write events to
|
|
||||||
* @param factory the factory used to create events
|
|
||||||
*/
|
|
||||||
StaxEventContentHandler(XMLEventConsumer consumer, XMLEventFactory factory) {
|
|
||||||
this.eventFactory = factory;
|
|
||||||
this.eventConsumer = consumer;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setDocumentLocator(Locator locator) {
|
|
||||||
if (locator != null) {
|
|
||||||
this.eventFactory.setLocation(new LocatorLocationAdapter(locator));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void startDocumentInternal() throws XMLStreamException {
|
|
||||||
consumeEvent(this.eventFactory.createStartDocument());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void endDocumentInternal() throws XMLStreamException {
|
|
||||||
consumeEvent(this.eventFactory.createEndDocument());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void startElementInternal(QName name, Attributes atts, SimpleNamespaceContext namespaceContext)
|
|
||||||
throws XMLStreamException {
|
|
||||||
|
|
||||||
List<Attribute> attributes = getAttributes(atts);
|
|
||||||
List<Namespace> namespaces = createNamespaces(namespaceContext);
|
|
||||||
consumeEvent(this.eventFactory.createStartElement(name, attributes.iterator(),
|
|
||||||
(namespaces != null ? namespaces.iterator() : null)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void endElementInternal(QName name, SimpleNamespaceContext namespaceContext) throws XMLStreamException {
|
|
||||||
List<Namespace> namespaces = createNamespaces(namespaceContext);
|
|
||||||
consumeEvent(this.eventFactory.createEndElement(name, namespaces != null ? namespaces.iterator() : null));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void charactersInternal(char[] ch, int start, int length) throws XMLStreamException {
|
|
||||||
consumeEvent(this.eventFactory.createCharacters(new String(ch, start, length)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void ignorableWhitespaceInternal(char[] ch, int start, int length) throws XMLStreamException {
|
|
||||||
consumeEvent(this.eventFactory.createIgnorableSpace(new String(ch, start, length)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void processingInstructionInternal(String target, String data) throws XMLStreamException {
|
|
||||||
consumeEvent(this.eventFactory.createProcessingInstruction(target, data));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void consumeEvent(XMLEvent event) throws XMLStreamException {
|
|
||||||
this.eventConsumer.add(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create and return a list of {@code NameSpace} objects from the {@code NamespaceContext}.
|
|
||||||
*/
|
|
||||||
private List<Namespace> createNamespaces(SimpleNamespaceContext namespaceContext) {
|
|
||||||
if (namespaceContext == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Namespace> namespaces = new ArrayList<Namespace>();
|
|
||||||
String defaultNamespaceUri = namespaceContext.getNamespaceURI(XMLConstants.DEFAULT_NS_PREFIX);
|
|
||||||
if (StringUtils.hasLength(defaultNamespaceUri)) {
|
|
||||||
namespaces.add(this.eventFactory.createNamespace(defaultNamespaceUri));
|
|
||||||
}
|
|
||||||
for (Iterator<String> iterator = namespaceContext.getBoundPrefixes(); iterator.hasNext();) {
|
|
||||||
String prefix = iterator.next();
|
|
||||||
String namespaceUri = namespaceContext.getNamespaceURI(prefix);
|
|
||||||
namespaces.add(this.eventFactory.createNamespace(prefix, namespaceUri));
|
|
||||||
}
|
|
||||||
return namespaces;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Attribute> getAttributes(Attributes attributes) {
|
|
||||||
List<Attribute> list = new ArrayList<Attribute>();
|
|
||||||
for (int i = 0; i < attributes.getLength(); i++) {
|
|
||||||
QName name = toQName(attributes.getURI(i), attributes.getQName(i));
|
|
||||||
if (!("xmlns".equals(name.getLocalPart()) || "xmlns".equals(name.getPrefix()))) {
|
|
||||||
list.add(this.eventFactory.createAttribute(name, attributes.getValue(i)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* No operation */
|
|
||||||
@Override
|
|
||||||
protected void skippedEntityInternal(String name) throws XMLStreamException {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static final class LocatorLocationAdapter implements Location {
|
|
||||||
|
|
||||||
private final Locator locator;
|
|
||||||
|
|
||||||
public LocatorLocationAdapter(Locator locator) {
|
|
||||||
this.locator = locator;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getLineNumber() {
|
|
||||||
return this.locator.getLineNumber();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getColumnNumber() {
|
|
||||||
return this.locator.getColumnNumber();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getCharacterOffset() {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getPublicId() {
|
|
||||||
return this.locator.getPublicId();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getSystemId() {
|
|
||||||
return this.locator.getSystemId();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,196 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2014 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed 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.springframework.util.xml;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import javax.xml.namespace.QName;
|
||||||
|
import javax.xml.stream.Location;
|
||||||
|
import javax.xml.stream.XMLEventFactory;
|
||||||
|
import javax.xml.stream.XMLEventWriter;
|
||||||
|
import javax.xml.stream.XMLStreamException;
|
||||||
|
import javax.xml.stream.events.Attribute;
|
||||||
|
import javax.xml.stream.events.Namespace;
|
||||||
|
|
||||||
|
import org.xml.sax.Attributes;
|
||||||
|
import org.xml.sax.Locator;
|
||||||
|
import org.xml.sax.ext.LexicalHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SAX {@link org.xml.sax.ContentHandler} and {@link LexicalHandler}
|
||||||
|
* that writes to a {@link javax.xml.stream.util.XMLEventConsumer}.
|
||||||
|
*
|
||||||
|
* @author Arjen Poutsma
|
||||||
|
* @since 4.0.3
|
||||||
|
*/
|
||||||
|
class StaxEventHandler extends AbstractStaxHandler {
|
||||||
|
|
||||||
|
private final XMLEventFactory eventFactory;
|
||||||
|
|
||||||
|
private final XMLEventWriter eventWriter;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new instance of the {@code StaxEventContentHandler} that writes to the
|
||||||
|
* given {@code XMLEventWriter}. A default {@code XMLEventFactory} will be created.
|
||||||
|
* @param eventWriter the writer to write events to
|
||||||
|
*/
|
||||||
|
public StaxEventHandler(XMLEventWriter eventWriter) {
|
||||||
|
this.eventFactory = XMLEventFactory.newInstance();
|
||||||
|
this.eventWriter = eventWriter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new instance of the {@code StaxEventContentHandler} that uses the given
|
||||||
|
* event factory to create events and writes to the given {@code XMLEventConsumer}.
|
||||||
|
* @param eventWriter the writer to write events to
|
||||||
|
* @param factory the factory used to create events
|
||||||
|
*/
|
||||||
|
public StaxEventHandler(XMLEventWriter eventWriter, XMLEventFactory factory) {
|
||||||
|
this.eventFactory = factory;
|
||||||
|
this.eventWriter = eventWriter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDocumentLocator(Locator locator) {
|
||||||
|
if (locator != null) {
|
||||||
|
this.eventFactory.setLocation(new LocatorLocationAdapter(locator));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void startDocumentInternal() throws XMLStreamException {
|
||||||
|
this.eventWriter.add(this.eventFactory.createStartDocument());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void endDocumentInternal() throws XMLStreamException {
|
||||||
|
this.eventWriter.add(this.eventFactory.createEndDocument());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void startElementInternal(QName name, Attributes atts,
|
||||||
|
Map<String, String> namespaceMapping) throws XMLStreamException {
|
||||||
|
|
||||||
|
List<Attribute> attributes = getAttributes(atts);
|
||||||
|
List<Namespace> namespaces = getNamespaces(namespaceMapping);
|
||||||
|
this.eventWriter.add(
|
||||||
|
this.eventFactory.createStartElement(name, attributes.iterator(), namespaces.iterator()));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Namespace> getNamespaces(Map<String, String> namespaceMapping) {
|
||||||
|
List<Namespace> result = new ArrayList<Namespace>();
|
||||||
|
for (Map.Entry<String, String> entry : namespaceMapping.entrySet()) {
|
||||||
|
String prefix = entry.getKey();
|
||||||
|
String namespaceUri = entry.getValue();
|
||||||
|
result.add(this.eventFactory.createNamespace(prefix, namespaceUri));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Attribute> getAttributes(Attributes attributes) {
|
||||||
|
List<Attribute> result = new ArrayList<Attribute>();
|
||||||
|
for (int i = 0; i < attributes.getLength(); i++) {
|
||||||
|
QName attrName = toQName(attributes.getURI(i), attributes.getQName(i));
|
||||||
|
if (!isNamespaceDeclaration(attrName)) {
|
||||||
|
result.add(this.eventFactory.createAttribute(attrName, attributes.getValue(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void endElementInternal(QName name, Map<String, String> namespaceMapping) throws XMLStreamException {
|
||||||
|
List<Namespace> namespaces = getNamespaces(namespaceMapping);
|
||||||
|
this.eventWriter.add(this.eventFactory.createEndElement(name, namespaces.iterator()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void charactersInternal(String data) throws XMLStreamException {
|
||||||
|
this.eventWriter.add(this.eventFactory.createCharacters(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void cDataInternal(String data) throws XMLStreamException {
|
||||||
|
this.eventWriter.add(this.eventFactory.createCData(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void ignorableWhitespaceInternal(String data) throws XMLStreamException {
|
||||||
|
this.eventWriter.add(this.eventFactory.createIgnorableSpace(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processingInstructionInternal(String target, String data) throws XMLStreamException {
|
||||||
|
this.eventWriter.add(this.eventFactory.createProcessingInstruction(target, data));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void dtdInternal(String dtd) throws XMLStreamException {
|
||||||
|
this.eventWriter.add(this.eventFactory.createDTD(dtd));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void commentInternal(String comment) throws XMLStreamException {
|
||||||
|
this.eventWriter.add(this.eventFactory.createComment(comment));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignored
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void skippedEntityInternal(String name) throws XMLStreamException {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static final class LocatorLocationAdapter implements Location {
|
||||||
|
|
||||||
|
private final Locator locator;
|
||||||
|
|
||||||
|
public LocatorLocationAdapter(Locator locator) {
|
||||||
|
this.locator = locator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLineNumber() {
|
||||||
|
return this.locator.getLineNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getColumnNumber() {
|
||||||
|
return this.locator.getColumnNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCharacterOffset() {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPublicId() {
|
||||||
|
return this.locator.getPublicId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSystemId() {
|
||||||
|
return this.locator.getSystemId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2002-2014 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -22,6 +22,7 @@ import javax.xml.stream.XMLStreamWriter;
|
||||||
import javax.xml.transform.sax.SAXResult;
|
import javax.xml.transform.sax.SAXResult;
|
||||||
|
|
||||||
import org.xml.sax.ContentHandler;
|
import org.xml.sax.ContentHandler;
|
||||||
|
import org.xml.sax.ext.LexicalHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of the {@code Result} tagging interface for StAX writers. Can be constructed with
|
* Implementation of the {@code Result} tagging interface for StAX writers. Can be constructed with
|
||||||
|
@ -35,7 +36,8 @@ import org.xml.sax.ContentHandler;
|
||||||
* {@code SAXResult} is <strong>not supported</strong>. In general, the only supported operation
|
* {@code SAXResult} is <strong>not supported</strong>. In general, the only supported operation
|
||||||
* on this class is to use the {@code ContentHandler} obtained via {@link #getHandler()} to parse an
|
* on this class is to use the {@code ContentHandler} obtained via {@link #getHandler()} to parse an
|
||||||
* input source using an {@code XMLReader}. Calling {@link #setHandler(org.xml.sax.ContentHandler)}
|
* input source using an {@code XMLReader}. Calling {@link #setHandler(org.xml.sax.ContentHandler)}
|
||||||
* will result in {@code UnsupportedOperationException}s.
|
* or {@link #setLexicalHandler(org.xml.sax.ext.LexicalHandler)} will result in
|
||||||
|
* {@code UnsupportedOperationException}s.
|
||||||
*
|
*
|
||||||
* @author Arjen Poutsma
|
* @author Arjen Poutsma
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
|
@ -54,8 +56,10 @@ class StaxResult extends SAXResult {
|
||||||
* Construct a new instance of the {@code StaxResult} with the specified {@code XMLStreamWriter}.
|
* Construct a new instance of the {@code StaxResult} with the specified {@code XMLStreamWriter}.
|
||||||
* @param streamWriter the {@code XMLStreamWriter} to write to
|
* @param streamWriter the {@code XMLStreamWriter} to write to
|
||||||
*/
|
*/
|
||||||
StaxResult(XMLStreamWriter streamWriter) {
|
public StaxResult(XMLStreamWriter streamWriter) {
|
||||||
super.setHandler(new StaxStreamContentHandler(streamWriter));
|
StaxStreamHandler handler = new StaxStreamHandler(streamWriter);
|
||||||
|
super.setHandler(handler);
|
||||||
|
super.setLexicalHandler(handler);
|
||||||
this.streamWriter = streamWriter;
|
this.streamWriter = streamWriter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,19 +67,10 @@ class StaxResult extends SAXResult {
|
||||||
* Construct a new instance of the {@code StaxResult} with the specified {@code XMLEventWriter}.
|
* Construct a new instance of the {@code StaxResult} with the specified {@code XMLEventWriter}.
|
||||||
* @param eventWriter the {@code XMLEventWriter} to write to
|
* @param eventWriter the {@code XMLEventWriter} to write to
|
||||||
*/
|
*/
|
||||||
StaxResult(XMLEventWriter eventWriter) {
|
public StaxResult(XMLEventWriter eventWriter) {
|
||||||
super.setHandler(new StaxEventContentHandler(eventWriter));
|
StaxEventHandler handler = new StaxEventHandler(eventWriter);
|
||||||
this.eventWriter = eventWriter;
|
super.setHandler(handler);
|
||||||
}
|
super.setLexicalHandler(handler);
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a new instance of the {@code StaxResult} with the specified {@code XMLEventWriter}
|
|
||||||
* and {@code XMLEventFactory}.
|
|
||||||
* @param eventWriter the {@code XMLEventWriter} to write to
|
|
||||||
* @param eventFactory the {@code XMLEventFactory} to use for creating events
|
|
||||||
*/
|
|
||||||
StaxResult(XMLEventWriter eventWriter, XMLEventFactory eventFactory) {
|
|
||||||
super.setHandler(new StaxEventContentHandler(eventWriter, eventFactory));
|
|
||||||
this.eventWriter = eventWriter;
|
this.eventWriter = eventWriter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +81,7 @@ class StaxResult extends SAXResult {
|
||||||
* @return the StAX event writer used by this result
|
* @return the StAX event writer used by this result
|
||||||
* @see #StaxResult(javax.xml.stream.XMLEventWriter)
|
* @see #StaxResult(javax.xml.stream.XMLEventWriter)
|
||||||
*/
|
*/
|
||||||
XMLEventWriter getXMLEventWriter() {
|
public XMLEventWriter getXMLEventWriter() {
|
||||||
return this.eventWriter;
|
return this.eventWriter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +91,7 @@ class StaxResult extends SAXResult {
|
||||||
* @return the StAX stream writer used by this result
|
* @return the StAX stream writer used by this result
|
||||||
* @see #StaxResult(javax.xml.stream.XMLStreamWriter)
|
* @see #StaxResult(javax.xml.stream.XMLStreamWriter)
|
||||||
*/
|
*/
|
||||||
XMLStreamWriter getXMLStreamWriter() {
|
public XMLStreamWriter getXMLStreamWriter() {
|
||||||
return this.streamWriter;
|
return this.streamWriter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,4 +105,13 @@ class StaxResult extends SAXResult {
|
||||||
throw new UnsupportedOperationException("setHandler is not supported");
|
throw new UnsupportedOperationException("setHandler is not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throws an {@code UnsupportedOperationException}.
|
||||||
|
* @throws UnsupportedOperationException always
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setLexicalHandler(LexicalHandler handler) {
|
||||||
|
throw new UnsupportedOperationException("setLexicalHandler is not supported");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,114 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed 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.springframework.util.xml;
|
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
import javax.xml.namespace.QName;
|
|
||||||
import javax.xml.stream.XMLStreamException;
|
|
||||||
import javax.xml.stream.XMLStreamWriter;
|
|
||||||
|
|
||||||
import org.xml.sax.Attributes;
|
|
||||||
import org.xml.sax.Locator;
|
|
||||||
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SAX {@code ContentHandler} that writes to a {@code XMLStreamWriter}.
|
|
||||||
*
|
|
||||||
* @author Arjen Poutsma
|
|
||||||
* @see XMLStreamWriter
|
|
||||||
* @since 3.0
|
|
||||||
*/
|
|
||||||
class StaxStreamContentHandler extends AbstractStaxContentHandler {
|
|
||||||
|
|
||||||
private final XMLStreamWriter streamWriter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new instance of the {@code StaxStreamContentHandler} that writes to the given
|
|
||||||
* {@code XMLStreamWriter}.
|
|
||||||
*
|
|
||||||
* @param streamWriter the stream writer to write to
|
|
||||||
*/
|
|
||||||
StaxStreamContentHandler(XMLStreamWriter streamWriter) {
|
|
||||||
Assert.notNull(streamWriter, "'streamWriter' must not be null");
|
|
||||||
this.streamWriter = streamWriter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setDocumentLocator(Locator locator) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void charactersInternal(char[] ch, int start, int length) throws XMLStreamException {
|
|
||||||
streamWriter.writeCharacters(ch, start, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void endDocumentInternal() throws XMLStreamException {
|
|
||||||
streamWriter.writeEndDocument();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void endElementInternal(QName name, SimpleNamespaceContext namespaceContext) throws XMLStreamException {
|
|
||||||
streamWriter.writeEndElement();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void ignorableWhitespaceInternal(char[] ch, int start, int length) throws XMLStreamException {
|
|
||||||
streamWriter.writeCharacters(ch, start, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void processingInstructionInternal(String target, String data) throws XMLStreamException {
|
|
||||||
streamWriter.writeProcessingInstruction(target, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void skippedEntityInternal(String name) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void startDocumentInternal() throws XMLStreamException {
|
|
||||||
streamWriter.writeStartDocument();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void startElementInternal(QName name, Attributes attributes, SimpleNamespaceContext namespaceContext)
|
|
||||||
throws XMLStreamException {
|
|
||||||
streamWriter.writeStartElement(name.getPrefix(), name.getLocalPart(), name.getNamespaceURI());
|
|
||||||
if (namespaceContext != null) {
|
|
||||||
String defaultNamespaceUri = namespaceContext.getNamespaceURI("");
|
|
||||||
if (StringUtils.hasLength(defaultNamespaceUri)) {
|
|
||||||
streamWriter.writeNamespace("", defaultNamespaceUri);
|
|
||||||
streamWriter.setDefaultNamespace(defaultNamespaceUri);
|
|
||||||
}
|
|
||||||
for (Iterator<String> iterator = namespaceContext.getBoundPrefixes(); iterator.hasNext();) {
|
|
||||||
String prefix = iterator.next();
|
|
||||||
streamWriter.writeNamespace(prefix, namespaceContext.getNamespaceURI(prefix));
|
|
||||||
streamWriter.setPrefix(prefix, namespaceContext.getNamespaceURI(prefix));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int i = 0; i < attributes.getLength(); i++) {
|
|
||||||
QName attrName = toQName(attributes.getURI(i), attributes.getQName(i));
|
|
||||||
if (!("xmlns".equals(attrName.getLocalPart()) || "xmlns".equals(attrName.getPrefix()))) {
|
|
||||||
streamWriter.writeAttribute(attrName.getPrefix(), attrName.getNamespaceURI(), attrName.getLocalPart(),
|
|
||||||
attributes.getValue(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,139 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2014 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed 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.springframework.util.xml;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import javax.xml.XMLConstants;
|
||||||
|
import javax.xml.namespace.QName;
|
||||||
|
import javax.xml.stream.XMLStreamException;
|
||||||
|
import javax.xml.stream.XMLStreamWriter;
|
||||||
|
|
||||||
|
import org.xml.sax.Attributes;
|
||||||
|
import org.xml.sax.Locator;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
import org.xml.sax.ext.LexicalHandler;
|
||||||
|
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SAX {@link org.xml.sax.ContentHandler} and {@link LexicalHandler}
|
||||||
|
* that writes to an {@link XMLStreamWriter}.
|
||||||
|
*
|
||||||
|
* @author Arjen Poutsma
|
||||||
|
* @since 4.0.3
|
||||||
|
*/
|
||||||
|
class StaxStreamHandler extends AbstractStaxHandler {
|
||||||
|
|
||||||
|
private final XMLStreamWriter streamWriter;
|
||||||
|
|
||||||
|
|
||||||
|
public StaxStreamHandler(XMLStreamWriter streamWriter) {
|
||||||
|
Assert.notNull(streamWriter, "XMLStreamWriter must not be null");
|
||||||
|
this.streamWriter = streamWriter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void startDocumentInternal() throws XMLStreamException {
|
||||||
|
this.streamWriter.writeStartDocument();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void endDocumentInternal() throws XMLStreamException {
|
||||||
|
this.streamWriter.writeEndDocument();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void startElementInternal(QName name, Attributes attributes,
|
||||||
|
Map<String, String> namespaceMapping) throws XMLStreamException {
|
||||||
|
|
||||||
|
this.streamWriter.writeStartElement(name.getPrefix(), name.getLocalPart(), name.getNamespaceURI());
|
||||||
|
|
||||||
|
for (Map.Entry<String, String> entry : namespaceMapping.entrySet()) {
|
||||||
|
String prefix = entry.getKey();
|
||||||
|
String namespaceUri = entry.getValue();
|
||||||
|
this.streamWriter.writeNamespace(prefix, namespaceUri);
|
||||||
|
if (XMLConstants.DEFAULT_NS_PREFIX.equals(prefix)) {
|
||||||
|
this.streamWriter.setDefaultNamespace(namespaceUri);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.streamWriter.setPrefix(prefix, namespaceUri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < attributes.getLength(); i++) {
|
||||||
|
QName attrName = toQName(attributes.getURI(i), attributes.getQName(i));
|
||||||
|
if (!isNamespaceDeclaration(attrName)) {
|
||||||
|
this.streamWriter.writeAttribute(attrName.getPrefix(), attrName.getNamespaceURI(),
|
||||||
|
attrName.getLocalPart(), attributes.getValue(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void endElementInternal(QName name, Map<String, String> namespaceMapping) throws XMLStreamException {
|
||||||
|
this.streamWriter.writeEndElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void charactersInternal(String data) throws XMLStreamException {
|
||||||
|
this.streamWriter.writeCharacters(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void cDataInternal(String data) throws XMLStreamException {
|
||||||
|
this.streamWriter.writeCData(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void ignorableWhitespaceInternal(String data) throws XMLStreamException {
|
||||||
|
this.streamWriter.writeCharacters(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processingInstructionInternal(String target, String data) throws XMLStreamException {
|
||||||
|
this.streamWriter.writeProcessingInstruction(target, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void dtdInternal(String dtd) throws XMLStreamException {
|
||||||
|
this.streamWriter.writeDTD(dtd);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void commentInternal(String comment) throws XMLStreamException {
|
||||||
|
this.streamWriter.writeComment(comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignored
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDocumentLocator(Locator locator) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startEntity(String name) throws SAXException {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endEntity(String name) throws SAXException {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void skippedEntityInternal(String name) throws XMLStreamException {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2002-2014 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -217,7 +217,7 @@ public abstract class StaxUtils {
|
||||||
* @return a content handler writing to the {@code streamWriter}
|
* @return a content handler writing to the {@code streamWriter}
|
||||||
*/
|
*/
|
||||||
public static ContentHandler createContentHandler(XMLStreamWriter streamWriter) {
|
public static ContentHandler createContentHandler(XMLStreamWriter streamWriter) {
|
||||||
return new StaxStreamContentHandler(streamWriter);
|
return new StaxStreamHandler(streamWriter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -226,7 +226,7 @@ public abstract class StaxUtils {
|
||||||
* @return a content handler writing to the {@code eventWriter}
|
* @return a content handler writing to the {@code eventWriter}
|
||||||
*/
|
*/
|
||||||
public static ContentHandler createContentHandler(XMLEventWriter eventWriter) {
|
public static ContentHandler createContentHandler(XMLEventWriter eventWriter) {
|
||||||
return new StaxEventContentHandler(eventWriter);
|
return new StaxEventHandler(eventWriter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,66 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2009 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed 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.springframework.util.xml;
|
|
||||||
|
|
||||||
import java.io.StringReader;
|
|
||||||
import java.io.StringWriter;
|
|
||||||
import java.io.Writer;
|
|
||||||
import javax.xml.stream.XMLStreamException;
|
|
||||||
|
|
||||||
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.xml.sax.InputSource;
|
|
||||||
import org.xml.sax.XMLReader;
|
|
||||||
import org.xml.sax.helpers.XMLReaderFactory;
|
|
||||||
|
|
||||||
public abstract class AbstractStaxContentHandlerTestCase {
|
|
||||||
|
|
||||||
private static final String XML_CONTENT_HANDLER =
|
|
||||||
"<?xml version='1.0' encoding='UTF-8'?><?pi content?><root xmlns='namespace'><prefix:child xmlns:prefix='namespace2' prefix:attr='value'>content</prefix:child></root>"
|
|
||||||
;
|
|
||||||
|
|
||||||
private XMLReader xmlReader;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void createXMLReader() throws Exception {
|
|
||||||
xmlReader = XMLReaderFactory.createXMLReader();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void contentHandler() throws Exception {
|
|
||||||
StringWriter stringWriter = new StringWriter();
|
|
||||||
AbstractStaxContentHandler handler = createStaxContentHandler(stringWriter);
|
|
||||||
xmlReader.setFeature("http://xml.org/sax/features/namespace-prefixes", false);
|
|
||||||
xmlReader.setContentHandler(handler);
|
|
||||||
xmlReader.parse(new InputSource(new StringReader(XML_CONTENT_HANDLER)));
|
|
||||||
assertXMLEqual("Invalid result", XML_CONTENT_HANDLER, stringWriter.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void contentHandlerNamespacePrefixes() throws Exception {
|
|
||||||
StringWriter stringWriter = new StringWriter();
|
|
||||||
AbstractStaxContentHandler handler = createStaxContentHandler(stringWriter);
|
|
||||||
xmlReader.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
|
|
||||||
xmlReader.setContentHandler(handler);
|
|
||||||
xmlReader.parse(new InputSource(new StringReader(XML_CONTENT_HANDLER)));
|
|
||||||
assertXMLEqual("Invalid result", XML_CONTENT_HANDLER, stringWriter.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract AbstractStaxContentHandler createStaxContentHandler(Writer writer) throws XMLStreamException;
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,134 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2014 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed 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.springframework.util.xml;
|
||||||
|
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import javax.xml.stream.XMLStreamException;
|
||||||
|
import javax.xml.transform.Result;
|
||||||
|
import javax.xml.transform.dom.DOMResult;
|
||||||
|
import javax.xml.transform.stream.StreamResult;
|
||||||
|
|
||||||
|
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.xml.sax.InputSource;
|
||||||
|
import org.xml.sax.XMLReader;
|
||||||
|
import org.xml.sax.helpers.XMLReaderFactory;
|
||||||
|
|
||||||
|
public abstract class AbstractStaxHandlerTestCase {
|
||||||
|
|
||||||
|
private static final String COMPLEX_XML =
|
||||||
|
"<?xml version='1.0' encoding='UTF-8'?>" +
|
||||||
|
"<!DOCTYPE beans PUBLIC \"-//SPRING//DTD BEAN 2.0//EN\" \"http://www.springframework.org/dtd/spring-beans-2.0.dtd\">" +
|
||||||
|
"<?pi content?><root xmlns='namespace'><prefix:child xmlns:prefix='namespace2' prefix:attr='value'>characters <![CDATA[cdata]]></prefix:child>" +
|
||||||
|
"<!-- comment -->" +
|
||||||
|
"</root>";
|
||||||
|
|
||||||
|
private static final String SIMPLE_XML = "<?xml version='1.0' encoding='UTF-8'?>" +
|
||||||
|
"<?pi content?><root xmlns='namespace'><prefix:child xmlns:prefix='namespace2' prefix:attr='value'>content</prefix:child>" +
|
||||||
|
"</root>";
|
||||||
|
|
||||||
|
|
||||||
|
private XMLReader xmlReader;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void createXMLReader() throws Exception {
|
||||||
|
xmlReader = XMLReaderFactory.createXMLReader();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void noNamespacePrefixes() throws Exception {
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
AbstractStaxHandler handler = createStaxHandler(new StreamResult(stringWriter));
|
||||||
|
xmlReader.setContentHandler(handler);
|
||||||
|
xmlReader.setProperty("http://xml.org/sax/properties/lexical-handler", handler);
|
||||||
|
|
||||||
|
xmlReader.setFeature("http://xml.org/sax/features/namespaces", true);
|
||||||
|
xmlReader.setFeature("http://xml.org/sax/features/namespace-prefixes", false);
|
||||||
|
|
||||||
|
xmlReader.parse(new InputSource(new StringReader(COMPLEX_XML)));
|
||||||
|
|
||||||
|
assertXMLEqual(COMPLEX_XML, stringWriter.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void namespacePrefixes() throws Exception {
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
AbstractStaxHandler handler = createStaxHandler(new StreamResult(stringWriter));
|
||||||
|
xmlReader.setContentHandler(handler);
|
||||||
|
xmlReader.setProperty("http://xml.org/sax/properties/lexical-handler", handler);
|
||||||
|
|
||||||
|
xmlReader.setFeature("http://xml.org/sax/features/namespaces", true);
|
||||||
|
xmlReader.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
|
||||||
|
|
||||||
|
xmlReader.parse(new InputSource(new StringReader(COMPLEX_XML)));
|
||||||
|
|
||||||
|
assertXMLEqual(COMPLEX_XML, stringWriter.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void noNamespacePrefixesDom() throws Exception {
|
||||||
|
DocumentBuilderFactory documentBuilderFactory =
|
||||||
|
DocumentBuilderFactory.newInstance();
|
||||||
|
documentBuilderFactory.setNamespaceAware(true);
|
||||||
|
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
|
||||||
|
|
||||||
|
Document expected = documentBuilder.parse(new InputSource(new StringReader(SIMPLE_XML)));
|
||||||
|
|
||||||
|
Document result = documentBuilder.newDocument();
|
||||||
|
AbstractStaxHandler handler = createStaxHandler(new DOMResult(result));
|
||||||
|
xmlReader.setContentHandler(handler);
|
||||||
|
xmlReader.setProperty("http://xml.org/sax/properties/lexical-handler", handler);
|
||||||
|
|
||||||
|
xmlReader.setFeature("http://xml.org/sax/features/namespaces", true);
|
||||||
|
xmlReader.setFeature("http://xml.org/sax/features/namespace-prefixes", false);
|
||||||
|
|
||||||
|
xmlReader.parse(new InputSource(new StringReader(SIMPLE_XML)));
|
||||||
|
|
||||||
|
assertXMLEqual(expected, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void namespacePrefixesDom() throws Exception {
|
||||||
|
DocumentBuilderFactory documentBuilderFactory =
|
||||||
|
DocumentBuilderFactory.newInstance();
|
||||||
|
documentBuilderFactory.setNamespaceAware(true);
|
||||||
|
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
|
||||||
|
|
||||||
|
Document expected = documentBuilder.parse(new InputSource(new StringReader(SIMPLE_XML)));
|
||||||
|
|
||||||
|
Document result = documentBuilder.newDocument();
|
||||||
|
AbstractStaxHandler handler = createStaxHandler(new DOMResult(result));
|
||||||
|
xmlReader.setContentHandler(handler);
|
||||||
|
xmlReader.setProperty("http://xml.org/sax/properties/lexical-handler", handler);
|
||||||
|
|
||||||
|
xmlReader.setFeature("http://xml.org/sax/features/namespaces", true);
|
||||||
|
xmlReader.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
|
||||||
|
|
||||||
|
xmlReader.parse(new InputSource(new StringReader(SIMPLE_XML)));
|
||||||
|
|
||||||
|
assertXMLEqual(expected, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected abstract AbstractStaxHandler createStaxHandler(Result result) throws XMLStreamException;
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2002-2014 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -17,18 +17,14 @@
|
||||||
package org.springframework.util.xml;
|
package org.springframework.util.xml;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
import javax.xml.stream.XMLInputFactory;
|
import javax.xml.stream.XMLInputFactory;
|
||||||
import javax.xml.stream.XMLStreamException;
|
import javax.xml.stream.XMLStreamException;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import static org.mockito.BDDMockito.*;
|
||||||
import org.mockito.invocation.InvocationOnMock;
|
import org.mockito.invocation.InvocationOnMock;
|
||||||
import org.mockito.stubbing.Answer;
|
import org.mockito.stubbing.Answer;
|
||||||
import org.springframework.core.io.ClassPathResource;
|
|
||||||
import org.springframework.core.io.Resource;
|
|
||||||
import org.springframework.tests.MockitoUtils;
|
|
||||||
import org.springframework.tests.MockitoUtils.InvocationArgumentsAdapter;
|
|
||||||
import org.xml.sax.Attributes;
|
import org.xml.sax.Attributes;
|
||||||
import org.xml.sax.ContentHandler;
|
import org.xml.sax.ContentHandler;
|
||||||
import org.xml.sax.InputSource;
|
import org.xml.sax.InputSource;
|
||||||
|
@ -38,7 +34,10 @@ import org.xml.sax.ext.LexicalHandler;
|
||||||
import org.xml.sax.helpers.AttributesImpl;
|
import org.xml.sax.helpers.AttributesImpl;
|
||||||
import org.xml.sax.helpers.XMLReaderFactory;
|
import org.xml.sax.helpers.XMLReaderFactory;
|
||||||
|
|
||||||
import static org.mockito.BDDMockito.*;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.tests.MockitoUtils;
|
||||||
|
import org.springframework.tests.MockitoUtils.InvocationArgumentsAdapter;
|
||||||
|
|
||||||
public abstract class AbstractStaxXMLReaderTestCase {
|
public abstract class AbstractStaxXMLReaderTestCase {
|
||||||
|
|
||||||
|
@ -224,6 +223,9 @@ public abstract class AbstractStaxXMLReaderTestCase {
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
Attributes other = ((PartialAttributes) obj).attributes;
|
Attributes other = ((PartialAttributes) obj).attributes;
|
||||||
|
if (this.attributes.getLength() != other.getLength()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
for (int i = 0; i < other.getLength(); i++) {
|
for (int i = 0; i < other.getLength(); i++) {
|
||||||
boolean found = false;
|
boolean found = false;
|
||||||
for (int j = 0; j < attributes.getLength(); j++) {
|
for (int j = 0; j < attributes.getLength(); j++) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2009 the original author or authors.
|
* Copyright 2002-2014 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -16,15 +16,22 @@
|
||||||
|
|
||||||
package org.springframework.util.xml;
|
package org.springframework.util.xml;
|
||||||
|
|
||||||
import java.io.Writer;
|
import javax.xml.stream.XMLEventWriter;
|
||||||
import javax.xml.stream.XMLOutputFactory;
|
import javax.xml.stream.XMLOutputFactory;
|
||||||
import javax.xml.stream.XMLStreamException;
|
import javax.xml.stream.XMLStreamException;
|
||||||
|
import javax.xml.transform.Result;
|
||||||
|
|
||||||
public class StaxEventContentHandlerTests extends AbstractStaxContentHandlerTestCase {
|
/**
|
||||||
|
* @author Arjen Poutsma
|
||||||
|
*/
|
||||||
|
public class StaxEventHandlerTests extends AbstractStaxHandlerTestCase {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AbstractStaxContentHandler createStaxContentHandler(Writer writer) throws XMLStreamException {
|
protected AbstractStaxHandler createStaxHandler(Result result)
|
||||||
XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
|
throws XMLStreamException {
|
||||||
return new StaxEventContentHandler(outputFactory.createXMLEventWriter(writer));
|
XMLOutputFactory outputFactory = XMLOutputFactory.newFactory();
|
||||||
|
XMLEventWriter eventWriter = outputFactory.createXMLEventWriter(result);
|
||||||
|
return new StaxEventHandler(eventWriter);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2009 the original author or authors.
|
* Copyright 2002-2014 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -16,15 +16,22 @@
|
||||||
|
|
||||||
package org.springframework.util.xml;
|
package org.springframework.util.xml;
|
||||||
|
|
||||||
import java.io.Writer;
|
|
||||||
import javax.xml.stream.XMLOutputFactory;
|
import javax.xml.stream.XMLOutputFactory;
|
||||||
import javax.xml.stream.XMLStreamException;
|
import javax.xml.stream.XMLStreamException;
|
||||||
|
import javax.xml.stream.XMLStreamWriter;
|
||||||
|
import javax.xml.transform.Result;
|
||||||
|
|
||||||
public class StaxStreamContentHandlerTests extends AbstractStaxContentHandlerTestCase {
|
/**
|
||||||
|
* @author Arjen Poutsma
|
||||||
|
*/
|
||||||
|
public class StaxStreamHandlerTests extends AbstractStaxHandlerTestCase {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AbstractStaxContentHandler createStaxContentHandler(Writer writer) throws XMLStreamException {
|
protected AbstractStaxHandler createStaxHandler(Result result)
|
||||||
XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
|
throws XMLStreamException {
|
||||||
return new StaxStreamContentHandler(outputFactory.createXMLStreamWriter(writer));
|
XMLOutputFactory outputFactory = XMLOutputFactory.newFactory();
|
||||||
|
XMLStreamWriter streamWriter = outputFactory.createXMLStreamWriter(result);
|
||||||
|
return new StaxStreamHandler(streamWriter);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
}
|
|
@ -1,2 +1,2 @@
|
||||||
<h:hello xmlns:h="http://www.greeting.com/hello/" id="a1" h:person="David"><goodbye
|
<h:hello xmlns:h="http://www.greeting.com/hello/" id="a1" h:person="David"><prefix:goodbye
|
||||||
xmlns="http://www.greeting.com/goodbye/" h:person="Arjen"/></h:hello>
|
xmlns:prefix="http://www.greeting.com/goodbye/" h:person="Arjen"/></h:hello>
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2002-2014 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -509,12 +509,22 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void marshalXmlEventWriter(Object graph, XMLEventWriter eventWriter) throws XmlMappingException {
|
protected void marshalXmlEventWriter(Object graph, XMLEventWriter eventWriter) throws XmlMappingException {
|
||||||
marshalSaxHandlers(graph, StaxUtils.createContentHandler(eventWriter), null);
|
ContentHandler contentHandler = StaxUtils.createContentHandler(eventWriter);
|
||||||
|
LexicalHandler lexicalHandler = null;
|
||||||
|
if (contentHandler instanceof LexicalHandler) {
|
||||||
|
lexicalHandler = (LexicalHandler) contentHandler;
|
||||||
|
}
|
||||||
|
marshalSaxHandlers(graph, contentHandler, lexicalHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void marshalXmlStreamWriter(Object graph, XMLStreamWriter streamWriter) throws XmlMappingException {
|
protected void marshalXmlStreamWriter(Object graph, XMLStreamWriter streamWriter) throws XmlMappingException {
|
||||||
marshalSaxHandlers(graph, StaxUtils.createContentHandler(streamWriter), null);
|
ContentHandler contentHandler = StaxUtils.createContentHandler(streamWriter);
|
||||||
|
LexicalHandler lexicalHandler = null;
|
||||||
|
if (contentHandler instanceof LexicalHandler) {
|
||||||
|
lexicalHandler = (LexicalHandler) contentHandler;
|
||||||
|
}
|
||||||
|
marshalSaxHandlers(graph, StaxUtils.createContentHandler(streamWriter), lexicalHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -21,10 +21,10 @@ import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.nio.CharBuffer;
|
import java.nio.CharBuffer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import javax.xml.stream.XMLEventReader;
|
import javax.xml.stream.XMLEventReader;
|
||||||
import javax.xml.stream.XMLEventWriter;
|
import javax.xml.stream.XMLEventWriter;
|
||||||
import javax.xml.stream.XMLStreamReader;
|
import javax.xml.stream.XMLStreamReader;
|
||||||
|
@ -142,13 +142,21 @@ public class XmlBeansMarshaller extends AbstractMarshaller {
|
||||||
@Override
|
@Override
|
||||||
protected void marshalXmlEventWriter(Object graph, XMLEventWriter eventWriter) {
|
protected void marshalXmlEventWriter(Object graph, XMLEventWriter eventWriter) {
|
||||||
ContentHandler contentHandler = StaxUtils.createContentHandler(eventWriter);
|
ContentHandler contentHandler = StaxUtils.createContentHandler(eventWriter);
|
||||||
marshalSaxHandlers(graph, contentHandler, null);
|
LexicalHandler lexicalHandler = null;
|
||||||
|
if (contentHandler instanceof LexicalHandler) {
|
||||||
|
lexicalHandler = (LexicalHandler) contentHandler;
|
||||||
|
}
|
||||||
|
marshalSaxHandlers(graph, contentHandler, lexicalHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void marshalXmlStreamWriter(Object graph, XMLStreamWriter streamWriter) throws XmlMappingException {
|
protected void marshalXmlStreamWriter(Object graph, XMLStreamWriter streamWriter) throws XmlMappingException {
|
||||||
ContentHandler contentHandler = StaxUtils.createContentHandler(streamWriter);
|
ContentHandler contentHandler = StaxUtils.createContentHandler(streamWriter);
|
||||||
marshalSaxHandlers(graph, contentHandler, null);
|
LexicalHandler lexicalHandler = null;
|
||||||
|
if (contentHandler instanceof LexicalHandler) {
|
||||||
|
lexicalHandler = (LexicalHandler) contentHandler;
|
||||||
|
}
|
||||||
|
marshalSaxHandlers(graph, contentHandler, lexicalHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -27,8 +27,11 @@ import java.lang.reflect.Constructor;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import javax.xml.stream.XMLEventReader;
|
||||||
import javax.xml.stream.*;
|
import javax.xml.stream.XMLEventWriter;
|
||||||
|
import javax.xml.stream.XMLStreamException;
|
||||||
|
import javax.xml.stream.XMLStreamReader;
|
||||||
|
import javax.xml.stream.XMLStreamWriter;
|
||||||
import javax.xml.transform.stream.StreamSource;
|
import javax.xml.transform.stream.StreamSource;
|
||||||
|
|
||||||
import com.thoughtworks.xstream.MarshallingStrategy;
|
import com.thoughtworks.xstream.MarshallingStrategy;
|
||||||
|
@ -59,11 +62,9 @@ import com.thoughtworks.xstream.io.xml.XppDriver;
|
||||||
import com.thoughtworks.xstream.mapper.CannotResolveClassException;
|
import com.thoughtworks.xstream.mapper.CannotResolveClassException;
|
||||||
import com.thoughtworks.xstream.mapper.Mapper;
|
import com.thoughtworks.xstream.mapper.Mapper;
|
||||||
import com.thoughtworks.xstream.mapper.MapperWrapper;
|
import com.thoughtworks.xstream.mapper.MapperWrapper;
|
||||||
|
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
|
|
||||||
import org.xml.sax.ContentHandler;
|
import org.xml.sax.ContentHandler;
|
||||||
import org.xml.sax.InputSource;
|
import org.xml.sax.InputSource;
|
||||||
import org.xml.sax.XMLReader;
|
import org.xml.sax.XMLReader;
|
||||||
|
@ -627,7 +628,11 @@ public class XStreamMarshaller extends AbstractMarshaller implements Initializin
|
||||||
@Override
|
@Override
|
||||||
protected void marshalXmlEventWriter(Object graph, XMLEventWriter eventWriter) throws XmlMappingException {
|
protected void marshalXmlEventWriter(Object graph, XMLEventWriter eventWriter) throws XmlMappingException {
|
||||||
ContentHandler contentHandler = StaxUtils.createContentHandler(eventWriter);
|
ContentHandler contentHandler = StaxUtils.createContentHandler(eventWriter);
|
||||||
marshalSaxHandlers(graph, contentHandler, null);
|
LexicalHandler lexicalHandler = null;
|
||||||
|
if (contentHandler instanceof LexicalHandler) {
|
||||||
|
lexicalHandler = (LexicalHandler) contentHandler;
|
||||||
|
}
|
||||||
|
marshalSaxHandlers(graph, contentHandler, lexicalHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -75,6 +75,7 @@ public class CastorMarshallerTests extends AbstractMarshallerTests {
|
||||||
*/
|
*/
|
||||||
private static final String XSI_EXPECTED_STRING = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
|
private static final String XSI_EXPECTED_STRING = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
|
||||||
+ "<objects><castor-object xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
|
+ "<objects><castor-object xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
|
||||||
|
+ " xmlns:java=\"http://java.sun.com\""
|
||||||
+ " xsi:type=\"java:org.springframework.oxm.castor.CastorObject\">"
|
+ " xsi:type=\"java:org.springframework.oxm.castor.CastorObject\">"
|
||||||
+ "<name>test</name><value>8</value></castor-object></objects>";
|
+ "<name>test</name><value>8</value></castor-object></objects>";
|
||||||
|
|
||||||
|
@ -89,6 +90,7 @@ public class CastorMarshallerTests extends AbstractMarshallerTests {
|
||||||
*/
|
*/
|
||||||
private static final String ROOT_WITH_XSI_EXPECTED_STRING = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
|
private static final String ROOT_WITH_XSI_EXPECTED_STRING = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
|
||||||
+ "<objects xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
|
+ "<objects xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
|
||||||
|
+ " xmlns:java=\"http://java.sun.com\""
|
||||||
+ " xsi:type=\"java:java.util.Arrays$ArrayList\">"
|
+ " xsi:type=\"java:java.util.Arrays$ArrayList\">"
|
||||||
+ "<castor-object xsi:type=\"java:org.springframework.oxm.castor.CastorObject\">"
|
+ "<castor-object xsi:type=\"java:org.springframework.oxm.castor.CastorObject\">"
|
||||||
+ "<name>test</name><value>8</value></castor-object></objects>";
|
+ "<name>test</name><value>8</value></castor-object></objects>";
|
||||||
|
@ -98,6 +100,7 @@ public class CastorMarshallerTests extends AbstractMarshallerTests {
|
||||||
*/
|
*/
|
||||||
private static final String ROOT_WITHOUT_XSI_EXPECTED_STRING = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
|
private static final String ROOT_WITHOUT_XSI_EXPECTED_STRING = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
|
||||||
+ "<objects><castor-object xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
|
+ "<objects><castor-object xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
|
||||||
|
+ " xmlns:java=\"http://java.sun.com\""
|
||||||
+ " xsi:type=\"java:org.springframework.oxm.castor.CastorObject\">"
|
+ " xsi:type=\"java:org.springframework.oxm.castor.CastorObject\">"
|
||||||
+ "<name>test</name><value>8</value></castor-object></objects>";
|
+ "<name>test</name><value>8</value></castor-object></objects>";
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue