From c122a7379b57d45d2c994728171d20609842f7c5 Mon Sep 17 00:00:00 2001 From: rfeng Date: Wed, 12 Aug 2009 23:43:27 +0000 Subject: Fix issues around XMLStreamWriter based on the isRepairingNamespaces property of XMLOutputFactory More refactoring to use common-xml and common-java git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@803742 13f79535-47bb-0310-9956-ffa450edef68 --- .../tuscany/sca/common/xml/stax/StAXHelper.java | 103 +++++++--- .../common/xml/stax/impl/XMLStreamSerializer.java | 222 ++++++++++++++------- .../sca/common/xml/stax/StAXHelperTestCase.java | 18 +- .../stax/reader/XmlTreeStreamReaderTestCase.java | 7 +- 4 files changed, 238 insertions(+), 112 deletions(-) (limited to 'java/sca/modules/common-xml/src') diff --git a/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/StAXHelper.java b/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/StAXHelper.java index 8ec45e9f9f..09d9d3062d 100644 --- a/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/StAXHelper.java +++ b/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/StAXHelper.java @@ -70,16 +70,16 @@ public class StAXHelper { factories.getFactory(XMLInputFactory.class); inputFactory = factories.getFactory(XMLInputFactory.class); outputFactory = factories.getFactory(XMLOutputFactory.class); + outputFactory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, Boolean.TRUE); UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); domHelper = utilities.getUtility(DOMHelper.class); } - + public static StAXHelper getInstance(ExtensionPointRegistry registry) { UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); return utilities.getUtility(StAXHelper.class); } - /** * @param inputFactory * @param outputFactory @@ -89,6 +89,9 @@ public class StAXHelper { super(); this.inputFactory = inputFactory; this.outputFactory = outputFactory; + if (outputFactory != null) { + this.outputFactory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, Boolean.TRUE); + } this.domHelper = domHelper; } @@ -117,7 +120,7 @@ public class StAXHelper { StringReader reader = new StringReader(string); return createXMLStreamReader(reader); } - + private static InputStream openStream(URL url) throws IOException { URLConnection connection = url.openConnection(); if (connection instanceof JarURLConnection) { @@ -127,7 +130,7 @@ public class StAXHelper { InputStream is = connection.getInputStream(); return is; } - + public XMLStreamReader createXMLStreamReader(URL url) throws XMLStreamException { try { return createXMLStreamReader(openStream(url)); @@ -143,10 +146,8 @@ public class StAXHelper { } public void save(XMLStreamReader reader, OutputStream outputStream) throws XMLStreamException { - XMLStreamSerializer serializer = new XMLStreamSerializer(); XMLStreamWriter streamWriter = createXMLStreamWriter(outputStream); - serializer.serialize(reader, streamWriter); - streamWriter.flush(); + save(reader, streamWriter); } public XMLStreamWriter createXMLStreamWriter(OutputStream outputStream) throws XMLStreamException { @@ -154,10 +155,8 @@ public class StAXHelper { } public void save(XMLStreamReader reader, Writer writer) throws XMLStreamException { - XMLStreamSerializer serializer = new XMLStreamSerializer(); XMLStreamWriter streamWriter = createXMLStreamWriter(writer); - serializer.serialize(reader, streamWriter); - streamWriter.flush(); + save(reader, streamWriter); } public XMLStreamWriter createXMLStreamWriter(Writer writer) throws XMLStreamException { @@ -192,7 +191,7 @@ public class StAXHelper { } public void save(XMLStreamReader reader, XMLStreamWriter writer) throws XMLStreamException { - XMLStreamSerializer serializer = new XMLStreamSerializer(); + XMLStreamSerializer serializer = new XMLStreamSerializer(isReparingNamespaces()); serializer.serialize(reader, writer); writer.flush(); } @@ -202,7 +201,6 @@ public class StAXHelper { new StAX2SAXAdapter(false).parse(reader, contentHandler); } - /** * @param url * @param element @@ -212,8 +210,7 @@ public class StAXHelper { * @throws IOException * @throws XMLStreamException */ - public String readAttribute(URL url, QName element, String attribute) throws IOException, - XMLStreamException { + public String readAttribute(URL url, QName element, String attribute) throws IOException, XMLStreamException { if (attribute == null) { attribute = "targetNamespace"; } @@ -225,8 +222,7 @@ public class StAXHelper { } } - public List readAttributes(URL url, QName element, String attribute) throws IOException, - XMLStreamException { + public List readAttributes(URL url, QName element, String attribute) throws IOException, XMLStreamException { if (attribute == null) { attribute = "targetNamespace"; } @@ -238,7 +234,7 @@ public class StAXHelper { reader.close(); } } - + /** * Returns the boolean value of an attribute. * @param reader @@ -356,7 +352,6 @@ public class StAXHelper { } } - private Attribute[] readAttributes(XMLStreamReader reader, AttributeFilter filter) throws XMLStreamException { XMLStreamReader newReader = inputFactory.createFilteredReader(reader, filter); while (filter.proceed() && newReader.hasNext()) { @@ -377,7 +372,7 @@ public class StAXHelper { public Attribute[] readAttributes(XMLStreamReader reader, Attribute... attributes) throws XMLStreamException { return readAttributes(reader, new AttributeFilter(false, attributes)); } - + private String readAttributeFromRoot(XMLStreamReader reader, Attribute filter) throws XMLStreamException { Attribute[] attrs = readAttributes(reader, new AttributeFilter(true, filter)); List values = attrs[0].getValues(); @@ -387,13 +382,13 @@ public class StAXHelper { return values.get(0); } } - + public String readAttributeFromRoot(XMLStreamReader reader, QName element, String attributeName) throws XMLStreamException { Attribute filter = new Attribute(element, attributeName); return readAttributeFromRoot(reader, filter); } - + public static class Attribute { private QName element; private String name; @@ -412,32 +407,32 @@ public class StAXHelper { public List getValues() { return values; } - + } - + private static class AttributeFilter implements StreamFilter { private boolean proceed = true; private Attribute[] attributes; private boolean rootOnly; - + /** * @param rootOnly */ - public AttributeFilter(boolean rootOnly, Attribute...attributes) { + public AttributeFilter(boolean rootOnly, Attribute... attributes) { super(); this.rootOnly = rootOnly; this.attributes = attributes; } public boolean accept(XMLStreamReader reader) { - if(attributes==null || attributes.length==0) { + if (attributes == null || attributes.length == 0) { proceed = false; return true; } - if(reader.getEventType() == XMLStreamConstants.START_ELEMENT) { + if (reader.getEventType() == XMLStreamConstants.START_ELEMENT) { QName name = reader.getName(); - for(Attribute attr: attributes) { - if(attr.element.equals(name)) { + for (Attribute attr : attributes) { + if (attr.element.equals(name)) { attr.values.add(reader.getAttributeValue(null, attr.name)); } } @@ -447,11 +442,57 @@ public class StAXHelper { } return true; } - + public boolean proceed() { return proceed; } - + + } + + public XMLInputFactory getInputFactory() { + return inputFactory; + } + + private boolean isReparingNamespaces() { + if (outputFactory == null) { + return Boolean.TRUE; + } + return outputFactory.getProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES) == Boolean.TRUE; + } + + public XMLOutputFactory getOutputFactory() { + return outputFactory; + } + + public String writeAttribute(XMLStreamWriter writer, QName name, String value) throws XMLStreamException { + return writeAttribute(writer, name.getPrefix(), name.getLocalPart(), name.getNamespaceURI(), value); + } + + public String writeAttribute(XMLStreamWriter writer, + String prefix, + String localName, + String namespaceURI, + String value) throws XMLStreamException { + if (value == null) { + return null; + } + XMLStreamSerializer serializer = new XMLStreamSerializer(isReparingNamespaces()); + return serializer.writeAttribute(writer, prefix, localName, namespaceURI, value); + } + + public void writeStartElement(XMLStreamWriter writer, QName name) throws XMLStreamException { + writeStartElement(writer, name.getPrefix(), name.getLocalPart(), name.getNamespaceURI()); + } + + public void writeStartElement(XMLStreamWriter writer, String prefix, String localName, String namespaceURI) + throws XMLStreamException { + XMLStreamSerializer serializer = new XMLStreamSerializer(isReparingNamespaces()); + serializer.writeStartElement(writer, prefix, localName, namespaceURI); + } + + public String writeNamespace(XMLStreamWriter writer, String prefix, String namespaceURI) throws XMLStreamException { + XMLStreamSerializer serializer = new XMLStreamSerializer(isReparingNamespaces()); + return serializer.writeNamespace(writer, prefix, namespaceURI); } } diff --git a/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/impl/XMLStreamSerializer.java b/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/impl/XMLStreamSerializer.java index 64ac0a40e5..5ef5a03d9f 100644 --- a/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/impl/XMLStreamSerializer.java +++ b/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/impl/XMLStreamSerializer.java @@ -19,7 +19,11 @@ package org.apache.tuscany.sca.common.xml.stax.impl; +import static javax.xml.XMLConstants.DEFAULT_NS_PREFIX; +import static javax.xml.XMLConstants.NULL_NS_URI; + import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; import javax.xml.stream.XMLStreamConstants; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; @@ -45,6 +49,23 @@ public class XMLStreamSerializer implements XMLStreamConstants { */ private int depth; + /** + * A flag to tell if the writer has javax.xml.stream.isRepairingNamespaces set to true + */ + private boolean isRepairingNamespaces = true; + + /** + * @param isRepairingNamespaces + */ + public XMLStreamSerializer(boolean isRepairingNamespaces) { + super(); + this.isRepairingNamespaces = isRepairingNamespaces; + } + + public XMLStreamSerializer() { + this(true); + } + /** * Generates a unique namespace prefix that is not in the scope of the NamespaceContext * @@ -81,62 +102,89 @@ public class XMLStreamSerializer implements XMLStreamConstants { int count = reader.getAttributeCount(); String prefix; String namespaceName; - String writerPrefix; + String localName; + String value; for (int i = 0; i < count; i++) { prefix = reader.getAttributePrefix(i); namespaceName = reader.getAttributeNamespace(i); - /* - * Due to parser implementations returning null as the namespace URI (for the empty namespace) we need to - * make sure that we deal with a namespace name that is not null. The best way to work around this issue is - * to set the namespace URI to "" if it is null - */ - if (namespaceName == null) { - namespaceName = ""; - } + localName = reader.getAttributeLocalName(i); + value = reader.getAttributeValue(i); - writerPrefix = writer.getPrefix(namespaceName); - - if (!"".equals(namespaceName)) { - // prefix has already being declared but this particular - // attrib has a - // no prefix attached. So use the prefix provided by the - // writer - if (writerPrefix != null && (prefix == null || prefix.equals(""))) { - writer.writeAttribute(writerPrefix, namespaceName, reader.getAttributeLocalName(i), reader - .getAttributeValue(i)); - - // writer prefix is available but different from the - // current - // prefix of the attrib. We should be declaring the new - // prefix - // as a namespace declaration - } else if (prefix != null && !"".equals(prefix) && !prefix.equals(writerPrefix)) { - writer.writeNamespace(prefix, namespaceName); - writer.writeAttribute(prefix, namespaceName, reader.getAttributeLocalName(i), reader - .getAttributeValue(i)); - - // prefix is null (or empty), but the namespace name is - // valid! it has not - // being written previously also. So we need to generate - // a prefix - // here - } else if (prefix == null || prefix.equals("")) { - prefix = generateUniquePrefix(writer.getNamespaceContext()); - writer.writeNamespace(prefix, namespaceName); - writer.writeAttribute(prefix, namespaceName, reader.getAttributeLocalName(i), reader - .getAttributeValue(i)); - } else { - writer.writeAttribute(prefix, namespaceName, reader.getAttributeLocalName(i), reader - .getAttributeValue(i)); - } + writeAttribute(writer, prefix, localName, namespaceName, value); + + } + } + + public void writeAttribute(XMLStreamWriter writer, QName name, String value) throws XMLStreamException { + writeAttribute(writer, name.getPrefix(), name.getLocalPart(), name.getNamespaceURI(), value); + } + + public String writeAttribute(XMLStreamWriter writer, + String prefix, + String localName, + String namespaceURI, + String value) throws XMLStreamException { + String writerPrefix; + /* + * Due to parser implementations returning null as the namespace URI (for the empty namespace) we need to + * make sure that we deal with a namespace name that is not null. The best way to work around this issue is + * to set the namespace URI to "" if it is null + */ + if (namespaceURI == null) { + namespaceURI = NULL_NS_URI; + } + + if (prefix == null) { + prefix = DEFAULT_NS_PREFIX; + } + + if (isRepairingNamespaces) { + writer.writeAttribute(prefix, namespaceURI, localName, value); + return writer.getPrefix(namespaceURI); + } + + writerPrefix = writer.getPrefix(namespaceURI); + + if (!NULL_NS_URI.equals(namespaceURI)) { + if (writerPrefix != null && isDefaultNSPrefix(prefix)) { + // prefix has already being declared but this particular attrib has a + // no prefix attached. So use the prefix provided by the writer + + writer.writeAttribute(writerPrefix, namespaceURI, localName, value); + return writerPrefix; + + } else if (!isDefaultNSPrefix(prefix) && !prefix.equals(writerPrefix)) { + // writer prefix is available but different from the current + // prefix of the attrib. We should be declaring the new prefix + // as a namespace declaration + + writer.writeNamespace(prefix, namespaceURI); + writer.writeAttribute(prefix, namespaceURI, localName, value); + return prefix; + + } else if (isDefaultNSPrefix(prefix)) { + // prefix is null (or empty), but the namespace name is valid! it has not + // being written previously also. So we need to generate a prefix here + + prefix = generateUniquePrefix(writer.getNamespaceContext()); + writer.writeNamespace(prefix, namespaceURI); + writer.writeAttribute(prefix, namespaceURI, localName, value); + return prefix; } else { - // empty namespace is equal to no namespace! - writer.writeAttribute(reader.getAttributeLocalName(i), reader.getAttributeValue(i)); + writer.writeAttribute(prefix, namespaceURI, localName, value); + return prefix; } - + } else { + // empty namespace is equal to no namespace! + writer.writeAttribute(localName, value); + return prefix; } } + private boolean isDefaultNSPrefix(String prefix) { + return (prefix == null || prefix.equals(DEFAULT_NS_PREFIX)); + } + /** * Method serializeCData. * @@ -165,38 +213,13 @@ public class XMLStreamSerializer implements XMLStreamConstants { * @throws XMLStreamException */ protected void serializeElement(XMLStreamReader reader, XMLStreamWriter writer) throws XMLStreamException { - String prefix = reader.getPrefix(); - String nameSpaceName = reader.getNamespaceURI(); - if (nameSpaceName != null) { - String writerPrefix = writer.getPrefix(nameSpaceName); - if (writerPrefix != null) { - writer.writeStartElement(nameSpaceName, reader.getLocalName()); - } else { - if (prefix != null) { - writer.writeStartElement(prefix, reader.getLocalName(), nameSpaceName); - writer.writeNamespace(prefix, nameSpaceName); - // writer.setPrefix(prefix, nameSpaceName); - } else { - // [rfeng] We need to set default NS 1st before calling writeStateElement - writer.setDefaultNamespace(nameSpaceName); - writer.writeStartElement(nameSpaceName, reader.getLocalName()); - writer.writeDefaultNamespace(nameSpaceName); - } - } - } else { - writer.writeStartElement(reader.getLocalName()); - } + writeStartElement(writer, reader.getName()); // add the namespaces int count = reader.getNamespaceCount(); String namespacePrefix; for (int i = 0; i < count; i++) { namespacePrefix = reader.getNamespacePrefix(i); - // [rfeng] The following is commented out to allow to default ns - // if (namespacePrefix != null && namespacePrefix.length() == 0) { - // continue; - // } - serializeNamespace(namespacePrefix, reader.getNamespaceURI(i), writer); } @@ -205,6 +228,45 @@ public class XMLStreamSerializer implements XMLStreamConstants { } + public void writeStartElement(XMLStreamWriter writer, QName name) throws XMLStreamException { + writeStartElement(writer, name.getPrefix(), name.getLocalPart(), name.getNamespaceURI()); + } + + public void writeStartElement(XMLStreamWriter writer, String prefix, String localName, String namespaceURI) + throws XMLStreamException { + + if (namespaceURI == null) { + namespaceURI = NULL_NS_URI; + } + if (prefix == null) { + prefix = DEFAULT_NS_PREFIX; + } + + if (isRepairingNamespaces) { + writer.writeStartElement(prefix, localName, namespaceURI); + return; + } + + String writerPrefix = writer.getPrefix(namespaceURI); + if (writerPrefix != null) { + // Namespace is bound + writer.writeStartElement(writerPrefix, localName, namespaceURI); + } else { + // Namespace is not bound + if (NULL_NS_URI.equals(namespaceURI)) { + writer.writeStartElement(localName); + String defaultNS = writer.getNamespaceContext().getNamespaceURI(DEFAULT_NS_PREFIX); + if (defaultNS != null && !NULL_NS_URI.equals(defaultNS)) { + writer.writeNamespace(prefix, namespaceURI); + } + } else { + writer.writeStartElement(prefix, localName, namespaceURI); + // writeNamespace() will call setPrefix() + writer.writeNamespace(prefix, namespaceURI); + } + } + } + /** * Method serializeEndElement. * @@ -224,10 +286,22 @@ public class XMLStreamSerializer implements XMLStreamConstants { * @throws XMLStreamException */ private void serializeNamespace(String prefix, String uri, XMLStreamWriter writer) throws XMLStreamException { + writeNamespace(writer, prefix, uri); + } + + public String writeNamespace(XMLStreamWriter writer, String prefix, String uri) throws XMLStreamException { + if (uri == null) { + uri = NULL_NS_URI; + } String prefix1 = writer.getPrefix(uri); if (prefix1 == null) { + if (prefix == null) { + prefix = DEFAULT_NS_PREFIX; + } writer.writeNamespace(prefix, uri); - // writer.setPrefix(prefix, uri); + return prefix; + } else { + return prefix1; } } diff --git a/java/sca/modules/common-xml/src/test/java/org/apache/tuscany/sca/common/xml/stax/StAXHelperTestCase.java b/java/sca/modules/common-xml/src/test/java/org/apache/tuscany/sca/common/xml/stax/StAXHelperTestCase.java index e853513e5a..77f060b081 100644 --- a/java/sca/modules/common-xml/src/test/java/org/apache/tuscany/sca/common/xml/stax/StAXHelperTestCase.java +++ b/java/sca/modules/common-xml/src/test/java/org/apache/tuscany/sca/common/xml/stax/StAXHelperTestCase.java @@ -25,6 +25,7 @@ import java.net.URL; import java.util.List; import javax.xml.namespace.QName; +import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamReader; import org.apache.tuscany.sca.common.xml.stax.StAXHelper.Attribute; @@ -41,8 +42,8 @@ import org.w3c.dom.Node; */ public class StAXHelperTestCase { private static final String XML = - "" + "" - + ""; + "" + "" + + ""; public static final QName WSDL11 = new QName("http://schemas.xmlsoap.org/wsdl/", "definitions"); public static final QName WSDL20 = new QName("http://www.w3.org/ns/wsdl", "description"); public static final QName XSD = new QName("http://www.w3.org/2001/XMLSchema", "schema"); @@ -62,7 +63,18 @@ public class StAXHelperTestCase { xml = helper.saveAsString(reader); XMLAssert.assertXMLEqual(XML, xml); } - + + @Test + public void testNoRepairingNamespaces() throws Exception { + StAXHelper helper = new StAXHelper(new DefaultExtensionPointRegistry()); + helper.getOutputFactory().setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, Boolean.FALSE); + XMLStreamReader reader = helper.createXMLStreamReader(XML); + String xml = helper.saveAsString(reader); + XMLAssert.assertXMLEqual(XML, xml); + reader = helper.createXMLStreamReader(xml); + assertNotNull(reader); + } + @Test public void testIndex() throws Exception { StAXHelper helper = new StAXHelper(new DefaultExtensionPointRegistry()); diff --git a/java/sca/modules/common-xml/src/test/java/org/apache/tuscany/sca/common/xml/stax/reader/XmlTreeStreamReaderTestCase.java b/java/sca/modules/common-xml/src/test/java/org/apache/tuscany/sca/common/xml/stax/reader/XmlTreeStreamReaderTestCase.java index 2c2f1f0583..264c1a0d61 100644 --- a/java/sca/modules/common-xml/src/test/java/org/apache/tuscany/sca/common/xml/stax/reader/XmlTreeStreamReaderTestCase.java +++ b/java/sca/modules/common-xml/src/test/java/org/apache/tuscany/sca/common/xml/stax/reader/XmlTreeStreamReaderTestCase.java @@ -35,9 +35,6 @@ import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamWriter; import org.apache.tuscany.sca.common.xml.stax.impl.XMLStreamSerializer; -import org.apache.tuscany.sca.common.xml.stax.reader.XmlNode; -import org.apache.tuscany.sca.common.xml.stax.reader.XmlNodeIterator; -import org.apache.tuscany.sca.common.xml.stax.reader.XmlTreeStreamReaderImpl; import org.custommonkey.xmlunit.XMLAssert; import org.junit.Assert; import org.junit.Before; @@ -144,7 +141,9 @@ public class XmlTreeStreamReaderTestCase { XmlTreeStreamReaderImpl reader = new XmlTreeStreamReaderImpl(root); XMLStreamSerializer serializer = new XMLStreamSerializer(); StringWriter sw = new StringWriter(); - XMLStreamWriter writer = XMLOutputFactory.newInstance().createXMLStreamWriter(sw); + XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); + outputFactory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, Boolean.TRUE); + XMLStreamWriter writer = outputFactory.createXMLStreamWriter(sw); serializer.serialize(reader, writer); String xml = sw.toString(); XMLAssert.assertXMLEqual(XML_RESULT, xml); -- cgit v1.2.3