Added support for unmarshalling XML fragments, requested by Spring Batch.

This commit is contained in:
Arjen Poutsma
2007-08-15 23:34:27 +00:00
parent 6feb315196
commit 7a60ba32f3
11 changed files with 232 additions and 62 deletions

View File

@@ -23,6 +23,7 @@ import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.Characters;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.EntityDeclaration;
import javax.xml.stream.events.Namespace;
import javax.xml.stream.events.NotationDeclaration;
import javax.xml.stream.events.ProcessingInstruction;
@@ -72,15 +73,26 @@ public class StaxEventXmlReader extends AbstractStaxXmlReader {
}
protected void parseInternal() throws SAXException, XMLStreamException {
boolean documentStarted = false;
boolean documentEnded = false;
while (reader.hasNext()) {
XMLEvent event = reader.nextEvent();
int elementDepth = 0;
XMLEvent event = null;
while (reader.hasNext() && elementDepth >= 0) {
event = reader.nextEvent();
if (!event.isStartDocument() && !event.isEndDocument() && !documentStarted) {
handleStartDocument();
documentStarted = true;
}
switch (event.getEventType()) {
case XMLStreamConstants.START_ELEMENT:
elementDepth++;
handleStartElement(event.asStartElement());
break;
case XMLStreamConstants.END_ELEMENT:
handleEndElement(event.asEndElement());
elementDepth--;
if (elementDepth >= 0) {
handleEndElement(event.asEndElement());
}
break;
case XMLStreamConstants.PROCESSING_INSTRUCTION:
handleProcessingInstruction((ProcessingInstruction) event);
@@ -93,6 +105,7 @@ public class StaxEventXmlReader extends AbstractStaxXmlReader {
case XMLStreamConstants.START_DOCUMENT:
setLocator(event.getLocation());
handleStartDocument();
documentStarted = true;
break;
case XMLStreamConstants.END_DOCUMENT:
handleEndDocument();
@@ -101,6 +114,9 @@ public class StaxEventXmlReader extends AbstractStaxXmlReader {
case XMLStreamConstants.NOTATION_DECLARATION:
handleNotationDeclaration((NotationDeclaration) event);
break;
case XMLStreamConstants.ENTITY_DECLARATION:
handleEntityDeclaration((EntityDeclaration) event);
break;
}
}
if (!documentEnded) {
@@ -145,6 +161,13 @@ public class StaxEventXmlReader extends AbstractStaxXmlReader {
}
}
private void handleEntityDeclaration(EntityDeclaration entityDeclaration) throws SAXException {
if (getDTDHandler() != null) {
getDTDHandler().unparsedEntityDecl(entityDeclaration.getName(), entityDeclaration.getPublicId(),
entityDeclaration.getSystemId(), entityDeclaration.getNotationName());
}
}
private void handleProcessingInstruction(ProcessingInstruction pi) throws SAXException {
if (getContentHandler() != null) {
getContentHandler().processingInstruction(pi.getTarget(), pi.getData());

View File

@@ -58,14 +58,26 @@ public class StaxStreamXmlReader extends AbstractStaxXmlReader {
}
protected void parseInternal() throws SAXException, XMLStreamException {
boolean documentStarted = false;
boolean documentEnded = false;
int elementDepth = 0;
int eventType = reader.getEventType();
while (true) {
switch (reader.getEventType()) {
if (eventType != XMLStreamConstants.START_DOCUMENT && eventType != XMLStreamConstants.END_DOCUMENT &&
!documentStarted) {
handleStartDocument();
documentStarted = true;
}
switch (eventType) {
case XMLStreamConstants.START_ELEMENT:
elementDepth++;
handleStartElement();
break;
case XMLStreamConstants.END_ELEMENT:
handleEndElement();
elementDepth--;
if (elementDepth >= 0) {
handleEndElement();
}
break;
case XMLStreamConstants.PROCESSING_INSTRUCTION:
handleProcessingInstruction();
@@ -76,15 +88,17 @@ public class StaxStreamXmlReader extends AbstractStaxXmlReader {
handleCharacters();
break;
case XMLStreamConstants.START_DOCUMENT:
setLocator(reader.getLocation());
handleStartDocument();
documentStarted = true;
break;
case XMLStreamConstants.END_DOCUMENT:
handleEndDocument();
documentEnded = true;
break;
}
if (reader.hasNext()) {
reader.next();
if (reader.hasNext() && elementDepth >= 0) {
eventType = reader.next();
}
else {
break;
@@ -137,7 +151,6 @@ public class StaxStreamXmlReader extends AbstractStaxXmlReader {
}
private void handleStartDocument() throws SAXException {
setLocator(reader.getLocation());
if (getContentHandler() != null) {
getContentHandler().startDocument();
}

View File

@@ -20,6 +20,7 @@ import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.Arrays;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import junit.framework.TestCase;
@@ -36,6 +37,8 @@ import org.xml.sax.helpers.XMLReaderFactory;
public abstract class AbstractStaxXmlReaderTestCase extends TestCase {
protected static XMLInputFactory inputFactory = XMLInputFactory.newInstance();
private static final String XML_DTD_HANDLER =
"<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'><beans />";
@@ -96,7 +99,7 @@ public abstract class AbstractStaxXmlReaderTestCase extends TestCase {
protected abstract AbstractStaxXmlReader createStaxXmlReader(Reader reader) throws XMLStreamException;
/** Easymock <code>ArgumentMatcher</code> implementation that matches SAX arguments. */
private static class SaxArgumentMatcher extends AbstractMatcher {
protected static class SaxArgumentMatcher extends AbstractMatcher {
public boolean matches(Object[] expected, Object[] actual) {
if (expected == actual) {
@@ -108,14 +111,14 @@ public abstract class AbstractStaxXmlReaderTestCase extends TestCase {
if (expected.length != actual.length) {
throw new IllegalArgumentException("Expected and actual arguments must have the same size");
}
if (expected.length == 3 && (expected[0] instanceof char[]) && (expected[1] instanceof Integer) &&
(expected[2] instanceof Integer)) {
if (expected.length == 3 && expected[0] instanceof char[] && expected[1] instanceof Integer &&
expected[2] instanceof Integer) {
// handling of the character(char[], int, int) methods
String expectedString = new String((char[]) expected[0], ((Integer) expected[1]).intValue(),
((Integer) expected[2]).intValue());
String actualString = new String((char[]) actual[0], ((Integer) actual[1]).intValue(),
((Integer) actual[2]).intValue());
return (expectedString.equals(actualString));
return expectedString.equals(actualString);
}
else if (expected.length == 1 && (expected[0] instanceof Locator)) {
return true;
@@ -148,8 +151,8 @@ public abstract class AbstractStaxXmlReaderTestCase extends TestCase {
else if (expected instanceof Locator) {
Locator expectedLocator = (Locator) expected;
Locator actualLocator = (Locator) actual;
return (expectedLocator.getColumnNumber() == actualLocator.getColumnNumber() &&
expectedLocator.getLineNumber() == actualLocator.getLineNumber());
return expectedLocator.getColumnNumber() == actualLocator.getColumnNumber() &&
expectedLocator.getLineNumber() == actualLocator.getLineNumber();
}
return super.argumentMatches(expected, actual);
}

View File

@@ -17,14 +17,44 @@
package org.springframework.xml.stream;
import java.io.Reader;
import java.io.StringReader;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import org.easymock.MockControl;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.helpers.AttributesImpl;
public class StaxEventXmlReaderTest extends AbstractStaxXmlReaderTestCase {
public static final String CONTENT = "<root xmlns='http://springframework.org/spring-ws'><child/></root>";
protected AbstractStaxXmlReader createStaxXmlReader(Reader reader) throws XMLStreamException {
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
return new StaxEventXmlReader(inputFactory.createXMLEventReader(reader));
}
public void testPartial() throws Exception {
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
XMLEventReader eventReader = inputFactory.createXMLEventReader(new StringReader(CONTENT));
eventReader.nextTag(); // skip to root
StaxEventXmlReader xmlReader = new StaxEventXmlReader(eventReader);
MockControl mockControl = MockControl.createStrictControl(ContentHandler.class);
mockControl.setDefaultMatcher(new SaxArgumentMatcher());
ContentHandler contentHandlerMock = (ContentHandler) mockControl.getMock();
contentHandlerMock.startDocument();
contentHandlerMock.startElement("http://springframework.org/spring-ws", "child", "child", new AttributesImpl());
contentHandlerMock.endElement("http://springframework.org/spring-ws", "child", "child");
contentHandlerMock.endDocument();
xmlReader.setContentHandler(contentHandlerMock);
mockControl.replay();
xmlReader.parse(new InputSource());
mockControl.verify();
}
}

View File

@@ -17,14 +17,50 @@
package org.springframework.xml.stream;
import java.io.Reader;
import java.io.StringReader;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import org.easymock.MockControl;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.helpers.AttributesImpl;
public class StaxStreamXmlReaderTest extends AbstractStaxXmlReaderTestCase {
public static final String CONTENT = "<root xmlns='http://springframework.org/spring-ws'><child/></root>";
protected AbstractStaxXmlReader createStaxXmlReader(Reader reader) throws XMLStreamException {
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
return new StaxStreamXmlReader(inputFactory.createXMLStreamReader(reader));
}
public void testPartial() throws Exception {
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
XMLStreamReader streamReader = inputFactory.createXMLStreamReader(new StringReader(CONTENT));
streamReader.nextTag(); // skip to root
assertEquals("Invalid element", new QName("http://springframework.org/spring-ws", "root"),
streamReader.getName());
streamReader.nextTag(); // skip to child
assertEquals("Invalid element", new QName("http://springframework.org/spring-ws", "child"),
streamReader.getName());
StaxStreamXmlReader xmlReader = new StaxStreamXmlReader(streamReader);
MockControl mockControl = MockControl.createStrictControl(ContentHandler.class);
mockControl.setDefaultMatcher(new SaxArgumentMatcher());
ContentHandler contentHandlerMock = (ContentHandler) mockControl.getMock();
contentHandlerMock.startDocument();
contentHandlerMock.startElement("http://springframework.org/spring-ws", "child", "child", new AttributesImpl());
contentHandlerMock.endElement("http://springframework.org/spring-ws", "child", "child");
contentHandlerMock.endDocument();
xmlReader.setContentHandler(contentHandlerMock);
mockControl.replay();
xmlReader.parse(new InputSource());
mockControl.verify();
}
}