Bug 8745: Add support for parsing attributes to the new XML parser
[yangtools.git] / yang / yang-data-codec-xml / src / main / java / org / opendaylight / yangtools / yang / data / codec / xml / XmlParserStream.java
index 7293b70e4c32c5c48de388d5a4ae39557db982bf..59afd1002a96fe29b00a60e008af54bf2a64199b 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.yangtools.yang.data.codec.xml;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
 import java.io.Closeable;
 import java.io.Flushable;
 import java.io.IOException;
@@ -18,8 +19,11 @@ import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.Deque;
 import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
 import java.util.Set;
 import javax.annotation.concurrent.NotThreadSafe;
+import javax.xml.XMLConstants;
 import javax.xml.namespace.NamespaceContext;
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.stream.Location;
@@ -28,6 +32,7 @@ import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamReader;
 import javax.xml.transform.dom.DOMSource;
 import org.opendaylight.yangtools.util.xml.UntrustedXML;
+import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.data.util.AbstractNodeDataWithSchema;
 import org.opendaylight.yangtools.yang.data.util.AnyXmlNodeDataWithSchema;
@@ -189,6 +194,29 @@ public final class XmlParserStream implements Closeable, Flushable {
         return this;
     }
 
+    private static Map<QName, String> getElementAttributes(final XMLStreamReader in) {
+        Preconditions.checkState(in.isStartElement(), "Attributes can be extracted only from START_ELEMENT.");
+        final Map<QName, String> attributes = new LinkedHashMap<>();
+
+        for (int attrIndex = 0; attrIndex < in.getAttributeCount(); attrIndex++) {
+            String attributeNS = in.getAttributeNamespace(attrIndex);
+
+            if (attributeNS == null) {
+                attributeNS = "";
+            }
+
+            // Skip namespace definitions
+            if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(attributeNS)) {
+                continue;
+            }
+
+            final QName qName = new QName(URI.create(attributeNS), in.getAttributeLocalName(attrIndex));
+            attributes.put(qName, in.getAttributeValue(attrIndex));
+        }
+
+        return ImmutableMap.copyOf(attributes);
+    }
+
     private static String readAnyXmlValue(final XMLStreamReader in) throws XMLStreamException {
         final StringBuilder sb = new StringBuilder();
         final String anyXmlElementName = in.getLocalName();
@@ -221,6 +249,7 @@ public final class XmlParserStream implements Closeable, Flushable {
         }
 
         if (parent instanceof LeafNodeDataWithSchema || parent instanceof LeafListEntryNodeDataWithSchema) {
+            parent.setAttributes(getElementAttributes(in));
             setValue(parent, in.getElementText().trim(), in.getNamespaceContext());
             if (isNextEndDocument(in)) {
                 return;
@@ -232,6 +261,10 @@ public final class XmlParserStream implements Closeable, Flushable {
             return;
         }
 
+        if (parent instanceof ListEntryNodeDataWithSchema || parent instanceof ContainerNodeDataWithSchema) {
+            parent.setAttributes(getElementAttributes(in));
+        }
+
         if (parent instanceof LeafListNodeDataWithSchema || parent instanceof ListNodeDataWithSchema) {
             String xmlElementName = in.getLocalName();
             while (xmlElementName.equals(parent.getSchema().getQName().getLocalName())) {
@@ -258,6 +291,10 @@ public final class XmlParserStream implements Closeable, Flushable {
             return;
         }
 
+        if (parent instanceof YangModeledAnyXmlSchemaNode) {
+            parent.setAttributes(getElementAttributes(in));
+        }
+
         switch (in.nextTag()) {
             case XMLStreamConstants.START_ELEMENT:
                 final Set<String> namesakes = new HashSet<>();