You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ju...@apache.org on 2009/02/22 00:41:39 UTC

svn commit: r746602 - in /jackrabbit/trunk/jackrabbit-jcr-commons/src: main/java/org/apache/jackrabbit/commons/xml/ test/java/org/apache/jackrabbit/commons/xml/

Author: jukka
Date: Sat Feb 21 23:41:38 2009
New Revision: 746602

URL: http://svn.apache.org/viewvc?rev=746602&view=rev
Log:
JCR-1952: DOMException: NAMESPACE_ERR thrown when exporting document view

Support for simple XML serialization that does not depend on JAXP libraries

Added:
    jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/xml/ProxyContentHandler.java
    jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/xml/ToXmlContentHandler.java
    jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/xml/XmlnsContentHandler.java
    jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/commons/xml/ToXmlContentHandlerTest.java
    jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/commons/xml/XmlnsContentHandlerTest.java

Added: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/xml/ProxyContentHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/xml/ProxyContentHandler.java?rev=746602&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/xml/ProxyContentHandler.java (added)
+++ jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/xml/ProxyContentHandler.java Sat Feb 21 23:41:38 2009
@@ -0,0 +1,187 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.jackrabbit.commons.xml;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * A proxy content handler that passes all SAX events as-is to the
+ * proxied handler.
+ * <p>
+ * As a convenience this class inherits the {@link DefaultHandler} class
+ * instead of just the {@link ContentHandler} interface. This makes it
+ * possible to use this class as an adapter when using methods like
+ * {@link javax.xml.parsers.SAXParser#parse(String, DefaultHandler)} that
+ * expect a DefaultHandler instance instead of a ContentHandler.
+ */
+public class ProxyContentHandler extends DefaultHandler {
+
+    /**
+     * The proxied content handler. This is a protected, non-final field
+     * so that subclasses can access the proxied handler or even replace
+     * it they want.
+     */
+    protected ContentHandler handler;
+
+    /**
+     * Creates a proxy for the given content handler.
+     *
+     * @param handler content handler to be proxied
+     */
+    public ProxyContentHandler(ContentHandler handler) {
+        this.handler = handler;
+    }
+
+    //------------------------------------------------------< ContentHandler >
+
+    /**
+     * Delegated to {@link #handler}.
+     *
+     * @param ch passed through
+     * @param start passed through
+     * @param length passed through
+     * @throws SAXException if an error occurs
+     */
+    public void characters(char[] ch, int start, int length)
+            throws SAXException {
+        handler.characters(ch, start, length);
+    }
+
+    /**
+     * Delegated to {@link #handler}.
+     *
+     * @throws SAXException if an error occurs
+     */
+    public void endDocument() throws SAXException {
+        handler.endDocument();
+    }
+
+    /**
+     * Delegated to {@link #handler}.
+     *
+     * @param namespaceURI passed through
+     * @param localName passed through
+     * @param qName passed through
+     * @throws SAXException if an error occurs
+     */
+    public void endElement(
+            String namespaceURI, String localName, String qName)
+            throws SAXException {
+        handler.endElement(namespaceURI, localName, qName);
+    }
+
+    /**
+     * Delegated to {@link #handler}.
+     *
+     * @param prefix passed through
+     * @throws SAXException if an error occurs
+     */
+    public void endPrefixMapping(String prefix) throws SAXException {
+        handler.endPrefixMapping(prefix);
+    }
+
+    /**
+     * Delegated to {@link #handler}.
+     *
+     * @param ch passed through
+     * @param start passed through
+     * @param length passed through
+     * @throws SAXException if an error occurs
+     */
+    public void ignorableWhitespace(char[] ch, int start, int length)
+            throws SAXException {
+        handler.ignorableWhitespace(ch, start, length);
+    }
+
+    /**
+     * Delegated to {@link #handler}.
+     *
+     * @param target passed through
+     * @param data passed through
+     * @throws SAXException if an error occurs
+     */
+    public void processingInstruction(String target, String data)
+            throws SAXException {
+        handler.processingInstruction(target, data);
+    }
+
+    /**
+     * Delegated to {@link #handler}.
+     *
+     * @param locator passed through
+     */
+    public void setDocumentLocator(Locator locator) {
+        handler.setDocumentLocator(locator);
+    }
+
+    /**
+     * Delegated to {@link #handler}.
+     *
+     * @param name passed through
+     * @throws SAXException if an error occurs
+     */
+    public void skippedEntity(String name) throws SAXException {
+        handler.skippedEntity(name);
+    }
+
+    /**
+     * Delegated to {@link #handler}.
+     *
+     * @throws SAXException if an error occurs
+     */
+    public void startDocument() throws SAXException {
+        handler.startDocument();
+    }
+
+    /**
+     * Delegated to {@link #handler}.
+     *
+     * @param namespaceURI passed through
+     * @param localName passed through
+     * @param qName passed through
+     * @param atts passed through
+     * @throws SAXException if an error occurs
+     */
+    public void startElement(
+            String namespaceURI, String localName, String qName,
+            Attributes atts) throws SAXException {
+        handler.startElement(namespaceURI, localName, qName, atts);
+    }
+
+    /**
+     * Delegated to {@link #handler}.
+     *
+     * @param prefix passed through
+     * @param uri passed through
+     * @throws SAXException if an error occurs
+     */
+    public void startPrefixMapping(String prefix, String uri)
+            throws SAXException {
+        handler.startPrefixMapping(prefix, uri);
+    }
+
+    //--------------------------------------------------------------< Object >
+
+    public String toString() {
+        return handler.toString();
+    }
+
+}

Added: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/xml/ToXmlContentHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/xml/ToXmlContentHandler.java?rev=746602&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/xml/ToXmlContentHandler.java (added)
+++ jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/xml/ToXmlContentHandler.java Sat Feb 21 23:41:38 2009
@@ -0,0 +1,283 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.jackrabbit.commons.xml;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * Simple XML serializer. This content handler serializes the received
+ * SAX events as XML to a given {@link Writer} or {@link OutputStream}.
+ * The serialization assumes that the incoming SAX events are well-formed,
+ * i.e. that all elements are properly nested, that element and attribute
+ * names are valid and that no invalid XML characters are included. Assuming
+ * these preconditions are met, the result will be a well-formed XML stream.
+ * <p>
+ * This serializer does not have any special support for namespaces. For
+ * example, namespace prefixes are declared in the resulting XML stream
+ * if and only if the corresponding "xmlns" attributes are explicitly
+ * included in the {@link Attributes} instances passed in
+ * {@link #startElement(String, String, String, Attributes)} calls.
+ * <p>
+ * As a convenience this class inherits the {@link DefaultHandler} class
+ * instead of just the {@link ContentHandler} interface. This makes it
+ * easier to pass instances of this class to methods like
+ * {@link javax.xml.parsers.SAXParser#parse(String, DefaultHandler)} that
+ * expect a DefaultHandler instance instead of a ContentHandler.
+ */
+public class ToXmlContentHandler extends DefaultHandler {
+
+    /**
+     * The XML stream.
+     */
+    private final Writer writer;
+
+    /**
+     * The data part of the &lt;?xml?&gt; processing instruction included
+     * at the beginning of the XML stream.
+     */
+    private final String declaration;
+
+    /**
+     * Flag variable that is used to track whether a start tag has had it's
+     * closing ">" appended. Set to <code>true</code> by the
+     * {@link #startElement(String, String, String, Attributes)} method that
+     * <em>does not</em> output the closing ">". If this flag is still set
+     * when the {#link {@link #endElement(String, String, String)}} method
+     * is called, then the method knows that the element is empty and can
+     * close it with "/>". Any other SAX event will cause the open start tag
+     * to be closed with a normal ">".
+     *
+     * @see #closeStartTagIfOpen()
+     */
+    private boolean startTagIsOpen = false;
+
+    //--------------------------------------------------------< constructors >
+
+    /**
+     * Creates an XML serializer that writes the serialized XML stream
+     * to the given output stream using the given character encoding.
+     *
+     * @param stream XML output stream
+     * @param encoding character encoding
+     * @throws UnsupportedEncodingException if the encoding is not supported
+     */
+    public ToXmlContentHandler(OutputStream stream, String encoding)
+            throws UnsupportedEncodingException {
+        this.writer = new OutputStreamWriter(stream, encoding);
+        this.declaration = "version=\"1.0\" encoding=\"" + encoding + "\"";
+    }
+
+    /**
+     * Creates an XML serializer that writes the serialized XML stream
+     * to the given output stream using the UTF-8 character encoding.
+     *
+     * @param stream XML output stream
+     */
+    public ToXmlContentHandler(OutputStream stream) {
+        try {
+            this.writer = new OutputStreamWriter(stream, "UTF-8");
+            this.declaration = "version=\"1.0\" encoding=\"UTF-8\"";
+        } catch (UnsupportedEncodingException e) {
+            // should never happen
+            throw new IllegalStateException("UTF-8 is not supported!");
+        }
+    }
+
+    /**
+     * Creates an XML serializer that writes the serialized XML stream
+     * to the given writer.
+     *
+     * @param writer XML output stream
+     */
+    public ToXmlContentHandler(Writer writer) {
+        this.writer = writer;
+        this.declaration = "version=\"1.0\"";
+    }
+
+    /**
+     * Creates an XML serializer that writes the serialized XML stream
+     * to an internal buffer. Use the {@link #toString()} method to access
+     * the serialized XML document.
+     */
+    public ToXmlContentHandler() {
+        this(new StringWriter());
+    }
+
+    //-------------------------------------------------------------< private >
+
+    private void write(char[] ch, int start, int length, boolean attribute)
+            throws SAXException {
+        for (int i = start; i < start + length; i++) {
+            try {
+                if (ch[i] == '>') {
+                    writer.write("&gt;");
+                } else if (ch[i] == '<') {
+                    writer.write("&lt;");
+                } else if (ch[i] == '&') {
+                    writer.write("&amp;");
+                } else if (attribute && ch[i] == '"') {
+                    writer.write("&quot;");
+                } else if (attribute && ch[i] == '\'') {
+                    writer.write("&apos;");
+                } else {
+                    writer.write(ch[i]);
+                }
+            } catch (IOException e) {
+                throw new SAXException(
+                        "Failed to output XML character: " + ch[i], e);
+            }
+        }
+    }
+
+    private void closeStartTagIfOpen() throws SAXException {
+        if (startTagIsOpen) {
+            try {
+                writer.write(">");
+            } catch (IOException e) {
+                throw new SAXException(
+                        "Failed to output XML bracket: >", e);
+            }
+            startTagIsOpen = false;
+        }
+    }
+
+    //------------------------------------------------------< ContentHandler >
+
+    /**
+     * Starts the XML serialization by outputting the &lt;?xml?&gt; header.
+     */
+    public void startDocument() throws SAXException {
+        processingInstruction("xml", declaration);
+    }
+
+    /**
+     * Ends the XML serialization by flushing the output stream.
+     */
+    public void endDocument() throws SAXException {
+        try {
+            writer.flush();
+        } catch (IOException e) {
+            throw new SAXException("Failed to flush XML output", e);
+        }
+    }
+
+    /**
+     * Serializes a processing instruction.
+     */
+    public void processingInstruction(String target, String data)
+            throws SAXException {
+        closeStartTagIfOpen();
+        try {
+            writer.write("<?");
+            writer.write(target);
+            if (data != null) {
+                writer.write(" ");
+                writer.write(data);
+            }
+            writer.write("?>");
+        } catch (IOException e) {
+            throw new SAXException(
+                    "Failed to output XML processing instruction: " + target, e);
+        }
+    }
+
+    /**
+     * Outputs the specified start tag with the given attributes.
+     */
+    public void startElement(
+            String namespaceURI, String localName, String qName,
+            Attributes atts) throws SAXException {
+        closeStartTagIfOpen();
+        try {
+            writer.write("<");
+            writer.write(qName);
+            for (int i = 0; i < atts.getLength(); i++) {
+                writer.write(" ");
+                writer.write(atts.getQName(i));
+                writer.write("=\"");
+                char[] ch = atts.getValue(i).toCharArray();
+                write(ch, 0, ch.length, true);
+                writer.write("\"");
+            }
+            startTagIsOpen = true;
+        } catch (IOException e) {
+            throw new SAXException(
+                    "Failed to output XML end tag: " + qName, e);
+        }
+    }
+
+    /**
+     * Escapes and outputs the given characters.
+     */
+    public void characters(char[] ch, int start, int length)
+            throws SAXException {
+        closeStartTagIfOpen();
+        write(ch, start, length, false);
+    }
+
+    /**
+     * Escapes and outputs the given characters.
+     */
+    public void ignorableWhitespace(char[] ch, int start, int length)
+            throws SAXException {
+        characters(ch, start, length);
+    }
+
+    /**
+     * Outputs the specified end tag.
+     */
+    public void endElement(
+            String namespaceURI, String localName, String qName)
+            throws SAXException {
+        try {
+            if (startTagIsOpen) {
+                writer.write("/>");
+                startTagIsOpen = false;
+            } else {
+                writer.write("</");
+                writer.write(qName);
+                writer.write(">");
+            }
+        } catch (IOException e) {
+            throw new SAXException(
+                    "Failed to output XML end tag: " + qName, e);
+        }
+    }
+
+    //--------------------------------------------------------------< Object >
+
+    /**
+     * Returns the serialized XML document (assuming the default no-argument
+     * constructor was used).
+     *
+     * @param serialized XML document
+     */
+    public String toString() {
+        return writer.toString();
+    }
+
+}

Added: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/xml/XmlnsContentHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/xml/XmlnsContentHandler.java?rev=746602&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/xml/XmlnsContentHandler.java (added)
+++ jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/xml/XmlnsContentHandler.java Sat Feb 21 23:41:38 2009
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.jackrabbit.commons.xml;
+
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+/**
+ * Content handler proxy that adds explicit "xmlns" attributes for all
+ * namespace mappings introduced through
+ * {@link #startPrefixMapping(String, String)} calls.
+ */
+public class XmlnsContentHandler extends ProxyContentHandler {
+
+    /**
+     * Namespace of the "xmlns" attributes.
+     */
+    private static final String XMLNS_NAMESPACE =
+        "http://www.w3.org/2000/xmlns/";
+
+    /**
+     * Namespace mappings recorded for the next element.
+     */
+    private final LinkedHashMap namespaces = new LinkedHashMap();
+
+    public XmlnsContentHandler(ContentHandler handler) {
+        super(handler);
+    }
+
+    //------------------------------------------------------< ContentHandler >
+
+    /**
+     * Records the namespace mapping and passes the call to the proxied
+     * content handler.
+     */
+    public void startPrefixMapping(String prefix, String uri)
+            throws SAXException {
+        namespaces.put(prefix, uri);
+        super.startPrefixMapping(prefix, uri);
+    }
+
+    /**
+     * Adds the recorded namespace mappings (if any) as "xmlns" attributes
+     * before passing the call on to the proxied content handler.
+     */
+    public void startElement(
+            String namespaceURI, String localName, String qName,
+            Attributes atts) throws SAXException {
+        if (!namespaces.isEmpty()) {
+            AttributesImpl attributes = new AttributesImpl(atts);
+            Iterator iterator = namespaces.entrySet().iterator();
+            while (iterator.hasNext()) {
+                Map.Entry entry = (Map.Entry) iterator.next();
+                String prefix = (String) entry.getKey();
+                String uri = (String) entry.getValue();
+                if (prefix.length() == 0) {
+                    attributes.addAttribute(
+                            XMLNS_NAMESPACE, "xmlns", "xmlns",
+                            "CDATA", uri);
+                } else {
+                    attributes.addAttribute(
+                            XMLNS_NAMESPACE, prefix, "xmlns:" + prefix,
+                            "CDATA", uri);
+                }
+            }
+            atts = attributes;
+            namespaces.clear();
+        }
+        super.startElement(namespaceURI, localName, qName, atts);
+    }
+
+}

Added: jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/commons/xml/ToXmlContentHandlerTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/commons/xml/ToXmlContentHandlerTest.java?rev=746602&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/commons/xml/ToXmlContentHandlerTest.java (added)
+++ jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/commons/xml/ToXmlContentHandlerTest.java Sat Feb 21 23:41:38 2009
@@ -0,0 +1,176 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.jackrabbit.commons.xml;
+
+import junit.framework.TestCase;
+
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+public class ToXmlContentHandlerTest extends TestCase {
+
+    public void testMinimalDocument() throws SAXException {
+        ContentHandler handler = new ToXmlContentHandler();
+        handler.startDocument();
+        handler.startElement("", "test", "test", new AttributesImpl());
+        handler.endElement("", "test", "test");
+        handler.endDocument();
+        assertEquals("<?xml version=\"1.0\"?><test/>", handler.toString());
+    }
+
+    public void testAttribute() throws SAXException {
+        ContentHandler handler = new ToXmlContentHandler();
+        handler.startDocument();
+        AttributesImpl attributes = new AttributesImpl();
+        attributes.addAttribute("", "foo", "foo", "CDATA", "bar");
+        handler.startElement("", "test", "test", attributes);
+        handler.endElement("", "test", "test");
+        handler.endDocument();
+        assertEquals(
+                "<?xml version=\"1.0\"?><test foo=\"bar\"/>",
+                handler.toString());
+    }
+
+    public void testAttributeOrder() throws SAXException {
+        ContentHandler handler;
+        AttributesImpl attributes;
+
+        handler = new ToXmlContentHandler();
+        handler.startDocument();
+        attributes = new AttributesImpl();
+        attributes.addAttribute("", "foo", "foo", "CDATA", "A");
+        attributes.addAttribute("", "bar", "bar", "CDATA", "B");
+        handler.startElement("", "test", "test", attributes);
+        handler.endElement("", "test", "test");
+        handler.endDocument();
+        assertEquals(
+                "<?xml version=\"1.0\"?><test foo=\"A\" bar=\"B\"/>",
+                handler.toString());
+
+        handler = new ToXmlContentHandler();
+        handler.startDocument();
+        attributes = new AttributesImpl();
+        attributes.addAttribute("", "bar", "bar", "CDATA", "B");
+        attributes.addAttribute("", "foo", "foo", "CDATA", "A");
+        handler.startElement("", "test", "test", attributes);
+        handler.endElement("", "test", "test");
+        handler.endDocument();
+        assertEquals(
+                "<?xml version=\"1.0\"?><test bar=\"B\" foo=\"A\"/>",
+                handler.toString());
+    }
+
+    public void testChildElements() throws SAXException {
+        ContentHandler handler = new ToXmlContentHandler();
+        handler.startDocument();
+        handler.startElement("", "test", "test", new AttributesImpl());
+        handler.startElement("", "foo", "foo", new AttributesImpl());
+        handler.endElement("", "foo", "foo");
+        handler.startElement("", "bar", "bar", new AttributesImpl());
+        handler.endElement("", "bar", "bar");
+        handler.endElement("", "test", "test");
+        handler.endDocument();
+        assertEquals(
+                "<?xml version=\"1.0\"?><test><foo/><bar/></test>",
+                handler.toString());
+    }
+
+    public void testCharacters() throws SAXException {
+        ContentHandler handler = new ToXmlContentHandler();
+        handler.startDocument();
+        handler.startElement("", "test", "test", new AttributesImpl());
+        handler.characters("foo".toCharArray(), 0, 3);
+        handler.endElement("", "test", "test");
+        handler.endDocument();
+        assertEquals(
+                "<?xml version=\"1.0\"?><test>foo</test>",
+                handler.toString());
+    }
+
+    public void testIgnorableWhitespace() throws SAXException {
+        ContentHandler handler = new ToXmlContentHandler();
+        handler.startDocument();
+        handler.ignorableWhitespace("\n".toCharArray(), 0, 1);
+        handler.startElement("", "test", "test", new AttributesImpl());
+        handler.ignorableWhitespace("\n".toCharArray(), 0, 1);
+        handler.endElement("", "test", "test");
+        handler.ignorableWhitespace("\n".toCharArray(), 0, 1);
+        handler.endDocument();
+        assertEquals(
+                "<?xml version=\"1.0\"?>\n<test>\n</test>\n",
+                handler.toString());
+    }
+
+    public void testProcessingInstruction() throws SAXException {
+        ContentHandler handler = new ToXmlContentHandler();
+        handler.startDocument();
+        handler.processingInstruction("foo", "abc=\"xyz\"");
+        handler.startElement("", "test", "test", new AttributesImpl());
+        handler.processingInstruction("bar", null);
+        handler.endElement("", "test", "test");
+        handler.endDocument();
+        assertEquals(
+                "<?xml version=\"1.0\"?>"
+                + "<?foo abc=\"xyz\"?><test><?bar?></test>",
+                handler.toString());
+    }
+
+    public void testComplexDocument() throws SAXException {
+        ContentHandler handler = new ToXmlContentHandler();
+        handler.startDocument();
+        handler.ignorableWhitespace("\n".toCharArray(), 0, 1);
+        handler.processingInstruction("foo", "abc=\"xyz\"");
+        handler.ignorableWhitespace("\n".toCharArray(), 0, 1);
+        AttributesImpl attributes = new AttributesImpl();
+        attributes.addAttribute("", "version", "version", "CDATA", "1.0");
+        attributes.addAttribute(
+                "http://www.w3.org/2000/xmlns/", "xmlns", "xmlns",
+                "CDATA", "http://x.y.z/");
+        attributes.addAttribute(
+                "http://www.w3.org/2000/xmlns/", "xmlns", "xmlns:abc",
+                "CDATA", "http://a.b.c/");
+        handler.startElement("", "test", "test", attributes);
+        handler.ignorableWhitespace("\n  ".toCharArray(), 0, 3);
+        handler.characters("abc\n".toCharArray(), 0, 4);
+        handler.characters("  ".toCharArray(), 0, 2);
+        attributes = new AttributesImpl();
+        attributes.addAttribute("", "escape", "escape", "CDATA", "\"'<>&");
+        handler.startElement("http://a.b.c/", "foo", "abc:foo", attributes);
+        handler.characters("def".toCharArray(), 0, 3);
+        handler.endElement("http://a.b.c/", "foo", "abc:foo");
+        handler.ignorableWhitespace("\n  ".toCharArray(), 0, 3);
+        char[] ch = "<bar a=\"&amp;\" b=''/>".toCharArray();
+        handler.characters(ch, 0, ch.length);
+        handler.characters("\n".toCharArray(), 0, 1);
+        handler.endElement("", "test", "test");
+        handler.characters("\n".toCharArray(), 0, 1);
+        handler.endDocument();
+        assertEquals(
+                "<?xml version=\"1.0\"?>\n"
+                + "<?foo abc=\"xyz\"?>\n"
+                + "<test version=\"1.0\""
+                + " xmlns=\"http://x.y.z/\" xmlns:abc=\"http://a.b.c/\">\n"
+                + "  abc\n"
+                + "  <abc:foo escape=\"&quot;&apos;&lt;&gt;&amp;\">"
+                + "def</abc:foo>\n"
+                + "  &lt;bar a=\"&amp;amp;\" b=''/&gt;\n"
+                + "</test>\n",
+                handler.toString());
+    }
+
+}

Added: jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/commons/xml/XmlnsContentHandlerTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/commons/xml/XmlnsContentHandlerTest.java?rev=746602&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/commons/xml/XmlnsContentHandlerTest.java (added)
+++ jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/commons/xml/XmlnsContentHandlerTest.java Sat Feb 21 23:41:38 2009
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.jackrabbit.commons.xml;
+
+import junit.framework.TestCase;
+
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+public class XmlnsContentHandlerTest extends TestCase {
+
+    public void testXmlns() throws SAXException {
+        ContentHandler handler =
+            new XmlnsContentHandler(new ToXmlContentHandler());
+        handler.startDocument();
+        handler.startPrefixMapping("foo", "http://x.y.z/");
+        handler.startPrefixMapping("bar", "http://a.b.c/");
+        handler.startElement("", "test", "test", new AttributesImpl());
+        handler.startPrefixMapping("foo", "http://a.b.c/");
+        handler.startElement("", "tset", "tset", new AttributesImpl());
+        handler.endElement("", "tset", "tset");
+        handler.endPrefixMapping("foo");
+        handler.startElement("", "tset", "tset", new AttributesImpl());
+        handler.endElement("", "tset", "tset");
+        handler.endElement("", "test", "test");
+        handler.endPrefixMapping("bar");
+        handler.endPrefixMapping("foo");
+        handler.endDocument();
+        assertEquals(
+                "<?xml version=\"1.0\"?>"
+                + "<test xmlns:foo=\"http://x.y.z/\" xmlns:bar=\"http://a.b.c/\">"
+                + "<tset xmlns:foo=\"http://a.b.c/\"/><tset/>"
+                + "</test>",
+                handler.toString());
+    }
+
+}