diff --git a/oxm/src/main/java/org/springframework/oxm/castor/CastorMarshaller.java b/oxm/src/main/java/org/springframework/oxm/castor/CastorMarshaller.java index e835d996..5f4bfbc5 100644 --- a/oxm/src/main/java/org/springframework/oxm/castor/CastorMarshaller.java +++ b/oxm/src/main/java/org/springframework/oxm/castor/CastorMarshaller.java @@ -42,6 +42,7 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.core.io.Resource; import org.springframework.oxm.AbstractMarshaller; import org.springframework.oxm.XmlMappingException; +import org.springframework.xml.dom.DomContentHandler; import org.springframework.xml.stream.StaxEventContentHandler; import org.springframework.xml.stream.StaxEventXmlReader; import org.springframework.xml.stream.StaxStreamContentHandler; @@ -202,8 +203,8 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing } protected void marshalDomNode(Object graph, Node node) throws XmlMappingException { - Marshaller marshaller = new Marshaller(node); - marshal(graph, marshaller); + ContentHandler contentHandler = new DomContentHandler(node); + marshalSaxHandlers(graph, contentHandler, null); } protected void marshalXmlEventWriter(Object graph, XMLEventWriter eventWriter) throws XmlMappingException { diff --git a/oxm/src/test/java/org/springframework/oxm/AbstractMarshallerTestCase.java b/oxm/src/test/java/org/springframework/oxm/AbstractMarshallerTestCase.java index e29550bf..e24bd2dc 100644 --- a/oxm/src/test/java/org/springframework/oxm/AbstractMarshallerTestCase.java +++ b/oxm/src/test/java/org/springframework/oxm/AbstractMarshallerTestCase.java @@ -22,16 +22,12 @@ import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.stream.XMLEventWriter; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamWriter; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMResult; -import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.custommonkey.xmlunit.XMLTestCase; import org.custommonkey.xmlunit.XMLUnit; import org.springframework.xml.transform.StaxResult; -import org.springframework.xml.transform.StringResult; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Text; @@ -72,12 +68,7 @@ public abstract class AbstractMarshallerTestCase extends XMLTestCase { flightElement.appendChild(numberElement); Text text = expected.createTextNode("42"); numberElement.appendChild(text); - Transformer transformer = TransformerFactory.newInstance().newTransformer(); - StringResult stringResult = new StringResult(); - transformer.transform(new DOMSource(result), stringResult); - StringResult stringExpected = new StringResult(); - transformer.transform(new DOMSource(expected), stringExpected); - assertXMLEqual("Marshaller writes invalid DOMResult", stringExpected.toString(), stringResult.toString()); + assertXMLEqual("Marshaller writes invalid DOMResult", expected, result); } public void testMarshalStreamResultWriter() throws Exception { @@ -91,8 +82,7 @@ public abstract class AbstractMarshallerTestCase extends XMLTestCase { ByteArrayOutputStream os = new ByteArrayOutputStream(); StreamResult result = new StreamResult(os); marshaller.marshal(flights, result); - assertXMLEqual("Marshaller writes invalid StreamResult", - EXPECTED_STRING, + assertXMLEqual("Marshaller writes invalid StreamResult", EXPECTED_STRING, new String(os.toByteArray(), "UTF-8")); } diff --git a/xml/src/main/java/org/springframework/xml/dom/DomContentHandler.java b/xml/src/main/java/org/springframework/xml/dom/DomContentHandler.java new file mode 100644 index 00000000..5e3ddfa8 --- /dev/null +++ b/xml/src/main/java/org/springframework/xml/dom/DomContentHandler.java @@ -0,0 +1,104 @@ +/* + * 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.xml.dom; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.util.Assert; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.Text; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * SAX ContentHandler that transforms callback calls to DOM Nodes. + * + * @author Arjen Poutsma + * @see org.w3c.dom.Node + */ +public class DomContentHandler extends DefaultHandler { + + private Document document; + + private List elements = new ArrayList(); + + private Node node; + + /** + * Creates a new instance of the DomContentHandler with the given node. + * + * @param node the node to publish events to + */ + public DomContentHandler(Node node) { + Assert.notNull(node, "node must not be null"); + this.node = node; + if (node instanceof Document) { + document = (Document) node; + } + } + + private Node getParent() { + if (!elements.isEmpty()) { + return (Node) elements.get(elements.size() - 1); + } + else { + return node; + } + } + + public void characters(char ch[], int start, int length) throws SAXException { + String data = new String(ch, start, length); + Node parent = getParent(); + Node lastChild = parent.getLastChild(); + if (lastChild != null && lastChild.getNodeType() == Node.TEXT_NODE) { + ((Text) lastChild).appendData(data); + } + else { + Text text = document.createTextNode(data); + parent.appendChild(text); + } + } + + public void endElement(String uri, String localName, String qName) throws SAXException { + elements.remove(elements.size() - 1); + } + + public void processingInstruction(String target, String data) throws SAXException { + Node parent = getParent(); + ProcessingInstruction pi = document.createProcessingInstruction(target, data); + parent.appendChild(pi); + } + + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + Node parent = getParent(); + Element element = document.createElementNS(uri, qName); + for (int i = 0; i < attributes.getLength(); i++) { + String attrUri = attributes.getURI(i); + String attrQname = attributes.getQName(i); + String value = attributes.getValue(i); + element.setAttributeNS(attrUri, attrQname, value); + } + parent.appendChild(element); + elements.add(element); + } + +} diff --git a/xml/src/test/java/org/springframework/xml/dom/DomContentHandlerTest.java b/xml/src/test/java/org/springframework/xml/dom/DomContentHandlerTest.java new file mode 100644 index 00000000..b3000084 --- /dev/null +++ b/xml/src/test/java/org/springframework/xml/dom/DomContentHandlerTest.java @@ -0,0 +1,60 @@ +/* + * 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.xml.dom; + +import java.io.StringReader; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.custommonkey.xmlunit.XMLTestCase; +import org.w3c.dom.Document; +import org.xml.sax.InputSource; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.XMLReaderFactory; + +public class DomContentHandlerTest extends XMLTestCase { + + private static final String XML_CONTENT_HANDLER = "" + "" + + "" + + "content" + + ""; + + private Document expected; + + private DomContentHandler handler; + + private Document result; + + private XMLReader xmlReader; + + protected void setUp() throws Exception { + xmlReader = XMLReaderFactory.createXMLReader(); + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + documentBuilderFactory.setNamespaceAware(true); + DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); + result = documentBuilder.newDocument(); + handler = new DomContentHandler(result); + expected = documentBuilder.parse(new InputSource(new StringReader(XML_CONTENT_HANDLER))); + } + + public void testContentHandler() throws Exception { + 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", expected, result); + } +} \ No newline at end of file