From: Michal Cmarada Date: Wed, 11 Jul 2018 15:18:59 +0000 (+0200) Subject: YANGTOOLS-890 - Fix XML parser bug X-Git-Tag: v2.0.8~7 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=ebb437c810fcdc2ac52d7c34f5ab5eb1facb19c7;p=yangtools.git YANGTOOLS-890 - Fix XML parser bug When model contains list which has the same name as its encapsulating parent container it leads to IllegalStateException: Attributes can be extracted only from START_ELEMENT. This is caused by list not beeing processed correctly and one additional empty list item is created. To fix this it is necessary to end the loop when end list element is reached. Change-Id: I0d6f6ec356e503fcfc941f18d9133ea0c9cebc6c Signed-off-by: Michal Cmarada --- diff --git a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlParserStream.java b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlParserStream.java index 79901ffd9a..eba402eb8e 100644 --- a/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlParserStream.java +++ b/yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlParserStream.java @@ -289,7 +289,8 @@ public final class XmlParserStream implements Closeable, Flushable { String xmlElementName = in.getLocalName(); while (xmlElementName.equals(parent.getSchema().getQName().getLocalName())) { read(in, newEntryNode(parent), rootElement); - if (in.getEventType() == XMLStreamConstants.END_DOCUMENT) { + if (in.getEventType() == XMLStreamConstants.END_DOCUMENT + || in.getEventType() == XMLStreamConstants.END_ELEMENT) { break; } xmlElementName = in.getLocalName(); diff --git a/yang/yang-data-codec-xml/src/test/java/org/opendaylight/yangtools/yang/data/codec/xml/Bug890Test.java b/yang/yang-data-codec-xml/src/test/java/org/opendaylight/yangtools/yang/data/codec/xml/Bug890Test.java new file mode 100644 index 0000000000..fdc76d787c --- /dev/null +++ b/yang/yang-data-codec-xml/src/test/java/org/opendaylight/yangtools/yang/data/codec/xml/Bug890Test.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2018 Pantheon Technologies s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.yangtools.yang.data.codec.xml; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.InputStream; +import java.net.URI; +import java.util.Collection; +import java.util.Optional; +import javax.xml.stream.XMLStreamReader; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.yangtools.util.xml.UntrustedXML; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.QNameModule; +import org.opendaylight.yangtools.yang.common.Revision; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; +import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; +import org.opendaylight.yangtools.yang.data.api.schema.MapNode; +import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter; +import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter; +import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult; +import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils; + +public class Bug890Test { + private static final QNameModule FOO_MODULE = QNameModule.create(URI.create("foo"), Revision.of("2018-07-10")); + private static final QName OUTGOING_LABELS_QNAME = QName.create(FOO_MODULE, "outgoing-labels"); + private static final QName INDEX_QNAME = QName.create(FOO_MODULE, "index"); + + private SchemaContext schemaContext; + + @Before + public void setUp() throws Exception { + schemaContext = YangParserTestUtils.parseYangResource("/bug890/yang/foo.yang"); + } + + @Test + public void testinputXml() throws Exception { + final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/bug890/xml/foo.xml"); + final Module fooModule = schemaContext.getModules().iterator().next(); + final Optional rootCont = fooModule.findDataChildByName( + QName.create(fooModule.getQNameModule(), "root")); + assertTrue(rootCont.isPresent()); + ContainerSchemaNode containerSchemaNode = (ContainerSchemaNode) rootCont.get(); + assertNotNull(containerSchemaNode); + + final XMLStreamReader reader = UntrustedXML.createXMLStreamReader(resourceAsStream); + + final NormalizedNodeResult result = new NormalizedNodeResult(); + + final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result); + + final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext, containerSchemaNode); + xmlParser.parse(reader); + + assertNotNull(result.getResult()); + assertTrue(result.getResult() instanceof ContainerNode); + final ContainerNode rootContainer = (ContainerNode) result.getResult(); + + Optional> myLeaf = + rootContainer.getChild(new NodeIdentifier(OUTGOING_LABELS_QNAME)); + assertTrue(myLeaf.orElse(null) instanceof ContainerNode); + + ContainerNode outgoingLabelsContainer = (ContainerNode)myLeaf.get(); + Optional> outgoingLabelsList = + outgoingLabelsContainer.getChild(new NodeIdentifier(OUTGOING_LABELS_QNAME)); + assertTrue(outgoingLabelsList.orElse(null) instanceof MapNode); + MapNode outgoingLabelsMap = (MapNode) outgoingLabelsList.get(); + + assertEquals(2, outgoingLabelsMap.getValue().size()); + Collection labels = outgoingLabelsMap.getValue(); + YangInstanceIdentifier.NodeIdentifierWithPredicates firstNodeId = + new YangInstanceIdentifier.NodeIdentifierWithPredicates(OUTGOING_LABELS_QNAME, INDEX_QNAME, 0); + YangInstanceIdentifier.NodeIdentifierWithPredicates secondNodeId = + new YangInstanceIdentifier.NodeIdentifierWithPredicates(OUTGOING_LABELS_QNAME, INDEX_QNAME, 1); + assertTrue(labels.stream().anyMatch(mapEntryNode -> mapEntryNode.getIdentifier().compareTo(firstNodeId) == 0)); + assertTrue(labels.stream().anyMatch(mapEntryNode -> mapEntryNode.getIdentifier().compareTo(secondNodeId) == 0)); + } +} diff --git a/yang/yang-data-codec-xml/src/test/resources/bug890/xml/foo.xml b/yang/yang-data-codec-xml/src/test/resources/bug890/xml/foo.xml new file mode 100644 index 0000000000..4bd91b1ebf --- /dev/null +++ b/yang/yang-data-codec-xml/src/test/resources/bug890/xml/foo.xml @@ -0,0 +1,19 @@ + + + + + 0 + + 0 + + + + + 1 + + 1 + + + + + \ No newline at end of file diff --git a/yang/yang-data-codec-xml/src/test/resources/bug890/yang/foo.yang b/yang/yang-data-codec-xml/src/test/resources/bug890/yang/foo.yang new file mode 100644 index 0000000000..4caaf48539 --- /dev/null +++ b/yang/yang-data-codec-xml/src/test/resources/bug890/yang/foo.yang @@ -0,0 +1,54 @@ +module foo { + yang-version 1; + namespace "foo"; + prefix "foo"; + + revision "2018-07-10" { + } + + grouping path-outgoing-labels_config { + description "Path outgoing labels grouping"; + leaf index { + type uint8 { + range "0..255"; + } + description "Index of the label. Index 0 indicates top of the label stack"; + } + leaf label { + type uint32; + description "The outgoing MPLS labels to impose"; + } + } + + grouping path-outgoing-labels { + description "Path outgoing labels grouping"; + container outgoing-labels { + description "List of outgoing labels"; + list outgoing-labels { + key "index"; + description "Outgoing label list"; + leaf index { + type leafref { + path "../config/index"; + } + description + "Index of the label. Index 0 indicates + top of the label stack"; + } + container config { + description "Configuration intended parameters"; + uses path-outgoing-labels_config; + } + container state { + config false; + description "Configuration applied parameters and state"; + uses path-outgoing-labels_config; + } + } + } + } + + container root { + uses path-outgoing-labels; + } +}