diff --git a/core/src/main/java/org/springframework/ws/soap/axiom/AxiomHandler.java b/core/src/main/java/org/springframework/ws/soap/axiom/AxiomHandler.java
new file mode 100644
index 00000000..784f8f8d
--- /dev/null
+++ b/core/src/main/java/org/springframework/ws/soap/axiom/AxiomHandler.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2006 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.ws.soap.axiom;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLStreamConstants;
+
+import org.apache.axiom.om.OMAttribute;
+import org.apache.axiom.om.OMContainer;
+import org.apache.axiom.om.OMElement;
+import org.apache.axiom.om.OMFactory;
+import org.apache.axiom.om.OMNamespace;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.ext.LexicalHandler;
+
+import org.springframework.util.Assert;
+import org.springframework.xml.namespace.QNameUtils;
+
+/**
+ * Specific SAX {@link ContentHandler} and {@link LexicalHandler} that adds the resulting AXIOM OMElement to a specified
+ * parent element when endDocument is called. Used for returing SAXResults from Axiom
+ * elements.
+ *
+ * @author Arjen Poutsma
+ * @since 1.0.0
+ */
+class AxiomHandler implements ContentHandler, LexicalHandler {
+
+ private final OMFactory factory;
+
+ private final List elements = new ArrayList();
+
+ private Map namespaces = new HashMap();
+
+ private final OMContainer container;
+
+ private int charactersType = XMLStreamConstants.CHARACTERS;
+
+ AxiomHandler(OMContainer container, OMFactory factory) {
+ Assert.notNull(container, "'container' must not be null");
+ Assert.notNull(factory, "'factory' must not be null");
+ this.factory = factory;
+ this.container = container;
+ }
+
+ private OMContainer getParent() {
+ if (!elements.isEmpty()) {
+ return (OMContainer) elements.get(elements.size() - 1);
+ }
+ else {
+ return container;
+ }
+ }
+
+ public void startPrefixMapping(String prefix, String uri) throws SAXException {
+ namespaces.put(prefix, uri);
+ }
+
+ public void endPrefixMapping(String prefix) throws SAXException {
+ namespaces.remove(prefix);
+ }
+
+ public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
+ OMContainer parent = getParent();
+ OMElement element = factory.createOMElement(localName, null, parent);
+ for (Iterator iterator = namespaces.entrySet().iterator(); iterator.hasNext();) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ String prefix = (String) entry.getKey();
+ if (prefix.length() == 0) {
+ element.declareDefaultNamespace((String) entry.getValue());
+ }
+ else {
+ element.declareNamespace((String) entry.getValue(), prefix);
+ }
+ }
+ QName qname = QNameUtils.toQName(uri, qName);
+ element.setLocalName(qname.getLocalPart());
+ element.setNamespace(element.findNamespace(qname.getNamespaceURI(), qname.getPrefix()));
+ for (int i = 0; i < atts.getLength(); i++) {
+ QName attrName = QNameUtils.toQName(atts.getURI(i), atts.getQName(i));
+ String value = atts.getValue(i);
+ if (!atts.getQName(i).startsWith("xmlns")) {
+ OMNamespace namespace = factory.createOMNamespace(attrName.getNamespaceURI(), attrName.getPrefix());
+ OMAttribute attribute = factory.createOMAttribute(attrName.getLocalPart(), namespace, value);
+ element.addAttribute(attribute);
+ }
+ }
+
+ elements.add(element);
+ }
+
+ public void endElement(String uri, String localName, String qName) throws SAXException {
+ elements.remove(elements.size() - 1);
+ }
+
+ public void characters(char ch[], int start, int length) throws SAXException {
+ String data = new String(ch, start, length);
+ OMContainer parent = getParent();
+ factory.createOMText(parent, data, charactersType);
+ }
+
+ public void ignorableWhitespace(char ch[], int start, int length) throws SAXException {
+ charactersType = XMLStreamConstants.SPACE;
+ characters(ch, start, length);
+ charactersType = XMLStreamConstants.CHARACTERS;
+ }
+
+ public void processingInstruction(String target, String data) throws SAXException {
+ OMContainer parent = getParent();
+ factory.createOMProcessingInstruction(parent, target, data);
+ }
+
+ public void comment(char ch[], int start, int length) throws SAXException {
+ String content = new String(ch, start, length);
+ OMContainer parent = getParent();
+ factory.createOMComment(parent, content);
+ }
+
+ public void startCDATA() throws SAXException {
+ charactersType = XMLStreamConstants.CDATA;
+ }
+
+ public void endCDATA() throws SAXException {
+ charactersType = XMLStreamConstants.CHARACTERS;
+ }
+
+ public void startEntity(String name) throws SAXException {
+ charactersType = XMLStreamConstants.ENTITY_REFERENCE;
+ }
+
+ public void endEntity(String name) throws SAXException {
+ charactersType = XMLStreamConstants.CHARACTERS;
+ }
+
+ /*
+ * Unsupported
+ */
+
+ public void setDocumentLocator(Locator locator) {
+ }
+
+ public void startDocument() throws SAXException {
+ }
+
+ public void endDocument() throws SAXException {
+ }
+
+ public void skippedEntity(String name) throws SAXException {
+ }
+
+ public void startDTD(String name, String publicId, String systemId) throws SAXException {
+ }
+
+ public void endDTD() throws SAXException {
+ }
+}
diff --git a/core/src/main/java/org/springframework/ws/soap/axiom/AxiomResult.java b/core/src/main/java/org/springframework/ws/soap/axiom/AxiomResult.java
new file mode 100644
index 00000000..bed1e274
--- /dev/null
+++ b/core/src/main/java/org/springframework/ws/soap/axiom/AxiomResult.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2008 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.ws.soap.axiom;
+
+import javax.xml.transform.sax.SAXResult;
+
+import org.apache.axiom.om.OMContainer;
+import org.apache.axiom.om.OMFactory;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.ext.LexicalHandler;
+
+/**
+ * Specific TrAX {@link javax.xml.transform.Result} that adds the resulting AXIOM OMElement to a specified parent
+ * element when endDocument is called.
+ *
+ * @author Arjen Poutsma
+ * @see AxiomHandler
+ * @since 1.5.0
+ */
+class AxiomResult extends SAXResult {
+
+ AxiomResult(OMContainer container, OMFactory factory) {
+ AxiomHandler handler = new AxiomHandler(container, factory);
+ super.setHandler(handler);
+ super.setLexicalHandler(handler);
+ }
+
+ /**
+ * Throws a UnsupportedOperationException.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public void setHandler(ContentHandler handler) {
+ throw new UnsupportedOperationException("setHandler is not supported");
+ }
+
+ /**
+ * Throws a UnsupportedOperationException.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public void setLexicalHandler(LexicalHandler handler) {
+ throw new UnsupportedOperationException("setLexicalHandler is not supported");
+ }
+}
diff --git a/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapBody.java b/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapBody.java
index 6c013e6b..8d55ded0 100644
--- a/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapBody.java
+++ b/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapBody.java
@@ -20,7 +20,6 @@ import java.util.Iterator;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
-import javax.xml.transform.sax.SAXResult;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMException;
@@ -70,7 +69,7 @@ abstract class AxiomSoapBody extends AxiomSoapElement implements SoapBody {
public Result getPayloadResult() {
AxiomUtils.removeContents(getAxiomBody());
- return new SAXResult(new AxiomContentHandler(getAxiomBody(), getAxiomFactory()));
+ return new AxiomResult(getAxiomBody(), getAxiomFactory());
}
public boolean hasFault() {
diff --git a/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapFaultDetail.java b/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapFaultDetail.java
index ea276313..f7335311 100644
--- a/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapFaultDetail.java
+++ b/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapFaultDetail.java
@@ -19,7 +19,6 @@ package org.springframework.ws.soap.axiom;
import java.util.Iterator;
import javax.xml.namespace.QName;
import javax.xml.transform.Result;
-import javax.xml.transform.sax.SAXResult;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMException;
@@ -57,7 +56,7 @@ class AxiomSoapFaultDetail extends AxiomSoapElement implements SoapFaultDetail {
}
public Result getResult() {
- return new SAXResult(new AxiomContentHandler(getAxiomFaultDetail(), getAxiomFactory()));
+ return new AxiomResult(getAxiomFaultDetail(), getAxiomFactory());
}
protected SOAPFaultDetail getAxiomFaultDetail() {
diff --git a/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapFaultDetailElement.java b/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapFaultDetailElement.java
index e032dbb7..b494b4f6 100644
--- a/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapFaultDetailElement.java
+++ b/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapFaultDetailElement.java
@@ -17,7 +17,6 @@
package org.springframework.ws.soap.axiom;
import javax.xml.transform.Result;
-import javax.xml.transform.sax.SAXResult;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMException;
@@ -39,7 +38,7 @@ class AxiomSoapFaultDetailElement extends AxiomSoapElement implements SoapFaultD
public Result getResult() {
try {
- return new SAXResult(new AxiomContentHandler(getAxiomElement(), getAxiomFactory()));
+ return new AxiomResult(getAxiomElement(), getAxiomFactory());
}
catch (OMException ex) {
throw new AxiomSoapFaultException(ex);
diff --git a/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapHeader.java b/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapHeader.java
index 7804806b..ce5c2e83 100644
--- a/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapHeader.java
+++ b/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapHeader.java
@@ -19,7 +19,6 @@ package org.springframework.ws.soap.axiom;
import java.util.Iterator;
import javax.xml.namespace.QName;
import javax.xml.transform.Result;
-import javax.xml.transform.sax.SAXResult;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMException;
@@ -46,7 +45,7 @@ abstract class AxiomSoapHeader extends AxiomSoapElement implements SoapHeader {
}
public Result getResult() {
- return new SAXResult(new AxiomContentHandler(getAxiomHeader(), getAxiomFactory()));
+ return new AxiomResult(getAxiomHeader(), getAxiomFactory());
}
public SoapHeaderElement addHeaderElement(QName name) {
diff --git a/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapHeaderElement.java b/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapHeaderElement.java
index fcf72500..b6ae1aa5 100644
--- a/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapHeaderElement.java
+++ b/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapHeaderElement.java
@@ -17,7 +17,6 @@
package org.springframework.ws.soap.axiom;
import javax.xml.transform.Result;
-import javax.xml.transform.sax.SAXResult;
import org.apache.axiom.om.OMException;
import org.apache.axiom.soap.SOAPFactory;
@@ -50,7 +49,7 @@ class AxiomSoapHeaderElement extends AxiomSoapElement implements SoapHeaderEleme
public Result getResult() {
try {
- return new SAXResult(new AxiomContentHandler(getAxiomHeaderBlock(), getAxiomFactory()));
+ return new AxiomResult(getAxiomHeaderBlock(), getAxiomFactory());
}
catch (OMException ex) {
throw new AxiomSoapHeaderException(ex);
diff --git a/core/src/test/java/org/springframework/ws/server/endpoint/StaxStreamPayloadEndpointTest.java b/core/src/test/java/org/springframework/ws/server/endpoint/StaxStreamPayloadEndpointTest.java
index a40b254c..a86fb2ee 100644
--- a/core/src/test/java/org/springframework/ws/server/endpoint/StaxStreamPayloadEndpointTest.java
+++ b/core/src/test/java/org/springframework/ws/server/endpoint/StaxStreamPayloadEndpointTest.java
@@ -16,6 +16,7 @@
package org.springframework.ws.server.endpoint;
+import javax.xml.soap.MessageFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamReader;
@@ -30,6 +31,8 @@ import org.springframework.ws.context.DefaultMessageContext;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.soap.axiom.AxiomSoapMessage;
import org.springframework.ws.soap.axiom.AxiomSoapMessageFactory;
+import org.springframework.ws.soap.saaj.SaajSoapMessage;
+import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
import org.springframework.xml.transform.StringResult;
import org.springframework.xml.transform.StringSource;
@@ -82,6 +85,23 @@ public class StaxStreamPayloadEndpointTest extends AbstractMessageEndpointTestCa
};
}
+ public void testSaajResponse() throws Exception {
+ Transformer transformer = TransformerFactory.newInstance().newTransformer();
+ MessageFactory messageFactory = MessageFactory.newInstance();
+ SaajSoapMessage request = new SaajSoapMessage(messageFactory.createMessage());
+ transformer.transform(new StringSource(REQUEST), request.getPayloadResult());
+ SaajSoapMessageFactory soapMessageFactory = new SaajSoapMessageFactory();
+ soapMessageFactory.afterPropertiesSet();
+ MessageContext context = new DefaultMessageContext(request, soapMessageFactory);
+
+ MessageEndpoint endpoint = createResponseEndpoint();
+ endpoint.invoke(context);
+ assertTrue("context has not response", context.hasResponse());
+ StringResult stringResult = new StringResult();
+ transformer.transform(context.getResponse().getPayloadSource(), stringResult);
+ assertXMLEqual(RESPONSE, stringResult.toString());
+ }
+
public void testAxiomResponse() throws Exception {
Transformer transformer = TransformerFactory.newInstance().newTransformer();
SOAPFactory axiomFactory = OMAbstractFactory.getSOAP11Factory();
diff --git a/core/src/test/java/org/springframework/ws/soap/axiom/AxiomHandlerTest.java b/core/src/test/java/org/springframework/ws/soap/axiom/AxiomHandlerTest.java
new file mode 100644
index 00000000..bad5a63d
--- /dev/null
+++ b/core/src/test/java/org/springframework/ws/soap/axiom/AxiomHandlerTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2006 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.ws.soap.axiom;
+
+import java.io.ByteArrayOutputStream;
+import java.io.StringReader;
+
+import org.apache.axiom.om.OMAbstractFactory;
+import org.apache.axiom.om.OMDocument;
+import org.apache.axiom.om.OMElement;
+import org.apache.axiom.om.OMFactory;
+import org.apache.axiom.om.OMNamespace;
+import org.custommonkey.xmlunit.XMLTestCase;
+import org.xml.sax.InputSource;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+public class AxiomHandlerTest extends XMLTestCase {
+
+ private static final String XML_1 = "" + "" +
+ "" +
+ "content" +
+ "";
+
+ private static final String XML_2_EXPECTED = "" + "" +
+ "" + "";
+
+ private static final String XML_2_SNIPPET =
+ "" + "";
+
+ private AxiomHandler handler;
+
+ private OMDocument result;
+
+ private XMLReader xmlReader;
+
+ private OMFactory factory;
+
+ protected void setUp() throws Exception {
+ factory = OMAbstractFactory.getOMFactory();
+ result = factory.createOMDocument();
+ xmlReader = XMLReaderFactory.createXMLReader();
+ }
+
+ public void testContentHandlerDocumentNamespacePrefixes() throws Exception {
+ xmlReader.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
+ handler = new AxiomHandler(result, factory);
+ xmlReader.setContentHandler(handler);
+ xmlReader.setProperty("http://xml.org/sax/properties/lexical-handler", handler);
+ xmlReader.parse(new InputSource(new StringReader(XML_1)));
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ result.serialize(bos);
+ assertXMLEqual("Invalid result", XML_1, bos.toString("UTF-8"));
+ }
+
+ public void testContentHandlerDocumentNoNamespacePrefixes() throws Exception {
+ xmlReader.setFeature("http://xml.org/sax/features/namespace-prefixes", false);
+ handler = new AxiomHandler(result, factory);
+ xmlReader.setContentHandler(handler);
+ xmlReader.parse(new InputSource(new StringReader(XML_1)));
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ result.serialize(bos);
+ assertXMLEqual("Invalid result", XML_1, bos.toString("UTF-8"));
+ }
+
+ public void testContentHandlerElement() throws Exception {
+ OMNamespace namespace = factory.createOMNamespace("namespace", "");
+ OMElement rootElement = factory.createOMElement("root", namespace, result);
+ handler = new AxiomHandler(rootElement, factory);
+ xmlReader.setContentHandler(handler);
+ xmlReader.parse(new InputSource(new StringReader(XML_2_SNIPPET)));
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ result.serialize(bos);
+ assertXMLEqual("Invalid result", XML_2_EXPECTED, bos.toString("UTF-8"));
+ }
+}
\ No newline at end of file
diff --git a/xml/src/main/java/org/springframework/xml/stream/StaxEventXmlReader.java b/xml/src/main/java/org/springframework/xml/stream/StaxEventXmlReader.java
index 0cba124a..fa020b9b 100644
--- a/xml/src/main/java/org/springframework/xml/stream/StaxEventXmlReader.java
+++ b/xml/src/main/java/org/springframework/xml/stream/StaxEventXmlReader.java
@@ -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;
}
-
}
diff --git a/xml/src/main/java/org/springframework/xml/stream/StaxStreamXmlReader.java b/xml/src/main/java/org/springframework/xml/stream/StaxStreamXmlReader.java
index 9613a363..1174e1e1 100644
--- a/xml/src/main/java/org/springframework/xml/stream/StaxStreamXmlReader.java
+++ b/xml/src/main/java/org/springframework/xml/stream/StaxStreamXmlReader.java
@@ -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());
}
}
diff --git a/xml/src/test/java/org/springframework/xml/stream/AbstractStaxXmlReaderTestCase.java b/xml/src/test/java/org/springframework/xml/stream/AbstractStaxXmlReaderTestCase.java
index 22db5a23..fb9e8eb9 100644
--- a/xml/src/test/java/org/springframework/xml/stream/AbstractStaxXmlReaderTestCase.java
+++ b/xml/src/test/java/org/springframework/xml/stream/AbstractStaxXmlReaderTestCase.java
@@ -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 ArgumentMatcher 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) {
diff --git a/xml/src/test/resources/org/springframework/xml/stream/testLexicalHandler.xml b/xml/src/test/resources/org/springframework/xml/stream/testLexicalHandler.xml
new file mode 100644
index 00000000..9fc9243a
--- /dev/null
+++ b/xml/src/test/resources/org/springframework/xml/stream/testLexicalHandler.xml
@@ -0,0 +1,8 @@
+
+]>
+
+
+
+ &entity;
+
\ No newline at end of file