Browse Source

Added StaxStreamContentHandler

conversation
Arjen Poutsma 16 years ago
parent
commit
7bf6d90f20
  1. 167
      org.springframework.core/src/main/java/org/springframework/util/xml/AbstractStaxContentHandler.java
  2. 109
      org.springframework.core/src/main/java/org/springframework/util/xml/StaxStreamContentHandler.java
  3. 66
      org.springframework.core/src/test/java/org/springframework/util/xml/AbstractStaxContentHandlerTestCase.java
  4. 30
      org.springframework.core/src/test/java/org/springframework/util/xml/StaxStreamContentHandlerTest.java

167
org.springframework.core/src/main/java/org/springframework/util/xml/AbstractStaxContentHandler.java

@ -0,0 +1,167 @@ @@ -0,0 +1,167 @@
/*
* 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 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</code> implementations that use StAX as a basis. All methods
* delegate to internal template methods, capable of throwing a <code>XMLStreamException</code>. 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();
public final void startDocument() throws SAXException {
namespaceContext.clear();
try {
startDocumentInternal();
}
catch (XMLStreamException ex) {
throw new SAXException("Could not handle startDocument: " + ex.getMessage(), ex);
}
}
protected abstract void startDocumentInternal() throws XMLStreamException;
public final void endDocument() throws SAXException {
namespaceContext.clear();
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)
*/
public final void startPrefixMapping(String prefix, String uri) {
namespaceContext.bindNamespaceUri(prefix, uri);
}
/**
* Removes the binding for the given prefix.
*
* @see SimpleNamespaceContext#removeBinding(String)
*/
public final void endPrefixMapping(String prefix) {
namespaceContext.removeBinding(prefix);
}
public final void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
try {
startElementInternal(toQName(uri, qName), atts, namespaceContext);
}
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;
public final void endElement(String uri, String localName, String qName) throws SAXException {
try {
endElementInternal(toQName(uri, qName), namespaceContext);
}
catch (XMLStreamException ex) {
throw new SAXException("Could not handle endElement: " + ex.getMessage(), ex);
}
}
protected abstract void endElementInternal(QName name, SimpleNamespaceContext namespaceContext)
throws XMLStreamException;
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;
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;
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;
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</code>. The qualified name can have the form
* <code>prefix:localname</code> or <code>localName</code>.
*
* @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;
}

109
org.springframework.core/src/main/java/org/springframework/util/xml/StaxStreamContentHandler.java

@ -0,0 +1,109 @@ @@ -0,0 +1,109 @@
/*
* 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.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.StringUtils;
/**
* SAX <code>ContentHandler</code> that writes to a <code>XMLStreamWriter</code>.
*
* @author Arjen Poutsma
* @see XMLStreamWriter
* @since 3.0
*/
class StaxStreamContentHandler extends AbstractStaxContentHandler {
private final XMLStreamWriter streamWriter;
/**
* Constructs a new instance of the <code>StaxStreamContentHandler</code> that writes to the given
* <code>XMLStreamWriter</code>.
*
* @param streamWriter the stream writer to write to
*/
StaxStreamContentHandler(XMLStreamWriter streamWriter) {
this.streamWriter = streamWriter;
}
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());
String defaultNamespaceUri = namespaceContext.getNamespaceURI("");
if (StringUtils.hasLength(defaultNamespaceUri)) {
streamWriter.writeNamespace("", defaultNamespaceUri);
streamWriter.setDefaultNamespace(defaultNamespaceUri);
}
for (Iterator iterator = namespaceContext.getBoundPrefixes(); iterator.hasNext();) {
String prefix = (String) 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));
}
}
}
}

66
org.springframework.core/src/test/java/org/springframework/util/xml/AbstractStaxContentHandlerTestCase.java

@ -0,0 +1,66 @@ @@ -0,0 +1,66 @@
/*
* 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;
}

30
org.springframework.core/src/test/java/org/springframework/util/xml/StaxStreamContentHandlerTest.java

@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
/*
* 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.Writer;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
public class StaxStreamContentHandlerTest extends AbstractStaxContentHandlerTestCase {
@Override
protected AbstractStaxContentHandler createStaxContentHandler(Writer writer) throws XMLStreamException {
XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
return new StaxStreamContentHandler(outputFactory.createXMLStreamWriter(writer));
}
}
Loading…
Cancel
Save