Making the StAX-based XML readers and handlers more compliant
This commit is contained in:
@@ -23,8 +23,11 @@ import javax.xml.stream.XMLStreamConstants;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.events.Attribute;
|
||||
import javax.xml.stream.events.Characters;
|
||||
import javax.xml.stream.events.Comment;
|
||||
import javax.xml.stream.events.DTD;
|
||||
import javax.xml.stream.events.EndElement;
|
||||
import javax.xml.stream.events.EntityDeclaration;
|
||||
import javax.xml.stream.events.EntityReference;
|
||||
import javax.xml.stream.events.Namespace;
|
||||
import javax.xml.stream.events.NotationDeclaration;
|
||||
import javax.xml.stream.events.ProcessingInstruction;
|
||||
@@ -120,6 +123,15 @@ public class StaxEventXmlReader extends AbstractStaxXmlReader {
|
||||
case XMLStreamConstants.ENTITY_DECLARATION:
|
||||
handleEntityDeclaration((EntityDeclaration) event);
|
||||
break;
|
||||
case XMLStreamConstants.COMMENT:
|
||||
handleComment((Comment) event);
|
||||
break;
|
||||
case XMLStreamConstants.DTD:
|
||||
handleDtd((DTD) event);
|
||||
break;
|
||||
case XMLStreamConstants.ENTITY_REFERENCE:
|
||||
handleEntityReference((EntityReference) event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!documentEnded) {
|
||||
@@ -128,24 +140,41 @@ public class StaxEventXmlReader extends AbstractStaxXmlReader {
|
||||
|
||||
}
|
||||
|
||||
private void handleCharacters(Characters characters) throws SAXException {
|
||||
private void handleStartElement(StartElement startElement) throws SAXException {
|
||||
if (getContentHandler() != null) {
|
||||
if (characters.isIgnorableWhiteSpace()) {
|
||||
getContentHandler()
|
||||
.ignorableWhitespace(characters.getData().toCharArray(), 0, characters.getData().length());
|
||||
QName qName = startElement.getName();
|
||||
if (hasNamespacesFeature()) {
|
||||
for (Iterator i = startElement.getNamespaces(); i.hasNext();) {
|
||||
Namespace namespace = (Namespace) i.next();
|
||||
getContentHandler().startPrefixMapping(namespace.getPrefix(), namespace.getNamespaceURI());
|
||||
}
|
||||
getContentHandler().startElement(qName.getNamespaceURI(), qName.getLocalPart(),
|
||||
QNameUtils.toQualifiedName(qName), getAttributes(startElement));
|
||||
}
|
||||
else {
|
||||
if (characters.isCData() && getLexicalHandler() != null) {
|
||||
getLexicalHandler().startCDATA();
|
||||
}
|
||||
getContentHandler().characters(characters.getData().toCharArray(), 0, characters.getData().length());
|
||||
if (characters.isCData() && getLexicalHandler() != null) {
|
||||
getLexicalHandler().endCDATA();
|
||||
}
|
||||
getContentHandler()
|
||||
.startElement("", "", QNameUtils.toQualifiedName(qName), getAttributes(startElement));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleCharacters(Characters characters) throws SAXException {
|
||||
char[] data = characters.getData().toCharArray();
|
||||
if (getContentHandler() != null && characters.isIgnorableWhiteSpace()) {
|
||||
getContentHandler().ignorableWhitespace(data, 0, data.length);
|
||||
return;
|
||||
}
|
||||
if (characters.isCData() && getLexicalHandler() != null) {
|
||||
getLexicalHandler().startCDATA();
|
||||
}
|
||||
if (getContentHandler() != null) {
|
||||
getContentHandler().characters(data, 0, data.length);
|
||||
}
|
||||
if (characters.isCData() && getLexicalHandler() != null) {
|
||||
getLexicalHandler().endCDATA();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleEndDocument() throws SAXException {
|
||||
if (getContentHandler() != null) {
|
||||
getContentHandler().endDocument();
|
||||
@@ -195,24 +224,34 @@ public class StaxEventXmlReader extends AbstractStaxXmlReader {
|
||||
}
|
||||
}
|
||||
|
||||
private void handleStartElement(StartElement startElement) throws SAXException {
|
||||
if (getContentHandler() != null) {
|
||||
QName qName = startElement.getName();
|
||||
if (hasNamespacesFeature()) {
|
||||
for (Iterator i = startElement.getNamespaces(); i.hasNext();) {
|
||||
Namespace namespace = (Namespace) i.next();
|
||||
getContentHandler().startPrefixMapping(namespace.getPrefix(), namespace.getNamespaceURI());
|
||||
}
|
||||
getContentHandler().startElement(qName.getNamespaceURI(), qName.getLocalPart(),
|
||||
QNameUtils.toQualifiedName(qName), getAttributes(startElement));
|
||||
}
|
||||
else {
|
||||
getContentHandler()
|
||||
.startElement("", "", QNameUtils.toQualifiedName(qName), getAttributes(startElement));
|
||||
}
|
||||
private void handleComment(Comment comment) throws SAXException {
|
||||
if (getLexicalHandler() != null) {
|
||||
char[] ch = comment.getText().toCharArray();
|
||||
getLexicalHandler().comment(ch, 0, ch.length);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleDtd(DTD dtd) throws SAXException {
|
||||
if (getLexicalHandler() != null) {
|
||||
javax.xml.stream.Location location = dtd.getLocation();
|
||||
getLexicalHandler().startDTD(null, location.getPublicId(), location.getSystemId());
|
||||
}
|
||||
if (getLexicalHandler() != null) {
|
||||
getLexicalHandler().endDTD();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void handleEntityReference(EntityReference reference) throws SAXException {
|
||||
if (getLexicalHandler() != null) {
|
||||
getLexicalHandler().startEntity(reference.getName());
|
||||
}
|
||||
if (getLexicalHandler() != null) {
|
||||
getLexicalHandler().endEntity(reference.getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Attributes getAttributes(StartElement event) {
|
||||
AttributesImpl attributes = new AttributesImpl();
|
||||
|
||||
@@ -249,5 +288,4 @@ public class StaxEventXmlReader extends AbstractStaxXmlReader {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -99,6 +99,15 @@ public class StaxStreamXmlReader extends AbstractStaxXmlReader {
|
||||
handleEndDocument();
|
||||
documentEnded = true;
|
||||
break;
|
||||
case XMLStreamConstants.COMMENT:
|
||||
handleComment();
|
||||
break;
|
||||
case XMLStreamConstants.DTD:
|
||||
handleDtd();
|
||||
break;
|
||||
case XMLStreamConstants.ENTITY_REFERENCE:
|
||||
handleEntityReference();
|
||||
break;
|
||||
}
|
||||
if (reader.hasNext() && elementDepth >= 0) {
|
||||
eventType = reader.next();
|
||||
@@ -110,7 +119,6 @@ public class StaxStreamXmlReader extends AbstractStaxXmlReader {
|
||||
if (!documentEnded) {
|
||||
handleEndDocument();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void handleStartDocument() throws SAXException {
|
||||
@@ -163,15 +171,45 @@ public class StaxStreamXmlReader extends AbstractStaxXmlReader {
|
||||
}
|
||||
|
||||
private void handleCharacters() throws SAXException {
|
||||
if (getContentHandler() != null && reader.isWhiteSpace()) {
|
||||
getContentHandler()
|
||||
.ignorableWhitespace(reader.getTextCharacters(), reader.getTextStart(), reader.getTextLength());
|
||||
return;
|
||||
}
|
||||
if (XMLStreamConstants.CDATA == reader.getEventType() && getLexicalHandler() != null) {
|
||||
getLexicalHandler().startCDATA();
|
||||
}
|
||||
if (getContentHandler() != null) {
|
||||
if (reader.isWhiteSpace()) {
|
||||
getContentHandler()
|
||||
.ignorableWhitespace(reader.getTextCharacters(), reader.getTextStart(), reader.getTextLength());
|
||||
}
|
||||
else {
|
||||
getContentHandler()
|
||||
.characters(reader.getTextCharacters(), reader.getTextStart(), reader.getTextLength());
|
||||
}
|
||||
getContentHandler()
|
||||
.characters(reader.getTextCharacters(), reader.getTextStart(), reader.getTextLength());
|
||||
}
|
||||
if (XMLStreamConstants.CDATA == reader.getEventType() && getLexicalHandler() != null) {
|
||||
getLexicalHandler().endCDATA();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleComment() throws SAXException {
|
||||
if (getLexicalHandler() != null) {
|
||||
getLexicalHandler().comment(reader.getTextCharacters(), reader.getTextStart(), reader.getTextLength());
|
||||
}
|
||||
}
|
||||
|
||||
private void handleDtd() throws SAXException {
|
||||
if (getLexicalHandler() != null) {
|
||||
javax.xml.stream.Location location = reader.getLocation();
|
||||
getLexicalHandler().startDTD(null, location.getPublicId(), location.getSystemId());
|
||||
}
|
||||
if (getLexicalHandler() != null) {
|
||||
getLexicalHandler().endDTD();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleEntityReference() throws SAXException {
|
||||
if (getLexicalHandler() != null) {
|
||||
getLexicalHandler().startEntity(reader.getLocalName());
|
||||
}
|
||||
if (getLexicalHandler() != null) {
|
||||
getLexicalHandler().endEntity(reader.getLocalName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.xml.sax.InputSource;
|
||||
import org.xml.sax.Locator;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.ext.LexicalHandler;
|
||||
import org.xml.sax.helpers.AttributesImpl;
|
||||
import org.xml.sax.helpers.XMLReaderFactory;
|
||||
|
||||
@@ -40,7 +41,7 @@ import org.springframework.xml.sax.SaxUtils;
|
||||
|
||||
public abstract class AbstractStaxXmlReaderTestCase extends TestCase {
|
||||
|
||||
protected static XMLInputFactory inputFactory = XMLInputFactory.newInstance();
|
||||
protected static XMLInputFactory inputFactory;
|
||||
|
||||
private Resource testContentHandler;
|
||||
|
||||
@@ -51,6 +52,7 @@ public abstract class AbstractStaxXmlReaderTestCase extends TestCase {
|
||||
private ContentHandler contentHandler;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
inputFactory = XMLInputFactory.newInstance();
|
||||
standardReader = XMLReaderFactory.createXMLReader();
|
||||
contentHandlerControl = MockControl.createStrictControl(ContentHandler.class);
|
||||
contentHandlerControl.setDefaultMatcher(new SaxArgumentMatcher());
|
||||
@@ -109,6 +111,32 @@ public abstract class AbstractStaxXmlReaderTestCase extends TestCase {
|
||||
contentHandlerControl.verify();
|
||||
}
|
||||
|
||||
public void testLexicalHandler() throws SAXException, IOException, XMLStreamException {
|
||||
|
||||
MockControl lexicalHandlerControl = MockControl.createStrictControl(LexicalHandler.class);
|
||||
lexicalHandlerControl.setDefaultMatcher(new SaxArgumentMatcher());
|
||||
LexicalHandler lexicalHandlerMock = (LexicalHandler) lexicalHandlerControl.getMock();
|
||||
LexicalHandler lexicalHandler = new CopyingLexicalHandler(lexicalHandlerMock);
|
||||
|
||||
Resource testLexicalHandlerXml = new ClassPathResource("testLexicalHandler.xml", getClass());
|
||||
|
||||
standardReader.setContentHandler(null);
|
||||
standardReader.setProperty("http://xml.org/sax/properties/lexical-handler", lexicalHandler);
|
||||
standardReader.parse(SaxUtils.createInputSource(testLexicalHandlerXml));
|
||||
lexicalHandlerControl.replay();
|
||||
|
||||
inputFactory.setProperty("javax.xml.stream.isCoalescing", Boolean.FALSE);
|
||||
inputFactory.setProperty("http://java.sun.com/xml/stream/properties/report-cdata-event", Boolean.TRUE);
|
||||
inputFactory.setProperty("javax.xml.stream.isReplacingEntityReferences", Boolean.FALSE);
|
||||
inputFactory.setProperty("javax.xml.stream.isSupportingExternalEntities", Boolean.FALSE);
|
||||
|
||||
AbstractStaxXmlReader staxXmlReader = createStaxXmlReader(testLexicalHandlerXml.getInputStream());
|
||||
|
||||
staxXmlReader.setProperty("http://xml.org/sax/properties/lexical-handler", lexicalHandler);
|
||||
staxXmlReader.parse(new InputSource());
|
||||
lexicalHandlerControl.verify();
|
||||
}
|
||||
|
||||
protected abstract AbstractStaxXmlReader createStaxXmlReader(InputStream inputStream) throws XMLStreamException;
|
||||
|
||||
/** Easymock <code>ArgumentMatcher</code> implementation that matches SAX arguments. */
|
||||
@@ -156,7 +184,6 @@ public abstract class AbstractStaxXmlReaderTestCase extends TestCase {
|
||||
for (int j = 0; j < actualAttributes.getLength(); j++) {
|
||||
if (expectedAttributes.getURI(i).equals(actualAttributes.getURI(j)) &&
|
||||
expectedAttributes.getQName(i).equals(actualAttributes.getQName(j)) &&
|
||||
// expectedAttributes.getLocalName(i).equals(actualAttributes.getLocalName(j)) &&
|
||||
expectedAttributes.getType(i).equals(actualAttributes.getType(j)) &&
|
||||
expectedAttributes.getValue(i).equals(actualAttributes.getValue(j))) {
|
||||
found = true;
|
||||
@@ -237,7 +264,7 @@ public abstract class AbstractStaxXmlReaderTestCase extends TestCase {
|
||||
|
||||
private static class CopyingContentHandler implements ContentHandler {
|
||||
|
||||
private ContentHandler wrappee;
|
||||
private final ContentHandler wrappee;
|
||||
|
||||
private CopyingContentHandler(ContentHandler wrappee) {
|
||||
this.wrappee = wrappee;
|
||||
@@ -286,7 +313,43 @@ public abstract class AbstractStaxXmlReaderTestCase extends TestCase {
|
||||
public void skippedEntity(String name) throws SAXException {
|
||||
wrappee.skippedEntity(name);
|
||||
}
|
||||
}
|
||||
|
||||
private static class CopyingLexicalHandler implements LexicalHandler {
|
||||
|
||||
private final LexicalHandler wrappee;
|
||||
|
||||
private CopyingLexicalHandler(LexicalHandler wrappee) {
|
||||
this.wrappee = wrappee;
|
||||
}
|
||||
|
||||
public void startDTD(String name, String publicId, String systemId) throws SAXException {
|
||||
wrappee.startDTD("element", publicId, systemId);
|
||||
}
|
||||
|
||||
public void endDTD() throws SAXException {
|
||||
wrappee.endDTD();
|
||||
}
|
||||
|
||||
public void startEntity(String name) throws SAXException {
|
||||
wrappee.startEntity(name);
|
||||
}
|
||||
|
||||
public void endEntity(String name) throws SAXException {
|
||||
wrappee.endEntity(name);
|
||||
}
|
||||
|
||||
public void startCDATA() throws SAXException {
|
||||
wrappee.startCDATA();
|
||||
}
|
||||
|
||||
public void endCDATA() throws SAXException {
|
||||
wrappee.endCDATA();
|
||||
}
|
||||
|
||||
public void comment(char ch[], int start, int length) throws SAXException {
|
||||
wrappee.comment(copy(ch), start, length);
|
||||
}
|
||||
}
|
||||
|
||||
private static char[] copy(char[] ch) {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE element
|
||||
[<!ENTITY entity "entity">]>
|
||||
<!--Comment-->
|
||||
<element>
|
||||
<cdata><![CDATA[cdata]]></cdata>
|
||||
<entity>&entity;</entity>
|
||||
</element>
|
||||
Reference in New Issue
Block a user