1 package org.opendaylight.controller.sal.rest.impl;
3 import static com.google.common.base.Preconditions.checkArgument;
5 import java.io.InputStream;
7 import java.util.Stack;
9 import javax.xml.stream.XMLEventReader;
10 import javax.xml.stream.XMLInputFactory;
11 import javax.xml.stream.XMLStreamException;
12 import javax.xml.stream.events.Characters;
13 import javax.xml.stream.events.StartElement;
14 import javax.xml.stream.events.XMLEvent;
16 import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper;
17 import org.opendaylight.controller.sal.restconf.impl.NodeWrapper;
18 import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper;
20 public class XmlReader {
22 private final static XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
23 private XMLEventReader eventReader;
25 public CompositeNodeWrapper read(InputStream entityStream) throws XMLStreamException, UnsupportedFormatException {
26 eventReader = xmlInputFactory.createXMLEventReader(entityStream);
28 if (eventReader.hasNext()) {
29 XMLEvent element = eventReader.peek();
30 if (element.isStartDocument()) {
31 eventReader.nextEvent();
35 if (eventReader.hasNext() && !isCompositeNodeEvent(eventReader.peek())) {
36 throw new UnsupportedFormatException("Root element of XML has to be composite element.");
39 final Stack<NodeWrapper<?>> processingQueue = new Stack<>();
40 CompositeNodeWrapper root = null;
41 NodeWrapper<?> element = null;
42 while (eventReader.hasNext()) {
43 final XMLEvent event = eventReader.nextEvent();
45 if (event.isStartElement()) {
46 final StartElement startElement = event.asStartElement();
47 CompositeNodeWrapper compParentNode = null;
48 if (!processingQueue.isEmpty() && processingQueue.peek() instanceof CompositeNodeWrapper) {
49 compParentNode = (CompositeNodeWrapper) processingQueue.peek();
51 NodeWrapper<?> newNode = null;
52 if (isCompositeNodeEvent(event)) {
54 root = resolveCompositeNodeFromStartElement(startElement);
57 newNode = resolveCompositeNodeFromStartElement(startElement);
59 } else if (isSimpleNodeEvent(event)) {
61 throw new UnsupportedFormatException("Root element of XML has to be composite element.");
63 newNode = resolveSimpleNodeFromStartElement(startElement);
66 if (newNode != null) {
67 processingQueue.push(newNode);
68 if (compParentNode != null) {
69 compParentNode.addValue(newNode);
72 } else if (event.isEndElement()) {
73 element = processingQueue.pop();
77 if (!root.getLocalName().equals(element.getLocalName())) {
78 throw new UnsupportedFormatException("XML should contain only one root element");
84 private boolean isSimpleNodeEvent(final XMLEvent event) throws XMLStreamException {
85 checkArgument(event != null, "XML Event cannot be NULL!");
86 if (event.isStartElement()) {
87 if (eventReader.hasNext()) {
88 final XMLEvent innerEvent;
89 innerEvent = eventReader.peek();
90 if (innerEvent.isCharacters()) {
91 final Characters chars = innerEvent.asCharacters();
92 if (!chars.isWhiteSpace()) {
95 } else if (innerEvent.isEndElement()) {
103 private boolean isCompositeNodeEvent(final XMLEvent event) throws XMLStreamException {
104 checkArgument(event != null, "XML Event cannot be NULL!");
105 if (event.isStartElement()) {
106 if (eventReader.hasNext()) {
108 innerEvent = eventReader.peek();
109 if (innerEvent.isCharacters()) {
110 Characters chars = innerEvent.asCharacters();
111 if (chars.isWhiteSpace()) {
112 eventReader.nextEvent();
113 innerEvent = eventReader.peek();
116 if (innerEvent.isStartElement()) {
124 private SimpleNodeWrapper resolveSimpleNodeFromStartElement(final StartElement startElement)
125 throws XMLStreamException {
126 checkArgument(startElement != null, "Start Element cannot be NULL!");
129 if (eventReader.hasNext()) {
130 final XMLEvent innerEvent = eventReader.peek();
131 if (innerEvent.isCharacters()) {
132 final Characters chars = innerEvent.asCharacters();
133 if (!chars.isWhiteSpace()) {
134 data = innerEvent.asCharacters().getData();
136 } else if (innerEvent.isEndElement()) {
137 if (startElement.getLocation().getCharacterOffset() == innerEvent.getLocation().getCharacterOffset()) {
145 return new SimpleNodeWrapper(getNamespaceFrom(startElement), getLocalNameFrom(startElement), data);
148 private CompositeNodeWrapper resolveCompositeNodeFromStartElement(final StartElement startElement) {
149 checkArgument(startElement != null, "Start Element cannot be NULL!");
150 return new CompositeNodeWrapper(getNamespaceFrom(startElement), getLocalNameFrom(startElement));
153 private String getLocalNameFrom(StartElement startElement) {
154 return startElement.getName().getLocalPart();
157 private URI getNamespaceFrom(StartElement startElement) {
158 String namespaceURI = startElement.getName().getNamespaceURI();
159 return namespaceURI.isEmpty() ? null : URI.create(namespaceURI);