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/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