BUG-580: Improved parsing.
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / util / ParserUtils.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.yangtools.yang.parser.util;
9
10 import com.google.common.base.Function;
11 import com.google.common.base.Preconditions;
12 import com.google.common.collect.Collections2;
13 import com.google.common.io.ByteSource;
14 import java.io.File;
15 import java.io.FileNotFoundException;
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.net.URI;
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.Collection;
22 import java.util.Date;
23 import java.util.HashSet;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Set;
27 import java.util.TreeMap;
28 import org.apache.commons.io.IOUtils;
29 import org.opendaylight.yangtools.yang.common.QName;
30 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
31 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
32 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
33 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
34 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
35 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
36 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
37 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
38 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
39 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
40 import org.opendaylight.yangtools.yang.model.api.Module;
41 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
42 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
43 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
44 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
45 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
46 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
47 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
48 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationTargetBuilder;
49 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
50 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
51 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
52 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
53 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingMember;
54 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
55 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
56 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
57 import org.opendaylight.yangtools.yang.parser.builder.impl.AnyXmlBuilder;
58 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceBuilder;
59 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceCaseBuilder;
60 import org.opendaylight.yangtools.yang.parser.builder.impl.ContainerSchemaNodeBuilder;
61 import org.opendaylight.yangtools.yang.parser.builder.impl.GroupingBuilderImpl;
62 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentitySchemaNodeBuilder;
63 import org.opendaylight.yangtools.yang.parser.builder.impl.LeafListSchemaNodeBuilder;
64 import org.opendaylight.yangtools.yang.parser.builder.impl.LeafSchemaNodeBuilder;
65 import org.opendaylight.yangtools.yang.parser.builder.impl.ListSchemaNodeBuilder;
66 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
67 import org.opendaylight.yangtools.yang.parser.builder.impl.NotificationBuilder;
68 import org.opendaylight.yangtools.yang.parser.builder.impl.RpcDefinitionBuilder;
69 import org.opendaylight.yangtools.yang.parser.builder.impl.TypeDefinitionBuilderImpl;
70 import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
71 import org.slf4j.Logger;
72 import org.slf4j.LoggerFactory;
73
74 public final class ParserUtils {
75
76     private static final Logger LOG = LoggerFactory.getLogger(ParserUtils.class);
77
78     private ParserUtils() {
79     }
80
81     public static Collection<ByteSource> streamsToByteSources(Collection<InputStream> streams) {
82         return Collections2.transform(streams, new Function<InputStream, ByteSource>() {
83             @Override
84             public ByteSource apply(final InputStream input) {
85                 return new ByteSource() {
86                     @Override
87                     public InputStream openStream() throws IOException {
88                         return NamedByteArrayInputStream.create(input);
89                     }
90                 };
91             }
92         });
93     }
94
95     public static ByteSource fileToByteSource(final File file) {
96         return new ByteSource() {
97             @Override
98             public InputStream openStream() throws IOException {
99                 return new NamedFileInputStream(file, file.getAbsolutePath());
100             }
101         };
102     }
103
104     public static Collection<ByteSource> filesToByteSources(Collection<File> streams) throws FileNotFoundException {
105         return Collections2.transform(streams, new Function<File, ByteSource>() {
106             @Override
107             public ByteSource apply(final File input) {
108                 return new ByteSource() {
109                     @Override
110                     public InputStream openStream() throws IOException {
111                         return new NamedFileInputStream(input, input.getAbsolutePath());
112                     }
113                 };
114             }
115         });
116     }
117
118     /**
119      * Set string representation of source to ModuleBuilder.
120      *
121      * @param sourceToBuilder
122      *            source to module mapping
123      */
124     public static void setSourceToBuilder(Map<ByteSource, ModuleBuilder> sourceToBuilder) throws IOException {
125         for (Map.Entry<ByteSource, ModuleBuilder> entry : sourceToBuilder.entrySet()) {
126             ModuleBuilder builder = entry.getValue();
127             ByteSource source = entry.getKey();
128
129             String content = null;
130             InputStream stream = null;
131             try {
132                 stream = source.openStream();
133                 content = IOUtils.toString(stream);
134             } finally {
135                 if (stream != null) {
136                     try {
137                         stream.close();
138                     } catch (IOException e) {
139                         LOG.warn("Failed to close stream {}", stream);
140                     }
141                 }
142             }
143             builder.setSource(content);
144         }
145     }
146
147     /**
148      * Create new SchemaPath from given path and qname.
149      *
150      * @param schemaPath
151      *            base path
152      * @param qname
153      *            one or more qnames added to base path
154      * @return new SchemaPath from given path and qname
155      */
156     public static SchemaPath createSchemaPath(SchemaPath schemaPath, QName... qname) {
157         List<QName> path = new ArrayList<>(schemaPath.getPath());
158         path.addAll(Arrays.asList(qname));
159         return new SchemaPath(path, schemaPath.isAbsolute());
160     }
161
162     /**
163      * Get module import referenced by given prefix.
164      *
165      * @param builder
166      *            module to search
167      * @param prefix
168      *            prefix associated with import
169      * @return ModuleImport based on given prefix
170      */
171     public static ModuleImport getModuleImport(ModuleBuilder builder, String prefix) {
172         for (ModuleImport mi : builder.getModuleImports()) {
173             if (mi.getPrefix().equals(prefix)) {
174                 return mi;
175
176             }
177         }
178         return null;
179     }
180
181     /**
182      * Find dependent module based on given prefix
183      *
184      * @param modules
185      *            all available modules
186      * @param module
187      *            current module
188      * @param prefix
189      *            target module prefix
190      * @param line
191      *            current line in yang model
192      * @return module builder if found, null otherwise
193      */
194     public static ModuleBuilder findModuleFromBuilders(Map<String, TreeMap<Date, ModuleBuilder>> modules,
195             ModuleBuilder module, String prefix, int line) {
196         ModuleBuilder dependentModule = null;
197         Date dependentModuleRevision = null;
198
199         if (prefix == null) {
200             dependentModule = module;
201         } else if (prefix.equals(module.getPrefix())) {
202             dependentModule = module;
203         } else {
204             ModuleImport dependentModuleImport = getModuleImport(module, prefix);
205             if (dependentModuleImport == null) {
206                 throw new YangParseException(module.getName(), line, "No import found with prefix '" + prefix + "'.");
207             }
208             String dependentModuleName = dependentModuleImport.getModuleName();
209             dependentModuleRevision = dependentModuleImport.getRevision();
210
211             TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules.get(dependentModuleName);
212             if (moduleBuildersByRevision == null) {
213                 return null;
214             }
215             if (dependentModuleRevision == null) {
216                 dependentModule = moduleBuildersByRevision.lastEntry().getValue();
217             } else {
218                 dependentModule = moduleBuildersByRevision.get(dependentModuleRevision);
219             }
220         }
221         return dependentModule;
222     }
223
224     /**
225      * Find module from context based on prefix.
226      *
227      * @param context
228      *            schema context
229      * @param currentModule
230      *            current module
231      * @param prefix
232      *            current prefix used to reference dependent module
233      * @param line
234      *            current line in yang model
235      * @return module based on given prefix if found in context, null otherwise
236      */
237     public static Module findModuleFromContext(SchemaContext context, ModuleBuilder currentModule, String prefix,
238             int line) {
239         if (context == null) {
240             throw new YangParseException(currentModule.getName(), line, "Cannot find module with prefix '" + prefix
241                     + "'.");
242         }
243         TreeMap<Date, Module> modulesByRevision = new TreeMap<>();
244
245         ModuleImport dependentModuleImport = ParserUtils.getModuleImport(currentModule, prefix);
246         if (dependentModuleImport == null) {
247             throw new YangParseException(currentModule.getName(), line, "No import found with prefix '" + prefix + "'.");
248         }
249         String dependentModuleName = dependentModuleImport.getModuleName();
250         Date dependentModuleRevision = dependentModuleImport.getRevision();
251
252         for (Module contextModule : context.getModules()) {
253             if (contextModule.getName().equals(dependentModuleName)) {
254                 Date revision = contextModule.getRevision();
255                 if (revision == null) {
256                     revision = new Date(0L);
257                 }
258                 modulesByRevision.put(revision, contextModule);
259             }
260         }
261
262         Module result = null;
263         if (dependentModuleRevision == null) {
264             result = modulesByRevision.get(modulesByRevision.firstKey());
265         } else {
266             result = modulesByRevision.get(dependentModuleRevision);
267         }
268         return result;
269     }
270
271     /**
272      * Parse XPath string.
273      *
274      * @param xpathString
275      *            XPath as String
276      * @return SchemaPath from given String
277      */
278     public static SchemaPath parseXPathString(String xpathString) {
279         boolean absolute = xpathString.startsWith("/");
280         String[] splittedPath = xpathString.split("/");
281         List<QName> path = new ArrayList<QName>();
282         QName name;
283         for (String pathElement : splittedPath) {
284             if (pathElement.length() > 0) {
285                 String[] splittedElement = pathElement.split(":");
286                 if (splittedElement.length == 1) {
287                     name = new QName(null, null, null, splittedElement[0]);
288                 } else {
289                     name = new QName(null, null, splittedElement[0], splittedElement[1]);
290                 }
291                 path.add(name);
292             }
293         }
294         return new SchemaPath(path, absolute);
295     }
296
297     /**
298      * Add all augment's child nodes to given target.
299      *
300      * @param augment
301      *            builder of augment statement
302      * @param target
303      *            augmentation target node
304      */
305     public static void fillAugmentTarget(AugmentationSchemaBuilder augment, Builder target) {
306         if (target instanceof DataNodeContainerBuilder) {
307             fillAugmentTarget(augment, (DataNodeContainerBuilder) target);
308         } else if (target instanceof ChoiceBuilder) {
309             fillAugmentTarget(augment, (ChoiceBuilder) target);
310         } else {
311             throw new YangParseException(
312                     augment.getModuleName(),
313                     augment.getLine(),
314                     "Error in augment parsing: The target node MUST be either a container, list, choice, case, input, output, or notification node.");
315         }
316     }
317
318     /**
319      * Add all augment's child nodes to given target.
320      *
321      * @param augment
322      *            builder of augment statement
323      * @param target
324      *            augmentation target node
325      */
326     private static void fillAugmentTarget(AugmentationSchemaBuilder augment, DataNodeContainerBuilder target) {
327         for (DataSchemaNodeBuilder child : augment.getChildNodeBuilders()) {
328             DataSchemaNodeBuilder childCopy = CopyUtils.copy(child, target, false);
329             if (augment.getParent() instanceof UsesNodeBuilder) {
330                 setNodeAddedByUses(childCopy);
331             }
332             setNodeAugmenting(childCopy);
333             try {
334                 target.addChildNode(childCopy);
335             } catch (YangParseException e) {
336
337                 // more descriptive message
338                 throw new YangParseException(augment.getModuleName(), augment.getLine(),
339                         "Failed to perform augmentation: " + e.getMessage());
340             }
341         }
342     }
343
344     /**
345      * Add all augment's child nodes to given target.
346      *
347      * @param augment
348      *            builder of augment statement
349      * @param target
350      *            augmentation target choice node
351      */
352     private static void fillAugmentTarget(AugmentationSchemaBuilder augment, ChoiceBuilder target) {
353         for (DataSchemaNodeBuilder builder : augment.getChildNodeBuilders()) {
354             DataSchemaNodeBuilder childCopy = CopyUtils.copy(builder, target, false);
355             if (augment.getParent() instanceof UsesNodeBuilder) {
356                 setNodeAddedByUses(childCopy);
357             }
358             setNodeAugmenting(childCopy);
359             target.addCase(childCopy);
360         }
361         for (UsesNodeBuilder usesNode : augment.getUsesNodeBuilders()) {
362             if (usesNode != null) {
363                 throw new YangParseException(augment.getModuleName(), augment.getLine(),
364                         "Error in augment parsing: cannot augment choice with nodes from grouping");
365             }
366         }
367     }
368
369     /**
370      * Set augmenting flag to true for node and all its child nodes.
371      *
372      * @param node
373      */
374     private static void setNodeAugmenting(DataSchemaNodeBuilder node) {
375         node.setAugmenting(true);
376         if (node instanceof DataNodeContainerBuilder) {
377             DataNodeContainerBuilder dataNodeChild = (DataNodeContainerBuilder) node;
378             for (DataSchemaNodeBuilder inner : dataNodeChild.getChildNodeBuilders()) {
379                 setNodeAugmenting(inner);
380             }
381         } else if (node instanceof ChoiceBuilder) {
382             ChoiceBuilder choiceChild = (ChoiceBuilder) node;
383             for (ChoiceCaseBuilder inner : choiceChild.getCases()) {
384                 setNodeAugmenting(inner);
385             }
386         }
387     }
388
389     /**
390      * Set addedByUses flag to true for node and all its child nodes.
391      *
392      * @param node
393      */
394     public static void setNodeAddedByUses(GroupingMember node) {
395         node.setAddedByUses(true);
396         if (node instanceof DataNodeContainerBuilder) {
397             DataNodeContainerBuilder dataNodeChild = (DataNodeContainerBuilder) node;
398             for (DataSchemaNodeBuilder inner : dataNodeChild.getChildNodeBuilders()) {
399                 setNodeAddedByUses(inner);
400             }
401         } else if (node instanceof ChoiceBuilder) {
402             ChoiceBuilder choiceChild = (ChoiceBuilder) node;
403             for (ChoiceCaseBuilder inner : choiceChild.getCases()) {
404                 setNodeAddedByUses(inner);
405             }
406         }
407     }
408
409     /**
410      * Set config flag to new value.
411      *
412      * @param node
413      *            node to update
414      * @param config
415      *            new config value
416      */
417     public static void setNodeConfig(DataSchemaNodeBuilder node, Boolean config) {
418         if (node instanceof ContainerSchemaNodeBuilder || node instanceof LeafSchemaNodeBuilder
419                 || node instanceof LeafListSchemaNodeBuilder || node instanceof ListSchemaNodeBuilder
420                 || node instanceof ChoiceBuilder || node instanceof AnyXmlBuilder) {
421             node.setConfiguration(config);
422         }
423         if (node instanceof DataNodeContainerBuilder) {
424             DataNodeContainerBuilder dataNodeChild = (DataNodeContainerBuilder) node;
425             for (DataSchemaNodeBuilder inner : dataNodeChild.getChildNodeBuilders()) {
426                 setNodeConfig(inner, config);
427             }
428         } else if (node instanceof ChoiceBuilder) {
429             ChoiceBuilder choiceChild = (ChoiceBuilder) node;
430             for (ChoiceCaseBuilder inner : choiceChild.getCases()) {
431                 setNodeConfig(inner, config);
432             }
433         }
434     }
435
436     public static DataSchemaNodeBuilder findSchemaNode(List<QName> path, SchemaNodeBuilder parentNode) {
437         DataSchemaNodeBuilder node = null;
438         SchemaNodeBuilder parent = parentNode;
439         int i = 0;
440         while (i < path.size()) {
441             String name = path.get(i).getLocalName();
442             if (parent instanceof DataNodeContainerBuilder) {
443                 node = ((DataNodeContainerBuilder) parent).getDataChildByName(name);
444             } else if (parent instanceof ChoiceBuilder) {
445                 node = ((ChoiceBuilder) parent).getCaseNodeByName(name);
446             } else if (parent instanceof RpcDefinitionBuilder) {
447                 if ("input".equals(name)) {
448                     node = ((RpcDefinitionBuilder) parent).getInput();
449                 } else if ("output".equals(name)) {
450                     node = ((RpcDefinitionBuilder) parent).getOutput();
451                 } else {
452                     return null;
453                 }
454             } else {
455                 return null;
456             }
457
458             if (i < path.size() - 1) {
459                 parent = node;
460             }
461             i = i + 1;
462         }
463
464         return node;
465     }
466
467     public static SchemaNodeBuilder findSchemaNodeInModule(List<QName> pathToNode, ModuleBuilder module) {
468         List<QName> path = new ArrayList<>(pathToNode);
469         QName first = path.remove(0);
470
471         SchemaNodeBuilder node = module.getDataChildByName(first.getLocalName());
472         if (node == null) {
473             Set<NotificationBuilder> notifications = module.getAddedNotifications();
474             for (NotificationBuilder notification : notifications) {
475                 if (notification.getQName().getLocalName().equals(first.getLocalName())) {
476                     node = notification;
477                 }
478             }
479         }
480         if (node == null) {
481             Set<RpcDefinitionBuilder> rpcs = module.getAddedRpcs();
482             for (RpcDefinitionBuilder rpc : rpcs) {
483                 if (rpc.getQName().getLocalName().equals(first.getLocalName())) {
484                     node = rpc;
485                 }
486             }
487         }
488         if (node == null) {
489             return null;
490         }
491
492         if (!path.isEmpty()) {
493             node = findSchemaNode(path, node);
494         }
495
496         return node;
497     }
498
499     /**
500      * Find augment target node and perform augmentation.
501      *
502      * @param augment
503      * @param firstNodeParent
504      *            parent of first node in path
505      * @param path
506      *            path to augment target
507      * @return true if augmentation process succeed, false otherwise
508      */
509     public static boolean processAugmentation(AugmentationSchemaBuilder augment, ModuleBuilder firstNodeParent) {
510         List<QName> path = augment.getTargetPath().getPath();
511         Builder targetNode = findSchemaNodeInModule(path, firstNodeParent);
512         if (targetNode == null) {
513             return false;
514         }
515
516         fillAugmentTarget(augment, targetNode);
517         ((AugmentationTargetBuilder) targetNode).addAugmentation(augment);
518         augment.setResolved(true);
519         return true;
520     }
521
522     public static IdentitySchemaNodeBuilder findBaseIdentity(Map<String, TreeMap<Date, ModuleBuilder>> modules,
523             ModuleBuilder module, String baseString, int line) {
524         IdentitySchemaNodeBuilder result = null;
525         if (baseString.contains(":")) {
526             String[] splittedBase = baseString.split(":");
527             if (splittedBase.length > 2) {
528                 throw new YangParseException(module.getName(), line, "Failed to parse identityref base: " + baseString);
529             }
530             String prefix = splittedBase[0];
531             String name = splittedBase[1];
532             ModuleBuilder dependentModule = findModuleFromBuilders(modules, module, prefix, line);
533             if (dependentModule != null) {
534                 result = findIdentity(dependentModule.getAddedIdentities(), name);
535             }
536         } else {
537             result = findIdentity(module.getAddedIdentities(), baseString);
538         }
539         return result;
540     }
541
542     public static IdentitySchemaNodeBuilder findIdentity(Set<IdentitySchemaNodeBuilder> identities, String name) {
543         for (IdentitySchemaNodeBuilder identity : identities) {
544             if (identity.getQName().getLocalName().equals(name)) {
545                 return identity;
546             }
547         }
548         return null;
549     }
550
551     /**
552      * Get module in which this node is defined.
553      *
554      * @param node
555      * @return builder of module where this node is defined
556      */
557     public static ModuleBuilder getParentModule(Builder node) {
558         if (node instanceof ModuleBuilder) {
559             return (ModuleBuilder) node;
560         }
561         Builder parent = node.getParent();
562         while (!(parent instanceof ModuleBuilder)) {
563             parent = parent.getParent();
564         }
565         Preconditions.checkState(parent instanceof ModuleBuilder);
566         ModuleBuilder parentModule = (ModuleBuilder) parent;
567         if (parentModule.isSubmodule()) {
568             parentModule = parentModule.getParent();
569         }
570         return parentModule;
571     }
572
573     public static Set<DataSchemaNodeBuilder> wrapChildNodes(String moduleName, int line, Set<DataSchemaNode> nodes,
574             SchemaPath parentPath, URI ns, Date rev, String pref) {
575         Set<DataSchemaNodeBuilder> result = new HashSet<>();
576
577         for (DataSchemaNode node : nodes) {
578             QName qname = new QName(ns, rev, pref, node.getQName().getLocalName());
579             DataSchemaNodeBuilder wrapped = wrapChildNode(moduleName, line, node, parentPath, qname);
580             result.add(wrapped);
581         }
582         return result;
583     }
584
585     public static DataSchemaNodeBuilder wrapChildNode(String moduleName, int line, DataSchemaNode node,
586             SchemaPath parentPath, QName qname) {
587         List<QName> path = new ArrayList<>(parentPath.getPath());
588         path.add(qname);
589         SchemaPath schemaPath = new SchemaPath(path, parentPath.isAbsolute());
590
591         if (node instanceof AnyXmlSchemaNode) {
592             return new AnyXmlBuilder(moduleName, line, qname, schemaPath, ((AnyXmlSchemaNode) node));
593         } else if (node instanceof ChoiceNode) {
594             return new ChoiceBuilder(moduleName, line, qname, schemaPath, ((ChoiceNode) node));
595         } else if (node instanceof ContainerSchemaNode) {
596             return new ContainerSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((ContainerSchemaNode) node));
597         } else if (node instanceof LeafSchemaNode) {
598             return new LeafSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((LeafSchemaNode) node));
599         } else if (node instanceof LeafListSchemaNode) {
600             return new LeafListSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((LeafListSchemaNode) node));
601         } else if (node instanceof ListSchemaNode) {
602             return new ListSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((ListSchemaNode) node));
603         } else if (node instanceof ChoiceCaseNode) {
604             return new ChoiceCaseBuilder(moduleName, line, qname, schemaPath, ((ChoiceCaseNode) node));
605         } else {
606             throw new YangParseException(moduleName, line, "Failed to copy node: Unknown type of DataSchemaNode: "
607                     + node);
608         }
609     }
610
611     public static Set<GroupingBuilder> wrapGroupings(String moduleName, int line, Set<GroupingDefinition> nodes,
612             SchemaPath parentPath, URI ns, Date rev, String pref) {
613         Set<GroupingBuilder> result = new HashSet<>();
614         for (GroupingDefinition node : nodes) {
615             QName qname = new QName(ns, rev, pref, node.getQName().getLocalName());
616             List<QName> path = new ArrayList<>(parentPath.getPath());
617             path.add(qname);
618             SchemaPath schemaPath = new SchemaPath(path, parentPath.isAbsolute());
619             result.add(new GroupingBuilderImpl(moduleName, line, qname, schemaPath, node));
620         }
621         return result;
622     }
623
624     public static Set<TypeDefinitionBuilder> wrapTypedefs(String moduleName, int line, DataNodeContainer dataNode,
625             SchemaPath parentPath, URI ns, Date rev, String pref) {
626         Set<TypeDefinition<?>> nodes = dataNode.getTypeDefinitions();
627         Set<TypeDefinitionBuilder> result = new HashSet<>();
628         for (TypeDefinition<?> node : nodes) {
629             QName qname = new QName(ns, rev, pref, node.getQName().getLocalName());
630             List<QName> path = new ArrayList<>(parentPath.getPath());
631             path.add(qname);
632             SchemaPath schemaPath = new SchemaPath(path, parentPath.isAbsolute());
633             result.add(new TypeDefinitionBuilderImpl(moduleName, line, qname, schemaPath, ((ExtendedType) node)));
634         }
635         return result;
636     }
637
638     public static List<UnknownSchemaNodeBuilder> wrapUnknownNodes(String moduleName, int line,
639             List<UnknownSchemaNode> nodes, SchemaPath parentPath, URI ns, Date rev, String pref) {
640         List<UnknownSchemaNodeBuilder> result = new ArrayList<>();
641         for (UnknownSchemaNode node : nodes) {
642             QName qname = new QName(ns, rev, pref, node.getQName().getLocalName());
643             List<QName> path = new ArrayList<>(parentPath.getPath());
644             path.add(qname);
645             SchemaPath schemaPath = new SchemaPath(path, parentPath.isAbsolute());
646             result.add(new UnknownSchemaNodeBuilder(moduleName, line, qname, schemaPath, node));
647         }
648         return result;
649     }
650
651 }