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.IdentityValuesDTO;
18 import org.opendaylight.controller.sal.restconf.impl.EmptyNodeWrapper;
19 import org.opendaylight.controller.sal.restconf.impl.NodeWrapper;
20 import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper;
21 import org.opendaylight.yangtools.yang.data.api.Node;
23 public class XmlReader {
25 private final static XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
26 private XMLEventReader eventReader;
28 public CompositeNodeWrapper read(InputStream entityStream) throws XMLStreamException, UnsupportedFormatException {
29 eventReader = xmlInputFactory.createXMLEventReader(entityStream);
31 if (eventReader.hasNext()) {
32 XMLEvent element = eventReader.peek();
33 if (element.isStartDocument()) {
34 eventReader.nextEvent();
38 if (eventReader.hasNext() && !isCompositeNodeEvent(eventReader.peek())) {
39 throw new UnsupportedFormatException("Root element of XML has to be composite element.");
42 final Stack<NodeWrapper<?>> processingQueue = new Stack<>();
43 CompositeNodeWrapper root = null;
44 NodeWrapper<?> element = null;
45 while (eventReader.hasNext()) {
46 final XMLEvent event = eventReader.nextEvent();
48 if (event.isStartElement()) {
49 final StartElement startElement = event.asStartElement();
50 CompositeNodeWrapper compParentNode = null;
51 if (!processingQueue.isEmpty() && processingQueue.peek() instanceof CompositeNodeWrapper) {
52 compParentNode = (CompositeNodeWrapper) processingQueue.peek();
54 NodeWrapper<?> newNode = null;
55 if (isCompositeNodeEvent(event)) {
57 root = resolveCompositeNodeFromStartElement(startElement);
60 newNode = resolveCompositeNodeFromStartElement(startElement);
62 } else if (isSimpleNodeEvent(event)) {
64 throw new UnsupportedFormatException("Root element of XML has to be composite element.");
66 newNode = resolveSimpleNodeFromStartElement(startElement);
69 if (newNode != null) {
70 processingQueue.push(newNode);
71 if (compParentNode != null) {
72 compParentNode.addValue(newNode);
75 } else if (event.isEndElement()) {
76 element = processingQueue.pop();
80 if (!root.getLocalName().equals(element.getLocalName())) {
81 throw new UnsupportedFormatException("XML should contain only one root element");
87 private boolean isSimpleNodeEvent(final XMLEvent event) throws XMLStreamException {
88 checkArgument(event != null, "XML Event cannot be NULL!");
89 if (event.isStartElement()) {
90 if (eventReader.hasNext()) {
91 final XMLEvent innerEvent;
92 innerEvent = eventReader.peek();
93 if (innerEvent.isCharacters()) {
94 final Characters chars = innerEvent.asCharacters();
95 if (!chars.isWhiteSpace()) {
98 } else if (innerEvent.isEndElement()) {
106 private boolean isCompositeNodeEvent(final XMLEvent event) throws XMLStreamException {
107 checkArgument(event != null, "XML Event cannot be NULL!");
108 if (event.isStartElement()) {
109 if (eventReader.hasNext()) {
111 innerEvent = eventReader.peek();
112 if (innerEvent.isCharacters()) {
113 Characters chars = innerEvent.asCharacters();
114 if (chars.isWhiteSpace()) {
115 eventReader.nextEvent();
116 innerEvent = eventReader.peek();
119 if (innerEvent.isStartElement()) {
127 private CompositeNodeWrapper resolveCompositeNodeFromStartElement(final StartElement startElement) {
128 checkArgument(startElement != null, "Start Element cannot be NULL!");
129 return new CompositeNodeWrapper(getNamespaceFor(startElement), getLocalNameFor(startElement));
132 private NodeWrapper<? extends Node<?>> resolveSimpleNodeFromStartElement(final StartElement startElement)
133 throws XMLStreamException {
134 checkArgument(startElement != null, "Start Element cannot be NULL!");
135 String data = getValueOf(startElement);
137 return new EmptyNodeWrapper(getNamespaceFor(startElement), getLocalNameFor(startElement));
139 return new SimpleNodeWrapper(getNamespaceFor(startElement), getLocalNameFor(startElement),
140 resolveValueOfElement(data, startElement));
143 private String getValueOf(StartElement startElement) throws XMLStreamException {
145 if (eventReader.hasNext()) {
146 final XMLEvent innerEvent = eventReader.peek();
147 if (innerEvent.isCharacters()) {
148 final Characters chars = innerEvent.asCharacters();
149 if (!chars.isWhiteSpace()) {
150 data = innerEvent.asCharacters().getData();
152 } else if (innerEvent.isEndElement()) {
153 if (startElement.getLocation().getCharacterOffset() == innerEvent.getLocation().getCharacterOffset()) {
163 private String getLocalNameFor(StartElement startElement) {
164 return startElement.getName().getLocalPart();
167 private URI getNamespaceFor(StartElement startElement) {
168 String namespaceURI = startElement.getName().getNamespaceURI();
169 return namespaceURI.isEmpty() ? null : URI.create(namespaceURI);
174 * value of startElement
175 * @param startElement
176 * element containing value
177 * @return if value is "prefix:value" then {@link IdentityValuesDTO} else the same
178 * string as parameter "value"
180 private Object resolveValueOfElement(String value, StartElement startElement) {
181 String[] namespaceAndValue = value.split(":");
182 if (namespaceAndValue.length != 2) { // it is not "prefix:value"
185 String namespace = startElement.getNamespaceContext().getNamespaceURI(namespaceAndValue[0]);
186 if (namespace != null && !namespace.isEmpty()) {
187 return new IdentityValuesDTO(namespace, namespaceAndValue[1], namespaceAndValue[0]);