2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.yangtools.yang.data.codec.xml;
11 import com.google.common.base.Preconditions;
12 import com.google.common.collect.Sets;
13 import java.io.IOException;
14 import java.io.InputStream;
15 import java.io.StringWriter;
17 import java.net.URISyntaxException;
18 import java.text.ParseException;
19 import java.util.ArrayList;
20 import java.util.HashMap;
21 import java.util.List;
23 import javax.xml.parsers.DocumentBuilder;
24 import javax.xml.parsers.DocumentBuilderFactory;
25 import javax.xml.parsers.ParserConfigurationException;
26 import javax.xml.stream.XMLOutputFactory;
27 import javax.xml.stream.XMLStreamException;
28 import javax.xml.stream.XMLStreamWriter;
29 import javax.xml.transform.OutputKeys;
30 import javax.xml.transform.Transformer;
31 import javax.xml.transform.TransformerException;
32 import javax.xml.transform.TransformerFactory;
33 import javax.xml.transform.TransformerFactoryConfigurationError;
34 import javax.xml.transform.dom.DOMResult;
35 import javax.xml.transform.dom.DOMSource;
36 import javax.xml.transform.stream.StreamResult;
37 import org.custommonkey.xmlunit.Diff;
38 import org.custommonkey.xmlunit.DifferenceListener;
39 import org.custommonkey.xmlunit.IgnoreTextAndAttributeValuesDifferenceListener;
40 import org.custommonkey.xmlunit.XMLAssert;
41 import org.custommonkey.xmlunit.XMLUnit;
42 import org.junit.Before;
43 import org.junit.Test;
44 import org.opendaylight.yangtools.yang.common.QName;
45 import org.opendaylight.yangtools.yang.common.QNameModule;
46 import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
47 import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode;
48 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
49 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
50 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
51 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
52 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
53 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
54 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
55 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
56 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
57 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
58 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
59 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
60 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
61 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
62 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
63 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
64 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
65 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
66 import org.w3c.dom.Document;
67 import org.w3c.dom.Node;
68 import org.xml.sax.SAXException;
70 public class SchemalessXMLStreamNormalizedNodeStreamWriterTest {
72 private QNameModule foobarModule;
74 private QName outerContainer;
76 private QName myContainer1;
77 private QName myKeyedList;
78 private QName myKeyLeaf;
79 private QName myLeafInList1;
80 private QName myLeafInList2;
81 private QName myOrderedList;
82 private QName myKeyLeafInOrderedList;
83 private QName myLeafInOrderedList1;
84 private QName myLeafInOrderedList2;
85 private QName myUnkeyedList;
86 private QName myLeafInUnkeyedList;
87 private QName myLeaf1;
88 private QName myLeafList;
89 private QName myOrderedLeafList;
91 private QName myContainer2;
92 private QName innerContainer;
93 private QName myLeaf2;
94 private QName myLeaf3;
95 private QName myChoice;
96 private QName myLeafInCase2;
97 private QName myAnyxml;
99 private QName myContainer3;
100 private QName myDoublyKeyedList;
101 private QName myFirstKeyLeaf;
102 private QName mySecondKeyLeaf;
103 private QName myLeafInList3;
105 private DOMSource anyxmlDomSource;
108 public void setup() throws URISyntaxException, ParseException {
109 foobarModule = QNameModule.create(new URI("foobar-namespace"), SimpleDateFormatUtil.getRevisionFormat().parse
112 outerContainer = QName.create(foobarModule, "outer-container");
114 myContainer1 = QName.create(foobarModule, "my-container-1");
115 myKeyedList = QName.create(foobarModule, "my-keyed-list");
116 myKeyLeaf = QName.create(foobarModule, "my-key-leaf");
117 myLeafInList1 = QName.create(foobarModule, "my-leaf-in-list-1");
118 myLeafInList2 = QName.create(foobarModule, "my-leaf-in-list-2");
119 myOrderedList = QName.create(foobarModule, "my-ordered-list");
120 myKeyLeafInOrderedList = QName.create(foobarModule, "my-key-leaf-in-ordered-list");
121 myLeafInOrderedList1 = QName.create(foobarModule, "my-leaf-in-ordered-list-1");
122 myLeafInOrderedList2 = QName.create(foobarModule, "my-leaf-in-ordered-list-2");
123 myUnkeyedList = QName.create(foobarModule, "my-unkeyed-list");
124 myLeafInUnkeyedList = QName.create(foobarModule, "my-leaf-in-unkeyed-list");
125 myLeaf1 = QName.create(foobarModule, "my-leaf-1");
126 myLeafList = QName.create(foobarModule, "my-leaf-list");
127 myOrderedLeafList = QName.create(foobarModule, "my-ordered-leaf-list");
129 myContainer2 = QName.create(foobarModule, "my-container-2");
130 innerContainer = QName.create(foobarModule, "inner-container");
131 myLeaf2 = QName.create(foobarModule, "my-leaf-2");
132 myLeaf3 = QName.create(foobarModule, "my-leaf-3");
133 myChoice = QName.create(foobarModule, "my-choice");
134 myLeafInCase2 = QName.create(foobarModule, "my-leaf-in-case-2");
135 myAnyxml = QName.create(foobarModule, "my-anyxml");
137 myContainer3 = QName.create(foobarModule, "my-container-3");
138 myDoublyKeyedList = QName.create(foobarModule, "my-doubly-keyed-list");
139 myFirstKeyLeaf = QName.create(foobarModule, "my-first-key-leaf");
140 mySecondKeyLeaf = QName.create(foobarModule, "my-second-key-leaf");
141 myLeafInList3 = QName.create(foobarModule, "my-leaf-in-list-3");
143 anyxmlDomSource = new DOMSource();
147 public void testWrite() throws XMLStreamException, IOException, SAXException {
148 final Document doc = loadDocument("/foobar.xml");
150 final Document document = getDocument();
151 final DOMResult domResult = new DOMResult(document);
153 final XMLOutputFactory factory = XMLOutputFactory.newInstance();
154 factory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
156 final XMLStreamWriter xmlStreamWriter = factory.createXMLStreamWriter(domResult);
158 final NormalizedNodeStreamWriter schemalessXmlNormalizedNodeStreamWriter =
159 XMLStreamNormalizedNodeStreamWriter.createSchemaless(xmlStreamWriter);
161 final NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter
162 (schemalessXmlNormalizedNodeStreamWriter);
164 normalizedNodeWriter.write(buildOuterContainerNode());
166 XMLUnit.setIgnoreWhitespace(true);
167 XMLUnit.setNormalize(true);
169 final String expectedXml = toString(doc.getDocumentElement().getElementsByTagName("outer-container").item(0));
170 final String serializedXml = toString(domResult.getNode());
171 final Diff diff = new Diff(expectedXml, serializedXml);
173 final DifferenceListener differenceListener = new IgnoreTextAndAttributeValuesDifferenceListener();
174 diff.overrideDifferenceListener(differenceListener);
176 XMLAssert.assertXMLEqual(diff, true);
179 private NormalizedNode<?, ?> buildOuterContainerNode() {
181 MapNode myKeyedListNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(myKeyedList))
182 .withChild(Builders.mapEntryBuilder().withNodeIdentifier(
183 new NodeIdentifierWithPredicates(myKeyedList, myKeyLeaf, "listkeyvalue1"))
184 .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeafInList1))
185 .withValue("listleafvalue1").build())
186 .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeafInList2))
187 .withValue("listleafvalue2").build()).build())
188 .withChild(Builders.mapEntryBuilder().withNodeIdentifier(
189 new NodeIdentifierWithPredicates(myKeyedList, myKeyLeaf, "listkeyvalue2"))
190 .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeafInList1))
191 .withValue("listleafvalue12").build())
192 .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeafInList2))
193 .withValue("listleafvalue22").build()).build()).build();
195 OrderedMapNode myOrderedListNode = Builders.orderedMapBuilder().withNodeIdentifier(new NodeIdentifier(myOrderedList))
196 .withChild(Builders.mapEntryBuilder().withNodeIdentifier(
197 new NodeIdentifierWithPredicates(myOrderedList, myKeyLeafInOrderedList, "olistkeyvalue1"))
198 .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeafInOrderedList1))
199 .withValue("olistleafvalue1").build())
200 .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeafInOrderedList2))
201 .withValue("olistleafvalue2").build()).build())
202 .withChild(Builders.mapEntryBuilder().withNodeIdentifier(
203 new NodeIdentifierWithPredicates(myOrderedList, myKeyLeafInOrderedList, "olistkeyvalue2"))
204 .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeafInOrderedList1))
205 .withValue("olistleafvalue12").build())
206 .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeafInOrderedList2))
207 .withValue("olistleafvalue22").build()).build()).build();
209 final UnkeyedListEntryNode unkeyedListEntry = Builders.unkeyedListEntryBuilder()
210 .withNodeIdentifier(new NodeIdentifier(myUnkeyedList))
211 .withChild(ImmutableNodes.leafNode(myLeafInUnkeyedList, "foo")).build();
213 final List<UnkeyedListEntryNode> unkeyedListEntries = new ArrayList<>();
214 unkeyedListEntries.add(unkeyedListEntry);
216 UnkeyedListNode myUnkeyedListNode = Builders.unkeyedListBuilder().withNodeIdentifier(
217 new NodeIdentifier(myUnkeyedList))
218 .withValue(unkeyedListEntries).build();
220 LeafNode<?> myLeaf1Node = Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeaf1))
221 .withValue("value1").build();
223 LeafSetNode<?> myLeafListNode = Builders.leafSetBuilder().withNodeIdentifier(new NodeIdentifier(myLeafList))
224 .withChild(Builders.leafSetEntryBuilder().withNodeIdentifier(
225 new NodeWithValue<>(myLeafList, "lflvalue1")).withValue("lflvalue1").build())
226 .withChild(Builders.leafSetEntryBuilder().withNodeIdentifier(
227 new NodeWithValue<>(myLeafList, "lflvalue2")).withValue("lflvalue2").build()).build();
229 LeafSetNode<?> myOrderedLeafListNode = Builders.orderedLeafSetBuilder().withNodeIdentifier(
230 new NodeIdentifier(myOrderedLeafList))
231 .withChild(Builders.leafSetEntryBuilder().withNodeIdentifier(
232 new NodeWithValue<>(myOrderedLeafList, "olflvalue1")).withValue("olflvalue1").build())
233 .withChild(Builders.leafSetEntryBuilder().withNodeIdentifier(
234 new NodeWithValue<>(myOrderedLeafList, "olflvalue2")).withValue("olflvalue2").build()).build();
236 ContainerNode myContainer1Node = Builders.containerBuilder().withNodeIdentifier(
237 new NodeIdentifier(myContainer1))
238 .withChild(myKeyedListNode)
239 .withChild(myOrderedListNode)
240 .withChild(myUnkeyedListNode)
241 .withChild(myLeaf1Node)
242 .withChild(myLeafListNode)
243 .withChild(myOrderedLeafListNode)
247 ContainerNode innerContainerNode = Builders.containerBuilder().withNodeIdentifier(
248 new NodeIdentifier(innerContainer))
249 .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeaf2))
250 .withValue("value2").build()).build();
252 LeafNode<?> myLeaf3Node = Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeaf3))
253 .withValue("value3").build();
255 ChoiceNode myChoiceNode = Builders.choiceBuilder().withNodeIdentifier(new NodeIdentifier(myChoice))
256 .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeafInCase2))
257 .withValue("case2value").build()).build();
259 AnyXmlNode myAnyxmlNode = Builders.anyXmlBuilder().withNodeIdentifier(new NodeIdentifier(myAnyxml))
260 .withValue(anyxmlDomSource).build();
262 ContainerNode myContainer2Node = Builders.containerBuilder().withNodeIdentifier(
263 new NodeIdentifier(myContainer2))
264 .withChild(innerContainerNode)
265 .withChild(myLeaf3Node)
266 .withChild(myChoiceNode).build();
267 //.withChild(myAnyxmlNode).build();
270 Map<QName, Object> keys = new HashMap<>();
271 keys.put(myFirstKeyLeaf, "listkeyvalue1");
272 keys.put(mySecondKeyLeaf, "listkeyvalue2");
274 MapNode myDoublyKeyedListNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(myDoublyKeyedList))
275 .withChild(Builders.mapEntryBuilder().withNodeIdentifier(
276 new NodeIdentifierWithPredicates(myDoublyKeyedList, keys))
277 .withChild(Builders.leafBuilder().withNodeIdentifier(
278 new NodeIdentifier(myLeafInList3)).withValue("listleafvalue1").build()).build())
281 AugmentationNode myDoublyKeyedListAugNode = Builders.augmentationBuilder().withNodeIdentifier(
282 new AugmentationIdentifier(Sets.newHashSet(myDoublyKeyedList)))
283 .withChild(myDoublyKeyedListNode).build();
285 ContainerNode myContainer3Node = Builders.containerBuilder().withNodeIdentifier(
286 new NodeIdentifier(myContainer3))
287 .withChild(myDoublyKeyedListAugNode).build();
289 AugmentationNode myContainer3AugNode = Builders.augmentationBuilder().withNodeIdentifier(
290 new AugmentationIdentifier(Sets.newHashSet(myContainer3)))
291 .withChild(myContainer3Node).build();
293 ContainerNode outerContainerNode = Builders.containerBuilder().withNodeIdentifier(
294 new NodeIdentifier(outerContainer))
295 .withChild(myContainer1Node)
296 .withChild(myContainer2Node)
297 .withChild(myContainer3AugNode).build();
299 return outerContainerNode;
302 private static Document loadDocument(final String xmlPath) throws IOException, SAXException {
303 final InputStream resourceAsStream = SchemalessXMLStreamNormalizedNodeStreamWriterTest.class.getResourceAsStream(xmlPath);
304 final Document currentConfigElement = readXmlToDocument(resourceAsStream);
305 Preconditions.checkNotNull(currentConfigElement);
306 return currentConfigElement;
309 private static Document readXmlToDocument(final InputStream xmlContent) throws IOException, SAXException {
310 final DocumentBuilder dBuilder;
312 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
313 factory.setNamespaceAware(true);
314 factory.setCoalescing(true);
315 factory.setIgnoringElementContentWhitespace(true);
316 factory.setIgnoringComments(true);
317 dBuilder = factory.newDocumentBuilder();
318 } catch (final ParserConfigurationException e) {
319 throw new RuntimeException("Failed to parse XML document", e);
321 final Document doc = dBuilder.parse(xmlContent);
323 doc.getDocumentElement().normalize();
327 private static String toString(final Node xml) {
329 final Transformer transformer = TransformerFactory.newInstance().newTransformer();
330 transformer.setOutputProperty(OutputKeys.INDENT, "yes");
331 transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
333 final StreamResult result = new StreamResult(new StringWriter());
334 final DOMSource source = new DOMSource(xml);
335 transformer.transform(source, result);
337 return result.getWriter().toString();
338 } catch (IllegalArgumentException | TransformerFactoryConfigurationError | TransformerException e) {
339 throw new RuntimeException("Unable to serialize xml element " + xml, e);
343 private static Document getDocument() {
344 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
347 DocumentBuilder bob = dbf.newDocumentBuilder();
348 doc = bob.newDocument();
349 } catch (ParserConfigurationException e) {
350 throw new RuntimeException(e);