2 * Copyright (c) 2014 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
8 package org.opendaylight.yangtools.yang.data.impl.codec.xml;
10 import com.google.common.base.Preconditions;
11 import com.google.common.base.Splitter;
14 import java.net.URISyntaxException;
15 import java.util.ArrayList;
16 import java.util.HashMap;
17 import java.util.Iterator;
18 import java.util.List;
20 import java.util.Map.Entry;
21 import java.util.regex.Matcher;
22 import java.util.regex.Pattern;
24 import org.opendaylight.yangtools.yang.common.QName;
25 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
26 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
27 import org.opendaylight.yangtools.yang.model.api.Module;
28 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
29 import org.w3c.dom.Element;
31 public final class InstanceIdentifierForXmlCodec {
32 private static final Pattern PREDICATE_PATTERN = Pattern.compile("\\[(.*?)\\]");
33 private static final Splitter SLASH_SPLITTER = Splitter.on('/');
34 private static final Splitter COLON_SPLITTER = Splitter.on(':');
36 private InstanceIdentifierForXmlCodec() {
37 throw new UnsupportedOperationException("Utility class");
40 public static InstanceIdentifier deserialize(final Element element, final SchemaContext schemaContext) {
41 Preconditions.checkNotNull(element, "Value of element for deserialization can't be null");
42 Preconditions.checkNotNull(schemaContext,
43 "Schema context for deserialization of instance identifier type can't be null");
45 final String valueTrimmed = element.getTextContent().trim();
46 final Iterator<String> xPathParts = SLASH_SPLITTER.split(valueTrimmed).iterator();
48 // must be at least "/pr:node"
49 if (!xPathParts.hasNext() || !xPathParts.next().isEmpty() || !xPathParts.hasNext()) {
53 List<PathArgument> result = new ArrayList<>();
54 while (xPathParts.hasNext()) {
55 String xPathPartTrimmed = xPathParts.next().trim();
57 PathArgument pathArgument = toPathArgument(xPathPartTrimmed, element, schemaContext);
58 if (pathArgument != null) {
59 result.add(pathArgument);
62 return InstanceIdentifier.create(result);
65 public static Element serialize(final InstanceIdentifier id, final Element element) {
66 Preconditions.checkNotNull(id, "Variable should contain instance of instance identifier and can't be null");
67 Preconditions.checkNotNull(element, "DOM element can't be null");
69 final RandomPrefix prefixes = new RandomPrefix();
70 final String str = XmlUtils.encodeIdentifier(prefixes, id);
72 for (Entry<URI, String> e: prefixes.getPrefixes()) {
73 element.setAttribute("xmlns:" + e.getValue(), e.getKey().toString());
75 element.setTextContent(str);
79 private static String getIdAndPrefixAsStr(final String pathPart) {
80 int predicateStartIndex = pathPart.indexOf('[');
81 return predicateStartIndex == -1 ? pathPart : pathPart.substring(0, predicateStartIndex);
84 private static PathArgument toPathArgument(final String xPathArgument, final Element element, final SchemaContext schemaContext) {
85 final QName mainQName = toIdentity(xPathArgument, element, schemaContext);
88 final Matcher matcher = PREDICATE_PATTERN.matcher(xPathArgument);
89 final Map<QName, Object> predicates = new HashMap<>();
90 QName currentQName = mainQName;
92 while (matcher.find()) {
93 final String predicateStr = matcher.group(1).trim();
94 final int indexOfEqualityMark = predicateStr.indexOf('=');
95 if (indexOfEqualityMark != -1) {
96 final String predicateValue = toPredicateValue(predicateStr.substring(indexOfEqualityMark + 1));
97 if (predicateValue == null) {
101 if (predicateStr.charAt(0) != '.') {
102 // target is not a leaf-list
103 currentQName = toIdentity(predicateStr.substring(0, indexOfEqualityMark), element, schemaContext);
104 if (currentQName == null) {
108 predicates.put(currentQName, predicateValue);
112 if (predicates.isEmpty()) {
113 return new InstanceIdentifier.NodeIdentifier(mainQName);
115 return new InstanceIdentifier.NodeIdentifierWithPredicates(mainQName, predicates);
120 public static QName toIdentity(final String xPathArgument, final Element element, final SchemaContext schemaContext) {
121 final String xPathPartTrimmed = getIdAndPrefixAsStr(xPathArgument).trim();
122 final Iterator<String> it = COLON_SPLITTER.split(xPathPartTrimmed).iterator();
129 final String prefix = it.next().trim();
130 if (prefix.isEmpty()) {
134 // it is not "prefix:value"
139 final String identifier = it.next().trim();
140 if (identifier.isEmpty()) {
144 URI namespace = null;
145 String namespaceStr = null;
147 namespaceStr = element.lookupNamespaceURI(prefix);
148 namespace = new URI(namespaceStr);
149 } catch (URISyntaxException e) {
150 throw new IllegalArgumentException("It wasn't possible to convert " + namespaceStr + " to URI object.");
151 } catch (NullPointerException e) {
152 throw new IllegalArgumentException("I wasn't possible to get namespace for prefix " + prefix);
155 Module module = schemaContext.findModuleByNamespaceAndRevision(namespace, null);
156 return QName.create(module.getQNameModule(), identifier);
159 private static String trimIfEndIs(final String str, final char end) {
160 final int l = str.length() - 1;
161 if (str.charAt(l) != end) {
165 return str.substring(1, l);
168 private static String toPredicateValue(final String predicatedValue) {
169 final String predicatedValueTrimmed = predicatedValue.trim();
170 if (predicatedValue.isEmpty()) {
174 switch (predicatedValueTrimmed.charAt(0)) {
176 return trimIfEndIs(predicatedValueTrimmed, '"');
178 return trimIfEndIs(predicatedValueTrimmed, '\'');