Improve error message in UnionXmlCodec
[yangtools.git] / yang / yang-data-codec-xml / src / main / java / org / opendaylight / yangtools / yang / data / codec / xml / StreamWriterFacade.java
index 91e177e7da425bdbf741a9fa2dd40b1d30dda243..19c05c251c1395f9a4c1a72ed71a08e4953e06a4 100644 (file)
@@ -7,7 +7,6 @@
  */
 package org.opendaylight.yangtools.yang.data.codec.xml;
 
-import static com.google.common.base.Verify.verify;
 import static java.util.Objects.requireNonNull;
 
 import com.google.common.base.Strings;
@@ -32,19 +31,6 @@ import org.slf4j.LoggerFactory;
  * class referencing this class should be {@link XMLStreamNormalizedNodeStreamWriter}.
  */
 final class StreamWriterFacade extends ValueWriter {
-    /**
-     * Simple namespace/localname holder, an alternative to QName.
-     */
-    private static final class NSName {
-        private final String uri;
-        private final String name;
-
-        NSName(final String uri, final String name) {
-            this.uri = requireNonNull(uri);
-            this.name = requireNonNull(name);
-        }
-    }
-
     private static final Logger LOG = LoggerFactory.getLogger(StreamWriterFacade.class);
     private static final Set<String> BROKEN_NAMESPACES = ConcurrentHashMap.newKeySet();
     private static final Set<String> LEGACY_ATTRIBUTES = ConcurrentHashMap.newKeySet();
@@ -54,7 +40,7 @@ final class StreamWriterFacade extends ValueWriter {
 
     // QName of an element we delayed emitting. This only happens if it is a naked element, without any attributes,
     // namespace declarations or value.
-    private Object openElement;
+    private QName openElement;
 
     StreamWriterFacade(final XMLStreamWriter writer) {
         this.writer = requireNonNull(writer);
@@ -95,42 +81,12 @@ final class StreamWriterFacade extends ValueWriter {
 
     private void flushElement() throws XMLStreamException {
         if (openElement != null) {
-            final String nsUri;
-            final String localName;
-            if (openElement instanceof QName) {
-                final QName qname = (QName) openElement;
-                nsUri = qname.getNamespace().toString();
-                localName = qname.getLocalName();
-            } else {
-                verify(openElement instanceof NSName);
-                final NSName nsname = (NSName) openElement;
-                nsUri = nsname.uri;
-                localName = nsname.name;
-            }
-            writer.writeStartElement(XMLConstants.DEFAULT_NS_PREFIX, localName, nsUri);
+            writer.writeStartElement(XMLConstants.DEFAULT_NS_PREFIX, openElement.getLocalName(),
+                openElement.getNamespace().toString());
             openElement = null;
         }
     }
 
-    void writeStartElement(final String namespace, final String localName) throws XMLStreamException {
-        flushElement();
-
-        final NamespaceContext context = writer.getNamespaceContext();
-        final boolean reuseNamespace;
-        if (context != null) {
-            reuseNamespace = namespace.equals(context.getNamespaceURI(XMLConstants.DEFAULT_NS_PREFIX));
-        } else {
-            reuseNamespace = XMLConstants.DEFAULT_NS_PREFIX.equals(writer.getPrefix(namespace));
-        }
-
-        if (!reuseNamespace) {
-            writer.writeStartElement(XMLConstants.DEFAULT_NS_PREFIX, localName, namespace);
-            writer.writeDefaultNamespace(namespace);
-        } else {
-            openElement = new NSName(namespace, localName);
-        }
-    }
-
     void writeStartElement(final QName qname) throws XMLStreamException {
         flushElement();
 
@@ -153,20 +109,8 @@ final class StreamWriterFacade extends ValueWriter {
 
     void writeEndElement() throws XMLStreamException {
         if (openElement != null) {
-            final String nsUri;
-            final String localName;
-            if (openElement instanceof QName) {
-                final QName qname = (QName) openElement;
-                nsUri = qname.getNamespace().toString();
-                localName = qname.getLocalName();
-            } else {
-                verify(openElement instanceof NSName);
-                final NSName nsname = (NSName) openElement;
-                nsUri = nsname.uri;
-                localName = nsname.name;
-            }
-
-            writer.writeEmptyElement(XMLConstants.DEFAULT_NS_PREFIX, localName, nsUri);
+            writer.writeEmptyElement(XMLConstants.DEFAULT_NS_PREFIX, openElement.getLocalName(),
+                openElement.getNamespace().toString());
             openElement = null;
         } else {
             writer.writeEndElement();
@@ -218,23 +162,37 @@ final class StreamWriterFacade extends ValueWriter {
     void anydataWriteStreamReader(final XMLStreamReader reader) throws XMLStreamException {
         flushElement();
 
+        // Do not emit top-level element
+        int depth = 0;
         while (reader.hasNext()) {
             final int event = reader.next();
             switch (event) {
                 case XMLStreamConstants.START_ELEMENT:
-                    forwardStartElement(reader);
+                    if (depth != 0) {
+                        forwardStartElement(reader);
+                    } else {
+                        // anydata: forward namespaces only, skipping the default namespace
+                        for (int i = 0; i < reader.getNamespaceCount(); ++i) {
+                            final String prefix = reader.getNamespacePrefix(i);
+                            if (!XMLConstants.DEFAULT_NS_PREFIX.equals(prefix)) {
+                                writer.writeNamespace(prefix, reader.getNamespaceURI(i));
+                            }
+                        }
+                    }
+                    ++depth;
                     break;
                 case XMLStreamConstants.END_ELEMENT:
-                    writer.writeEndElement();
+                    --depth;
+                    if (depth != 0) {
+                        writer.writeEndElement();
+                    }
                     break;
                 case XMLStreamConstants.CHARACTERS:
                     writer.writeCharacters(reader.getText());
                     break;
                 case XMLStreamConstants.COMMENT:
-                    writer.writeComment(reader.getText());
-                    break;
                 case XMLStreamConstants.SPACE:
-                    // Ignore insignificant whitespace
+                    // Ignore comments and insignificant whitespace
                     break;
                 case XMLStreamConstants.START_DOCUMENT:
                 case XMLStreamConstants.END_DOCUMENT:
@@ -273,15 +231,16 @@ final class StreamWriterFacade extends ValueWriter {
                         forwardStartElement(reader);
                     } else {
                         forwardNamespaces(reader);
+                        // anyxml, hence we need to forward attributes
                         forwardAttributes(reader);
                     }
                     ++depth;
                     break;
                 case XMLStreamConstants.END_ELEMENT:
+                    --depth;
                     if (depth != 0) {
                         writer.writeEndElement();
                     }
-                    --depth;
                     break;
                 case XMLStreamConstants.PROCESSING_INSTRUCTION:
                     forwardProcessingInstruction(reader);
@@ -323,6 +282,7 @@ final class StreamWriterFacade extends ValueWriter {
     }
 
     void emitNormalizedAnydata(final NormalizedAnydata anydata) throws XMLStreamException {
+        flushElement();
         try {
             anydata.writeTo(XMLStreamNormalizedNodeStreamWriter.create(writer, anydata.getSchemaContext(),
                 new SingleChildDataNodeContainer(anydata.getContextNode())));