d6e557d78fdf51baba14bfdd32bb34a62307e8fc
[yangtools.git] / yang / yang-model-export / src / main / java / org / opendaylight / yangtools / yang / model / export / SchemaContextEmitter.java
1 /*
2  * Copyright (c) 2015 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.model.export;
9
10 import com.google.common.annotations.Beta;
11 import com.google.common.base.Preconditions;
12 import com.google.common.base.Predicates;
13 import com.google.common.base.Strings;
14 import com.google.common.collect.Collections2;
15 import com.google.common.collect.Range;
16 import com.google.common.collect.RangeSet;
17 import com.google.common.primitives.UnsignedInteger;
18 import java.net.URI;
19 import java.util.Collection;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Map.Entry;
24 import java.util.Objects;
25 import java.util.Optional;
26 import java.util.Set;
27 import javax.annotation.Nonnull;
28 import javax.annotation.Nullable;
29 import javax.annotation.concurrent.NotThreadSafe;
30 import org.opendaylight.yangtools.yang.common.QName;
31 import org.opendaylight.yangtools.yang.common.Revision;
32 import org.opendaylight.yangtools.yang.common.YangVersion;
33 import org.opendaylight.yangtools.yang.model.api.ActionDefinition;
34 import org.opendaylight.yangtools.yang.model.api.AnyDataSchemaNode;
35 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
36 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
37 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
38 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
39 import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition;
40 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
41 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
42 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
43 import org.opendaylight.yangtools.yang.model.api.Deviation;
44 import org.opendaylight.yangtools.yang.model.api.DocumentedNode;
45 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
46 import org.opendaylight.yangtools.yang.model.api.FeatureDefinition;
47 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
48 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
49 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
50 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
51 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
52 import org.opendaylight.yangtools.yang.model.api.Module;
53 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
54 import org.opendaylight.yangtools.yang.model.api.MustDefinition;
55 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
56 import org.opendaylight.yangtools.yang.model.api.OperationDefinition;
57 import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
58 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
59 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
60 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
61 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
62 import org.opendaylight.yangtools.yang.model.api.Status;
63 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
64 import org.opendaylight.yangtools.yang.model.api.UniqueConstraint;
65 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
66 import org.opendaylight.yangtools.yang.model.api.UsesNode;
67 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
68 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
69 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
70 import org.opendaylight.yangtools.yang.model.api.meta.StatementSource;
71 import org.opendaylight.yangtools.yang.model.api.stmt.ActionStatement;
72 import org.opendaylight.yangtools.yang.model.api.stmt.AnydataStatement;
73 import org.opendaylight.yangtools.yang.model.api.stmt.AnyxmlStatement;
74 import org.opendaylight.yangtools.yang.model.api.stmt.ArgumentStatement;
75 import org.opendaylight.yangtools.yang.model.api.stmt.AugmentStatement;
76 import org.opendaylight.yangtools.yang.model.api.stmt.BaseStatement;
77 import org.opendaylight.yangtools.yang.model.api.stmt.BelongsToStatement;
78 import org.opendaylight.yangtools.yang.model.api.stmt.BitStatement;
79 import org.opendaylight.yangtools.yang.model.api.stmt.BodyGroup;
80 import org.opendaylight.yangtools.yang.model.api.stmt.CaseStatement;
81 import org.opendaylight.yangtools.yang.model.api.stmt.ChoiceStatement;
82 import org.opendaylight.yangtools.yang.model.api.stmt.ConfigStatement;
83 import org.opendaylight.yangtools.yang.model.api.stmt.ContactStatement;
84 import org.opendaylight.yangtools.yang.model.api.stmt.ContainerStatement;
85 import org.opendaylight.yangtools.yang.model.api.stmt.DataDefinitionContainer;
86 import org.opendaylight.yangtools.yang.model.api.stmt.DataDefinitionStatement;
87 import org.opendaylight.yangtools.yang.model.api.stmt.DefaultStatement;
88 import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionStatement;
89 import org.opendaylight.yangtools.yang.model.api.stmt.DeviateStatement;
90 import org.opendaylight.yangtools.yang.model.api.stmt.DeviationStatement;
91 import org.opendaylight.yangtools.yang.model.api.stmt.DocumentationGroup;
92 import org.opendaylight.yangtools.yang.model.api.stmt.DocumentedConstraintGroup;
93 import org.opendaylight.yangtools.yang.model.api.stmt.EnumStatement;
94 import org.opendaylight.yangtools.yang.model.api.stmt.ErrorAppTagStatement;
95 import org.opendaylight.yangtools.yang.model.api.stmt.ErrorMessageStatement;
96 import org.opendaylight.yangtools.yang.model.api.stmt.FeatureStatement;
97 import org.opendaylight.yangtools.yang.model.api.stmt.FractionDigitsStatement;
98 import org.opendaylight.yangtools.yang.model.api.stmt.GroupingStatement;
99 import org.opendaylight.yangtools.yang.model.api.stmt.IdentityStatement;
100 import org.opendaylight.yangtools.yang.model.api.stmt.IfFeatureStatement;
101 import org.opendaylight.yangtools.yang.model.api.stmt.ImportStatement;
102 import org.opendaylight.yangtools.yang.model.api.stmt.IncludeStatement;
103 import org.opendaylight.yangtools.yang.model.api.stmt.InputStatement;
104 import org.opendaylight.yangtools.yang.model.api.stmt.KeyStatement;
105 import org.opendaylight.yangtools.yang.model.api.stmt.LeafListStatement;
106 import org.opendaylight.yangtools.yang.model.api.stmt.LeafStatement;
107 import org.opendaylight.yangtools.yang.model.api.stmt.LengthStatement;
108 import org.opendaylight.yangtools.yang.model.api.stmt.LinkageGroup;
109 import org.opendaylight.yangtools.yang.model.api.stmt.ListStatement;
110 import org.opendaylight.yangtools.yang.model.api.stmt.MandatoryStatement;
111 import org.opendaylight.yangtools.yang.model.api.stmt.MaxElementsStatement;
112 import org.opendaylight.yangtools.yang.model.api.stmt.MetaGroup;
113 import org.opendaylight.yangtools.yang.model.api.stmt.MinElementsStatement;
114 import org.opendaylight.yangtools.yang.model.api.stmt.ModifierStatement;
115 import org.opendaylight.yangtools.yang.model.api.stmt.ModuleStatement;
116 import org.opendaylight.yangtools.yang.model.api.stmt.MustStatement;
117 import org.opendaylight.yangtools.yang.model.api.stmt.NamespaceStatement;
118 import org.opendaylight.yangtools.yang.model.api.stmt.NotificationStatement;
119 import org.opendaylight.yangtools.yang.model.api.stmt.OperationGroup;
120 import org.opendaylight.yangtools.yang.model.api.stmt.OrderedByStatement;
121 import org.opendaylight.yangtools.yang.model.api.stmt.OrganizationStatement;
122 import org.opendaylight.yangtools.yang.model.api.stmt.OutputStatement;
123 import org.opendaylight.yangtools.yang.model.api.stmt.PathStatement;
124 import org.opendaylight.yangtools.yang.model.api.stmt.PatternStatement;
125 import org.opendaylight.yangtools.yang.model.api.stmt.PositionStatement;
126 import org.opendaylight.yangtools.yang.model.api.stmt.PrefixStatement;
127 import org.opendaylight.yangtools.yang.model.api.stmt.PresenceStatement;
128 import org.opendaylight.yangtools.yang.model.api.stmt.RangeStatement;
129 import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceStatement;
130 import org.opendaylight.yangtools.yang.model.api.stmt.RefineStatement;
131 import org.opendaylight.yangtools.yang.model.api.stmt.RequireInstanceStatement;
132 import org.opendaylight.yangtools.yang.model.api.stmt.RevisionDateStatement;
133 import org.opendaylight.yangtools.yang.model.api.stmt.RevisionGroup;
134 import org.opendaylight.yangtools.yang.model.api.stmt.RevisionStatement;
135 import org.opendaylight.yangtools.yang.model.api.stmt.RpcStatement;
136 import org.opendaylight.yangtools.yang.model.api.stmt.StatusStatement;
137 import org.opendaylight.yangtools.yang.model.api.stmt.SubmoduleStatement;
138 import org.opendaylight.yangtools.yang.model.api.stmt.TypeStatement;
139 import org.opendaylight.yangtools.yang.model.api.stmt.TypedefStatement;
140 import org.opendaylight.yangtools.yang.model.api.stmt.UniqueStatement;
141 import org.opendaylight.yangtools.yang.model.api.stmt.UnitsStatement;
142 import org.opendaylight.yangtools.yang.model.api.stmt.UnknownStatement;
143 import org.opendaylight.yangtools.yang.model.api.stmt.UsesStatement;
144 import org.opendaylight.yangtools.yang.model.api.stmt.ValueStatement;
145 import org.opendaylight.yangtools.yang.model.api.stmt.WhenStatement;
146 import org.opendaylight.yangtools.yang.model.api.stmt.YangVersionStatement;
147 import org.opendaylight.yangtools.yang.model.api.stmt.YinElementStatement;
148 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
149 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
150 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit;
151 import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
152 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
153 import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
154 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
155 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair;
156 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
157 import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
158 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
159 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
160 import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
161 import org.opendaylight.yangtools.yang.model.api.type.ModifierKind;
162 import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
163 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
164 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
165 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
166 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
167 import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils;
168
169 @Beta
170 @NotThreadSafe
171 abstract class SchemaContextEmitter {
172
173     final YangModuleWriter writer;
174     final boolean emitInstantiated;
175     final boolean emitUses;
176     final Map<QName, StatementDefinition> extensions;
177     final YangVersion yangVersion;
178
179     SchemaContextEmitter(final YangModuleWriter writer, final Map<QName, StatementDefinition> extensions,
180             final YangVersion yangVersion) {
181         this(writer, extensions, yangVersion, false, true);
182     }
183
184     SchemaContextEmitter(final YangModuleWriter writer, final Map<QName, StatementDefinition> extensions,
185             final YangVersion yangVersion, final boolean emitInstantiated, final boolean emitUses) {
186         this.writer = Preconditions.checkNotNull(writer);
187         this.emitInstantiated = emitInstantiated;
188         this.emitUses = emitUses;
189         this.extensions = Preconditions.checkNotNull(extensions);
190         this.yangVersion = yangVersion;
191     }
192
193     static void writeToStatementWriter(final Module module, final SchemaContext ctx,
194             final StatementTextWriter statementWriter, final boolean emitInstantiated) {
195         final YangModuleWriter yangSchemaWriter = SchemaToStatementWriterAdaptor.from(statementWriter);
196         final Map<QName, StatementDefinition> extensions = ExtensionStatement.mapFrom(ctx.getExtensions());
197         if (module instanceof EffectiveStatement && !emitInstantiated) {
198             /*
199              * if module is an effective statement and we don't want to export
200              * instantiated statements (e.g. statements added by uses or
201              * augment) we can get declared form i.e. ModuleStatement and then
202              * use DeclaredSchemaContextEmitter
203              */
204             new DeclaredSchemaContextEmitter(yangSchemaWriter, extensions, module.getYangVersion())
205             .emitModule(((EffectiveStatement<?, ?>) module).getDeclared());
206         } else {
207             /*
208              * if we don't have access to declared form of supplied module or we
209              * want to emit also instantiated statements (e.g. statements added
210              * by uses or augment), we use EffectiveSchemaContextEmitter.
211              */
212             new EffectiveSchemaContextEmitter(yangSchemaWriter, extensions, module.getYangVersion(), emitInstantiated)
213             .emitModule(module);
214         }
215     }
216
217     // FIXME: Probably should be moved to utils bundle.
218     static <T> boolean isPrefix(final Iterable<T> prefix, final Iterable<T> other) {
219         final Iterator<T> prefixIt = prefix.iterator();
220         final Iterator<T> otherIt = other.iterator();
221         while (prefixIt.hasNext()) {
222             if (!otherIt.hasNext()) {
223                 return false;
224             }
225             if (!Objects.deepEquals(prefixIt.next(), otherIt.next())) {
226                 return false;
227             }
228         }
229         return true;
230     }
231
232     static class DeclaredSchemaContextEmitter extends SchemaContextEmitter {
233
234         DeclaredSchemaContextEmitter(final YangModuleWriter writer, final Map<QName, StatementDefinition> extensions,
235                 final YangVersion yangVersion) {
236             super(writer, extensions, yangVersion);
237         }
238
239         void emitModule(final DeclaredStatement<?> declaredRootStmt) {
240             if (declaredRootStmt instanceof ModuleStatement) {
241                 emitModule((ModuleStatement) declaredRootStmt);
242             } else if (declaredRootStmt instanceof SubmoduleStatement) {
243                 emitSubmodule((SubmoduleStatement) declaredRootStmt);
244             } else {
245                 throw new UnsupportedOperationException(
246                         String.format("Yin export: unsupported declared statement %s", declaredRootStmt));
247             }
248         }
249
250         private void emitModule(final ModuleStatement module) {
251             super.writer.startModuleNode(module.rawArgument());
252             emitModuleHeader(module);
253             emitLinkageNodes(module);
254             emitMetaNodes(module);
255             emitRevisionNodes(module);
256             emitBodyNodes(module);
257             emitUnknownStatementNodes(module);
258             super.writer.endNode();
259         }
260
261         private void emitModuleHeader(final ModuleStatement input) {
262             emitYangVersionNode(input.getYangVersion());
263             emitNamespace(input.getNamespace());
264             emitPrefixNode(input.getPrefix());
265         }
266
267         private void emitSubmodule(final SubmoduleStatement submodule) {
268             super.writer.startSubmoduleNode(submodule.rawArgument());
269             emitSubmoduleHeaderNodes(submodule);
270             emitLinkageNodes(submodule);
271             emitMetaNodes(submodule);
272             emitRevisionNodes(submodule);
273             emitBodyNodes(submodule);
274             emitUnknownStatementNodes(submodule);
275             super.writer.endNode();
276         }
277
278         private void emitSubmoduleHeaderNodes(final SubmoduleStatement input) {
279             emitYangVersionNode(input.getYangVersion());
280             emitBelongsTo(input.getBelongsTo());
281         }
282
283         private void emitBelongsTo(final BelongsToStatement belongsTo) {
284             super.writer.startBelongsToNode(belongsTo.rawArgument());
285             emitPrefixNode(belongsTo.getPrefix());
286             super.writer.endNode();
287         }
288
289         private void emitMetaNodes(final MetaGroup input) {
290             emitOrganizationNode(input.getOrganization());
291             emitContact(input.getContact());
292             emitDescriptionNode(input.getDescription());
293             emitReferenceNode(input.getReference());
294         }
295
296         private void emitLinkageNodes(final LinkageGroup input) {
297             for (final ImportStatement importNode : input.getImports()) {
298                 emitImport(importNode);
299             }
300             for (final IncludeStatement importNode : input.getIncludes()) {
301                 emitInclude(importNode);
302             }
303         }
304
305         private void emitRevisionNodes(final RevisionGroup input) {
306             emitRevisions(input.getRevisions());
307         }
308
309         private void emitBodyNodes(final BodyGroup input) {
310
311             for (final org.opendaylight.yangtools.yang.model.api.stmt.ExtensionStatement extension : input
312                     .getExtensions()) {
313                 emitExtension(extension);
314             }
315             for (final FeatureStatement definition : input.getFeatures()) {
316                 emitFeature(definition);
317             }
318             for (final IdentityStatement identity : input.getIdentities()) {
319                 emitIdentity(identity);
320             }
321             for (final DeviationStatement deviation : input.getDeviations()) {
322                 emitDeviation(deviation);
323             }
324
325             emitDataNodeContainer(input);
326
327             for (final AugmentStatement augmentation : input.getAugments()) {
328                 emitAugment(augmentation);
329             }
330             for (final RpcStatement rpc : input.getRpcs()) {
331                 emitRpc(rpc);
332             }
333
334             emitNotifications(input.getNotifications());
335         }
336
337         private void emitDataNodeContainer(final DataDefinitionContainer input) {
338             for (final DataDefinitionStatement child : input.getDataDefinitions()) {
339                 emitDataSchemaNode(child);
340             }
341         }
342
343         private void emitDataNodeContainer(final DataDefinitionContainer.WithReusableDefinitions input) {
344             for (final TypedefStatement typedef : input.getTypedefs()) {
345                 emitTypedefNode(typedef);
346             }
347             for (final GroupingStatement grouping : input.getGroupings()) {
348                 emitGrouping(grouping);
349             }
350             for (final DataDefinitionStatement child : input.getDataDefinitions()) {
351                 emitDataSchemaNode(child);
352             }
353         }
354
355         private void emitDataSchemaNode(final DataDefinitionStatement child) {
356             if (child instanceof ContainerStatement) {
357                 emitContainer((ContainerStatement) child);
358             } else if (child instanceof LeafStatement) {
359                 emitLeaf((LeafStatement) child);
360             } else if (child instanceof LeafListStatement) {
361                 emitLeafList((LeafListStatement) child);
362             } else if (child instanceof ListStatement) {
363                 emitList((ListStatement) child);
364             } else if (child instanceof ChoiceStatement) {
365                 emitChoice((ChoiceStatement) child);
366             } else if (child instanceof AnyxmlStatement) {
367                 emitAnyxml((AnyxmlStatement) child);
368             } else if (child instanceof AnydataStatement) {
369                 emitAnydata((AnydataStatement) child);
370             } else if (child instanceof UsesStatement) {
371                 emitUsesNode((UsesStatement) child);
372             } else {
373                 throw new UnsupportedOperationException("Not supported DataStatement type " + child.getClass());
374             }
375         }
376
377         private void emitYangVersionNode(@Nullable final YangVersionStatement yangVersionStatement) {
378             if (yangVersionStatement != null) {
379                 super.writer.startYangVersionNode(yangVersionStatement.rawArgument());
380                 super.writer.endNode();
381             }
382         }
383
384         private void emitImport(final ImportStatement importNode) {
385             super.writer.startImportNode(importNode.rawArgument());
386             emitDocumentedNode(importNode);
387             emitPrefixNode(importNode.getPrefix());
388             emitRevisionDateNode(importNode.getRevisionDate());
389             super.writer.endNode();
390         }
391
392         private void emitInclude(final IncludeStatement include) {
393             super.writer.startIncludeNode(include.rawArgument());
394             emitDocumentedNode(include);
395             emitRevisionDateNode(include.getRevisionDate());
396             super.writer.endNode();
397         }
398
399         private void emitNamespace(final NamespaceStatement namespaceStatement) {
400             Preconditions.checkNotNull(namespaceStatement, "Namespace must not be null");
401             super.writer.startNamespaceNode(namespaceStatement.getUri());
402             super.writer.endNode();
403         }
404
405         private void emitPrefixNode(final PrefixStatement prefixStatement) {
406             Preconditions.checkNotNull(prefixStatement, "Prefix must not be null");
407             super.writer.startPrefixNode(prefixStatement.rawArgument());
408             super.writer.endNode();
409         }
410
411         private void emitOrganizationNode(@Nullable final OrganizationStatement organizationStatement) {
412             if (organizationStatement != null) {
413                 super.writer.startOrganizationNode(organizationStatement.rawArgument());
414                 super.writer.endNode();
415             }
416         }
417
418         private void emitContact(@Nullable final ContactStatement contactStatement) {
419             if (contactStatement != null) {
420                 super.writer.startContactNode(contactStatement.rawArgument());
421                 super.writer.endNode();
422             }
423         }
424
425         private void emitDescriptionNode(@Nullable final DescriptionStatement descriptionStatement) {
426             if (descriptionStatement != null) {
427                 super.writer.startDescriptionNode(descriptionStatement.rawArgument());
428                 super.writer.endNode();
429             }
430         }
431
432         private void emitReferenceNode(@Nullable final ReferenceStatement referenceStatement) {
433             if (referenceStatement != null) {
434                 super.writer.startReferenceNode(referenceStatement.rawArgument());
435                 super.writer.endNode();
436             }
437         }
438
439         private void emitUnitsNode(@Nullable final UnitsStatement unitsStatement) {
440             if (unitsStatement != null) {
441                 super.writer.startUnitsNode(unitsStatement.rawArgument());
442                 super.writer.endNode();
443             }
444         }
445
446         private void emitRevisions(final Collection<? extends RevisionStatement> revisions) {
447             for (final RevisionStatement revisionStatement : revisions) {
448                 emitRevision(revisionStatement);
449             }
450         }
451
452         private void emitRevision(final RevisionStatement revision) {
453             super.writer.startRevisionNode(revision.rawArgument());
454             emitDocumentedNode(revision);
455             super.writer.endNode();
456         }
457
458         private void emitRevisionDateNode(@Nullable final RevisionDateStatement revisionDateStatement) {
459             if (revisionDateStatement != null) {
460                 super.writer.startRevisionDateNode(revisionDateStatement.rawArgument());
461                 super.writer.endNode();
462             }
463         }
464
465         private void emitExtension(final org.opendaylight.yangtools.yang.model.api.stmt.ExtensionStatement extension) {
466             super.writer.startExtensionNode(extension.rawArgument());
467             emitArgument(extension.getArgument());
468             emitDocumentedNodeWithStatus(extension);
469             emitUnknownStatementNodes(extension);
470             super.writer.endNode();
471         }
472
473         private void emitArgument(@Nullable final ArgumentStatement input) {
474             if (input != null) {
475                 super.writer.startArgumentNode(input.rawArgument());
476                 emitYinElement(input.getYinElement());
477                 super.writer.endNode();
478             }
479         }
480
481         private void emitYinElement(@Nullable final YinElementStatement yinElementStatement) {
482             if (yinElementStatement != null) {
483                 super.writer.startYinElementNode(yinElementStatement.rawArgument());
484                 super.writer.endNode();
485             }
486         }
487
488         private void emitIdentity(final IdentityStatement identity) {
489             super.writer.startIdentityNode(identity.rawArgument());
490             emitBaseIdentities(identity.getBases());
491             emitStatusNode(identity.getStatus());
492             emitDescriptionNode(identity.getDescription());
493             emitReferenceNode(identity.getReference());
494             super.writer.endNode();
495         }
496
497         private void emitBaseIdentities(final Collection<? extends BaseStatement> collection) {
498             for (final BaseStatement baseStmt : collection) {
499                 emitBase(baseStmt);
500             }
501         }
502
503         private void emitBase(final BaseStatement baseStmt) {
504             super.writer.startBaseNode(baseStmt.rawArgument());
505             super.writer.endNode();
506         }
507
508         private void emitFeature(final FeatureStatement feature) {
509             super.writer.startFeatureNode(feature.rawArgument());
510             emitIfFeatures(feature.getIfFeatures());
511             emitDocumentedNodeWithStatus(feature);
512             super.writer.endNode();
513         }
514
515         private void emitIfFeatures(final Collection<? extends IfFeatureStatement> ifFeatures) {
516             for (final IfFeatureStatement ifFeatureStatement : ifFeatures) {
517                 emitIfFeature(ifFeatureStatement);
518             }
519         }
520
521         private void emitIfFeature(final IfFeatureStatement ifFeature) {
522             super.writer.startIfFeatureNode(ifFeature.rawArgument());
523             super.writer.endNode();
524         }
525
526         private void emitTypedefNode(final TypedefStatement typedef) {
527             super.writer.startTypedefNode(typedef.rawArgument());
528             emitType(typedef.getType());
529             emitUnitsNode(typedef.getUnits());
530             emitDefaultNode(typedef.getDefault());
531             emitStatusNode(typedef.getStatus());
532             emitDescriptionNode(typedef.getDescription());
533             emitReferenceNode(typedef.getReference());
534             emitUnknownStatementNodes(typedef);
535             super.writer.endNode();
536         }
537
538         private void emitType(final TypeStatement typeStatement) {
539             super.writer.startTypeNode(typeStatement.rawArgument());
540             for (final DeclaredStatement<?> typeSubstmt : typeStatement.declaredSubstatements()) {
541                 if (typeSubstmt instanceof RangeStatement) {
542                     emitRange((RangeStatement) typeSubstmt);
543                 } else if (typeSubstmt instanceof LengthStatement) {
544                     emitLength((LengthStatement) typeSubstmt);
545                 } else if (typeSubstmt instanceof PatternStatement) {
546                     emitPattern((PatternStatement) typeSubstmt);
547                 } else if (typeSubstmt instanceof FractionDigitsStatement) {
548                     emitFractionDigits((FractionDigitsStatement) typeSubstmt);
549                 } else if (typeSubstmt instanceof EnumStatement) {
550                     emitEnum((EnumStatement) typeSubstmt);
551                 } else if (typeSubstmt instanceof PathStatement) {
552                     emitPath((PathStatement) typeSubstmt);
553                 } else if (typeSubstmt instanceof RequireInstanceStatement) {
554                     emitRequireInstance((RequireInstanceStatement) typeSubstmt);
555                 } else if (typeSubstmt instanceof BaseStatement) {
556                     emitBase((BaseStatement) typeSubstmt);
557                 } else if (typeSubstmt instanceof BitStatement) {
558                     emitBit((BitStatement) typeSubstmt);
559                 } else if (typeSubstmt instanceof TypeStatement) {
560                     emitType((TypeStatement) typeSubstmt);
561                 }
562             }
563             super.writer.endNode();
564         }
565
566         private void emitRange(final RangeStatement range) {
567             super.writer.startRangeNode(range.rawArgument());
568             emitDocumentedConstraint(range);
569             super.writer.endNode();
570         }
571
572         private void emitFractionDigits(final FractionDigitsStatement fractionDigits) {
573             super.writer.startFractionDigitsNode(fractionDigits.rawArgument());
574             super.writer.endNode();
575         }
576
577         private void emitLength(final LengthStatement lengthStatement) {
578             super.writer.startLengthNode(lengthStatement.rawArgument());
579             emitDocumentedConstraint(lengthStatement);
580             super.writer.endNode();
581         }
582
583         private void emitPattern(final PatternStatement pattern) {
584             super.writer.startPatternNode(pattern.rawArgument());
585             emitModifier(pattern.getModifierStatement());
586             emitDocumentedConstraint(pattern);
587             super.writer.endNode();
588         }
589
590         private void emitModifier(final ModifierStatement modifierStatement) {
591             if (modifierStatement != null) {
592                 super.writer.startModifierNode(modifierStatement.rawArgument());
593                 super.writer.endNode();
594             }
595         }
596
597         private void emitDefaultNodes(final Collection<? extends DefaultStatement> collection) {
598             for (final DefaultStatement defaultValue : collection) {
599                 emitDefaultNode(defaultValue);
600             }
601         }
602
603         private void emitDefaultNode(@Nullable final DefaultStatement defaultStmt) {
604             if (defaultStmt != null) {
605                 super.writer.startDefaultNode(defaultStmt.rawArgument());
606                 super.writer.endNode();
607             }
608         }
609
610         private void emitEnum(final EnumStatement enumStmt) {
611             super.writer.startEnumNode(enumStmt.rawArgument());
612             emitDocumentedNodeWithStatus(enumStmt);
613             emitValueNode(enumStmt.getValue());
614             super.writer.endNode();
615         }
616
617         private void emitPath(final PathStatement path) {
618             super.writer.startPathNode(path.rawArgument());
619             super.writer.endNode();
620         }
621
622         private void emitRequireInstance(final RequireInstanceStatement require) {
623             super.writer.startRequireInstanceNode(require.rawArgument());
624             super.writer.endNode();
625         }
626
627         private void emitBit(final BitStatement bit) {
628             super.writer.startBitNode(bit.rawArgument());
629             emitPositionNode(bit.getPosition());
630             emitDocumentedNodeWithStatus(bit);
631             super.writer.endNode();
632         }
633
634         private void emitPositionNode(@Nullable final PositionStatement positionStatement) {
635             if (positionStatement != null) {
636                 super.writer.startPositionNode(positionStatement.rawArgument());
637                 super.writer.endNode();
638             }
639         }
640
641         private void emitStatusNode(@Nullable final StatusStatement statusStatement) {
642             if (statusStatement != null) {
643                 super.writer.startStatusNode(statusStatement.rawArgument());
644                 super.writer.endNode();
645             }
646         }
647
648         private void emitConfigNode(@Nullable final ConfigStatement configStatement) {
649             if (configStatement != null) {
650                 super.writer.startConfigNode(configStatement.rawArgument());
651                 super.writer.endNode();
652             }
653         }
654
655         private void emitMandatoryNode(@Nullable final MandatoryStatement mandatoryStatement) {
656             if (mandatoryStatement != null) {
657                 super.writer.startMandatoryNode(mandatoryStatement.rawArgument());
658                 super.writer.endNode();
659             }
660         }
661
662         private void emitPresenceNode(@Nullable final PresenceStatement presenceStatement) {
663             if (presenceStatement != null) {
664                 super.writer.startPresenceNode(presenceStatement.rawArgument());
665                 super.writer.endNode();
666             }
667         }
668
669         private void emitOrderedBy(@Nullable final OrderedByStatement orderedByStatement) {
670             if (orderedByStatement != null) {
671                 super.writer.startOrderedByNode(orderedByStatement.rawArgument());
672                 super.writer.endNode();
673             }
674         }
675
676         private void emitMust(@Nullable final MustStatement must) {
677             if (must != null) {
678                 super.writer.startMustNode(must.rawArgument());
679                 emitErrorMessageNode(must.getErrorMessageStatement());
680                 emitErrorAppTagNode(must.getErrorAppTagStatement());
681                 emitDescriptionNode(must.getDescription());
682                 emitReferenceNode(must.getReference());
683                 super.writer.endNode();
684             }
685         }
686
687         private void emitErrorMessageNode(@Nullable final ErrorMessageStatement errorMessageStatement) {
688             if (errorMessageStatement != null) {
689                 super.writer.startErrorMessageNode(errorMessageStatement.rawArgument());
690                 super.writer.endNode();
691             }
692         }
693
694         private void emitErrorAppTagNode(@Nullable final ErrorAppTagStatement errorAppTagStatement) {
695             if (errorAppTagStatement != null) {
696                 super.writer.startErrorAppTagNode(errorAppTagStatement.rawArgument());
697                 super.writer.endNode();
698             }
699         }
700
701         private void emitMinElementsNode(@Nullable final MinElementsStatement minElementsStatement) {
702             if (minElementsStatement != null) {
703                 super.writer.startMinElementsNode(minElementsStatement.rawArgument());
704                 super.writer.endNode();
705             }
706         }
707
708         private void emitMaxElementsNode(@Nullable final MaxElementsStatement maxElementsStatement) {
709             if (maxElementsStatement != null) {
710                 super.writer.startMaxElementsNode(maxElementsStatement.rawArgument());
711                 super.writer.endNode();
712             }
713         }
714
715         private void emitValueNode(@Nullable final ValueStatement valueStatement) {
716             if (valueStatement != null) {
717                 super.writer.startValueNode(valueStatement.rawArgument());
718                 super.writer.endNode();
719             }
720         }
721
722         private void emitDocumentedNodeWithStatus(final DocumentationGroup.WithStatus input) {
723             emitStatusNode(input.getStatus());
724             emitDocumentedNode(input);
725         }
726
727         private void emitDocumentedNode(final DocumentationGroup input) {
728             emitDescriptionNode(input.getDescription());
729             emitReferenceNode(input.getReference());
730         }
731
732         private void emitDocumentedConstraint(final DocumentedConstraintGroup input) {
733             emitDescriptionNode(input.getDescription());
734             emitReferenceNode(input.getReference());
735             emitErrorMessageNode(input.getErrorMessageStatement());
736             emitErrorAppTagNode(input.getErrorAppTagStatement());
737         }
738
739         private void emitGrouping(final GroupingStatement grouping) {
740             super.writer.startGroupingNode(grouping.rawArgument());
741             emitDocumentedNodeWithStatus(grouping);
742             emitDataNodeContainer(grouping);
743             emitUnknownStatementNodes(grouping);
744             emitNotifications(grouping.getNotifications());
745             emitActions(grouping.getActions());
746             super.writer.endNode();
747
748         }
749
750         private void emitContainer(final ContainerStatement container) {
751             super.writer.startContainerNode(container.rawArgument());
752             emitWhen(container.getWhenStatement());
753             emitMustNodes(container.getMusts());
754             emitIfFeatures(container.getIfFeatures());
755             emitPresenceNode(container.getPresence());
756             emitConfigNode(container.getConfig());
757             emitDocumentedNodeWithStatus(container);
758             emitDataNodeContainer(container);
759             emitUnknownStatementNodes(container);
760             emitNotifications(container.getNotifications());
761             emitActions(container.getActions());
762             super.writer.endNode();
763
764         }
765
766         private void emitLeaf(final LeafStatement leaf) {
767             super.writer.startLeafNode(leaf.rawArgument());
768             emitWhen(leaf.getWhenStatement());
769             emitIfFeatures(leaf.getIfFeatures());
770             emitType(leaf.getType());
771             emitUnitsNode(leaf.getUnits());
772             emitMustNodes(leaf.getMusts());
773             emitDefaultNode(leaf.getDefault());
774             emitConfigNode(leaf.getConfig());
775             emitMandatoryNode(leaf.getMandatory());
776             emitDocumentedNodeWithStatus(leaf);
777             emitUnknownStatementNodes(leaf);
778             super.writer.endNode();
779         }
780
781         private void emitLeafList(final LeafListStatement leafList) {
782             super.writer.startLeafListNode(leafList.rawArgument());
783             emitWhen(leafList.getWhenStatement());
784             emitIfFeatures(leafList.getIfFeatures());
785             emitType(leafList.getType());
786             emitUnitsNode(leafList.getUnits());
787             emitMustNodes(leafList.getMusts());
788             emitConfigNode(leafList.getConfig());
789             emitDefaultNodes(leafList.getDefaults());
790             emitMinElementsNode(leafList.getMinElements());
791             emitMaxElementsNode(leafList.getMaxElements());
792             emitOrderedBy(leafList.getOrderedBy());
793             emitDocumentedNodeWithStatus(leafList);
794             emitUnknownStatementNodes(leafList);
795             super.writer.endNode();
796         }
797
798         private void emitList(final ListStatement list) {
799             super.writer.startListNode(list.rawArgument());
800             emitWhen(list.getWhenStatement());
801             emitIfFeatures(list.getIfFeatures());
802             emitMustNodes(list.getMusts());
803             emitKey(list.getKey());
804             emitUniqueConstraints(list.getUnique());
805             emitConfigNode(list.getConfig());
806             emitMinElementsNode(list.getMinElements());
807             emitMaxElementsNode(list.getMaxElements());
808             emitOrderedBy(list.getOrderedBy());
809             emitDocumentedNodeWithStatus(list);
810             emitDataNodeContainer(list);
811             emitUnknownStatementNodes(list);
812             emitNotifications(list.getNotifications());
813             emitActions(list.getActions());
814             super.writer.endNode();
815         }
816
817         private void emitMustNodes(final Collection<? extends MustStatement> collection) {
818             for (final MustStatement must : collection) {
819                 emitMust(must);
820             }
821         }
822
823         private void emitKey(final KeyStatement keyStatement) {
824             if (keyStatement != null) {
825                 super.writer.startKeyNode(keyStatement.rawArgument());
826                 super.writer.endNode();
827             }
828         }
829
830         private void emitUniqueConstraints(final Collection<? extends UniqueStatement> collection) {
831             for (final UniqueStatement uniqueConstraint : collection) {
832                 emitUnique(uniqueConstraint);
833             }
834         }
835
836         private void emitUnique(final UniqueStatement uniqueConstraint) {
837             if (uniqueConstraint != null) {
838                 super.writer.startUniqueNode(uniqueConstraint.rawArgument());
839                 super.writer.endNode();
840             }
841         }
842
843         private void emitChoice(final ChoiceStatement choice) {
844             super.writer.startChoiceNode(choice.rawArgument());
845             emitWhen(choice.getWhenStatement());
846             emitIfFeatures(choice.getIfFeatures());
847             emitDefaultNode(choice.getDefault());
848             emitConfigNode(choice.getConfig());
849             emitMandatoryNode(choice.getMandatory());
850             emitDocumentedNodeWithStatus(choice);
851             emitCases(choice.getCases());
852             emitUnknownStatementNodes(choice);
853             super.writer.endNode();
854         }
855
856         private void emitShortCases(final Collection<? extends DeclaredStatement<?>> declaredSubstatements) {
857             for (final DeclaredStatement<?> child : declaredSubstatements) {
858                 if (child instanceof ContainerStatement) {
859                     emitContainer((ContainerStatement) child);
860                 } else if (child instanceof LeafStatement) {
861                     emitLeaf((LeafStatement) child);
862                 } else if (child instanceof LeafListStatement) {
863                     emitLeafList((LeafListStatement) child);
864                 } else if (child instanceof ListStatement) {
865                     emitList((ListStatement) child);
866                 } else if (child instanceof ChoiceStatement) {
867                     emitChoice((ChoiceStatement) child);
868                 } else if (child instanceof AnyxmlStatement) {
869                     emitAnyxml((AnyxmlStatement) child);
870                 } else if (child instanceof AnydataStatement) {
871                     emitAnydata((AnydataStatement) child);
872                 }
873             }
874         }
875
876         private void emitCases(final Collection<? extends CaseStatement> cases) {
877             for (final CaseStatement caze : cases) {
878                 if (isExplicitStatement(caze)) {
879                     emitCaseNode(caze);
880                 } else {
881                     final Collection<? extends DeclaredStatement<?>> shortCaseChilds = caze.declaredSubstatements();
882                     Preconditions.checkState(shortCaseChilds.size() == 1,
883                             "Only one child is allowed for each short case node");
884                     emitShortCases(shortCaseChilds);
885                 }
886             }
887         }
888
889         private void emitCaseNode(final CaseStatement caze) {
890             super.writer.startCaseNode(caze.rawArgument());
891             emitWhen(caze.getWhenStatement());
892             emitIfFeatures(caze.getIfFeatures());
893             emitDocumentedNodeWithStatus(caze);
894             emitDataNodeContainer(caze);
895             emitUnknownStatementNodes(caze);
896             super.writer.endNode();
897         }
898
899         private void emitAnyxml(final AnyxmlStatement anyxml) {
900             super.writer.startAnyxmlNode(anyxml.rawArgument());
901             emitDocumentedNodeWithStatus(anyxml);
902             emitWhen(anyxml.getWhenStatement());
903             emitIfFeatures(anyxml.getIfFeatures());
904             emitMustNodes(anyxml.getMusts());
905             emitConfigNode(anyxml.getConfig());
906             emitMandatoryNode(anyxml.getMandatory());
907             emitDocumentedNodeWithStatus(anyxml);
908             emitUnknownStatementNodes(anyxml);
909             super.writer.endNode();
910         }
911
912         private void emitAnydata(final AnydataStatement anydata) {
913             super.writer.startAnydataNode(anydata.rawArgument());
914             emitWhen(anydata.getWhenStatement());
915             emitIfFeatures(anydata.getIfFeatures());
916             emitMustNodes(anydata.getMusts());
917             emitConfigNode(anydata.getConfig());
918             emitMandatoryNode(anydata.getMandatory());
919             emitDocumentedNodeWithStatus(anydata);
920             emitUnknownStatementNodes(anydata);
921             super.writer.endNode();
922         }
923
924         private void emitUsesNode(final UsesStatement uses) {
925             super.writer.startUsesNode(uses.rawArgument());
926             emitWhen(uses.getWhenStatement());
927             emitIfFeatures(uses.getIfFeatures());
928             emitDocumentedNodeWithStatus(uses);
929             for (final RefineStatement refine : uses.getRefines()) {
930                 emitRefine(refine);
931             }
932             for (final AugmentStatement aug : uses.getAugments()) {
933                 emitUsesAugmentNode(aug);
934             }
935             super.writer.endNode();
936         }
937
938         private void emitRefine(final RefineStatement refine) {
939             super.writer.startRefineNode(refine.rawArgument());
940             emitDocumentedNode(refine);
941             emitIfFeatures(refine.getIfFeatures());
942             emitMustNodes(refine.getMusts());
943             emitPresenceNode(refine.getPresence());
944             emitDefaultNodes(refine.getDefaults());
945             emitConfigNode(refine.getConfig());
946             emitMandatoryNode(refine.getMandatory());
947             emitMinElementsNode(refine.getMinElements());
948             emitMaxElementsNode(refine.getMaxElements());
949             super.writer.endNode();
950         }
951
952         private void emitUsesAugmentNode(final AugmentStatement aug) {
953             /**
954              * differs only in location in schema, otherwise currently (as of
955              * RFC6020) it is same, so we could freely reuse path.
956              */
957             emitAugment(aug);
958         }
959
960         private void emitAugment(final AugmentStatement augmentation) {
961             super.writer.startAugmentNode(augmentation.rawArgument());
962             emitIfFeatures(augmentation.getIfFeatures());
963             emitWhen(augmentation.getWhenStatement());
964             emitDocumentedNodeWithStatus(augmentation);
965             emitDataNodeContainer(augmentation);
966             emitCases(augmentation.getCases());
967             emitUnknownStatementNodes(augmentation);
968             emitNotifications(augmentation.getNotifications());
969             emitActions(augmentation.getActions());
970             super.writer.endNode();
971         }
972
973         private void emitUnknownStatementNodes(final DeclaredStatement<?> decaredStmt) {
974             final Collection<? extends DeclaredStatement<?>> unknownStmts = Collections2
975                     .filter(decaredStmt.declaredSubstatements(), Predicates.instanceOf(UnknownStatement.class));
976             for (final DeclaredStatement<?> unknonwnStmt : unknownStmts) {
977                 emitUnknownStatementNode(unknonwnStmt);
978             }
979         }
980
981         private void emitUnknownStatementNode(final DeclaredStatement<?> unknonwnStmt) {
982             final StatementDefinition def = unknonwnStmt.statementDefinition();
983             if (def.getArgumentName() == null) {
984                 super.writer.startUnknownNode(def);
985             } else {
986                 super.writer.startUnknownNode(def, unknonwnStmt.rawArgument());
987             }
988             emitUnknownStatementNodes(unknonwnStmt);
989             super.writer.endNode();
990         }
991
992         private void emitWhen(final WhenStatement whenStatement) {
993             if (whenStatement != null) {
994                 super.writer.startWhenNode(whenStatement.rawArgument());
995                 emitDocumentedNode(whenStatement);
996                 super.writer.endNode();
997             }
998         }
999
1000         private void emitRpc(final RpcStatement rpc) {
1001             super.writer.startRpcNode(rpc.rawArgument());
1002             emitOperationBody(rpc);
1003             emitUnknownStatementNodes(rpc);
1004             super.writer.endNode();
1005         }
1006
1007         private void emitOperationBody(final OperationGroup operationStmt) {
1008             emitIfFeatures(operationStmt.getIfFeatures());
1009             emitStatusNode(operationStmt.getStatus());
1010             emitDescriptionNode(operationStmt.getDescription());
1011             emitReferenceNode(operationStmt.getReference());
1012
1013             for (final TypedefStatement typedef : operationStmt.getTypedefs()) {
1014                 emitTypedefNode(typedef);
1015             }
1016             for (final GroupingStatement grouping : operationStmt.getGroupings()) {
1017                 emitGrouping(grouping);
1018             }
1019             emitInput(operationStmt.getInput());
1020             emitOutput(operationStmt.getOutput());
1021         }
1022
1023         private void emitActions(final Collection<? extends ActionStatement> collection) {
1024             for (final ActionStatement actionDefinition : collection) {
1025                 emitAction(actionDefinition);
1026             }
1027         }
1028
1029         private void emitAction(final ActionStatement actionDefinition) {
1030             super.writer.startActionNode(actionDefinition.rawArgument());
1031             emitOperationBody(actionDefinition);
1032             emitUnknownStatementNodes(actionDefinition);
1033             super.writer.endNode();
1034         }
1035
1036         private void emitInput(final InputStatement inputStatement) {
1037             if (isExplicitStatement(inputStatement)) {
1038                 super.writer.startInputNode();
1039                 emitMustNodes(inputStatement.getMusts());
1040                 emitDataNodeContainer(inputStatement);
1041                 emitUnknownStatementNodes(inputStatement);
1042                 super.writer.endNode();
1043             }
1044         }
1045
1046         private void emitOutput(final OutputStatement output) {
1047             if (isExplicitStatement(output)) {
1048                 super.writer.startOutputNode();
1049                 emitMustNodes(output.getMusts());
1050                 emitDataNodeContainer(output);
1051                 emitUnknownStatementNodes(output);
1052                 super.writer.endNode();
1053             }
1054         }
1055
1056         private static boolean isExplicitStatement(final DeclaredStatement<?> stmt) {
1057             return stmt != null && stmt.getStatementSource() == StatementSource.DECLARATION;
1058         }
1059
1060         private void emitNotifications(final Collection<? extends NotificationStatement> collection) {
1061             for (final NotificationStatement notification : collection) {
1062                 emitNotificationNode(notification);
1063             }
1064         }
1065
1066         private void emitNotificationNode(final NotificationStatement notification) {
1067             super.writer.startNotificationNode(notification.rawArgument());
1068             emitIfFeatures(notification.getIfFeatures());
1069             emitMustNodes(notification.getMusts());
1070             emitDocumentedNodeWithStatus(notification);
1071             emitDataNodeContainer(notification);
1072             emitUnknownStatementNodes(notification);
1073             super.writer.endNode();
1074         }
1075
1076         private void emitDeviation(final DeviationStatement deviation) {
1077             super.writer.startDeviationNode(deviation.rawArgument());
1078             emitDeviateStatements(deviation.getDeviateStatements());
1079             emitUnknownStatementNodes(deviation);
1080             super.writer.endNode();
1081         }
1082
1083         private void emitDeviateStatements(final Collection<? extends DeviateStatement> deviateStatements) {
1084             for (final DeviateStatement deviateStatement : deviateStatements) {
1085                 emitDeviate(deviateStatement);
1086             }
1087         }
1088
1089         private void emitDeviate(final DeviateStatement deviateStatement) {
1090             super.writer.startDeviateNode(deviateStatement.rawArgument());
1091             /*
1092              * :FIXME Currently, DeviateStatementImpl contains implementation
1093              * for all deviate types (i.e. add, replace, delete). However it
1094              * would be better to create subinterfaces of DeviateStatement for
1095              * each deviate type (i.e. AddDeviateStatement,
1096              * ReplaceDeviateStatement,..) and create argument specific supports
1097              * (i.e. definitions) for each deviate type (very similarly like by
1098              * TypeStatement).
1099              */
1100             for (final DeclaredStatement<?> child : deviateStatement.declaredSubstatements()) {
1101                 if (child instanceof MustStatement) {
1102                     emitMust((MustStatement) child);
1103                 } else if (child instanceof DefaultStatement) {
1104                     emitDefaultNode((DefaultStatement) child);
1105                 } else if (child instanceof UniqueStatement) {
1106                     emitUnique((UniqueStatement) child);
1107                 } else if (child instanceof UnitsStatement) {
1108                     emitUnitsNode((UnitsStatement) child);
1109                 } else if (child instanceof TypeStatement) {
1110                     emitType((TypeStatement) child);
1111                 } else if (child instanceof MinElementsStatement) {
1112                     emitMinElementsNode((MinElementsStatement) child);
1113                 } else if (child instanceof MaxElementsStatement) {
1114                     emitMaxElementsNode((MaxElementsStatement) child);
1115                 } else if (child instanceof MandatoryStatement) {
1116                     emitMandatoryNode((MandatoryStatement) child);
1117                 } else if (child instanceof ConfigStatement) {
1118                     emitConfigNode((ConfigStatement) child);
1119                 } else if (child instanceof UnknownStatement) {
1120                     emitUnknownStatementNode(child);
1121                 }
1122             }
1123             super.writer.endNode();
1124         }
1125     }
1126
1127     static class EffectiveSchemaContextEmitter extends SchemaContextEmitter {
1128
1129         EffectiveSchemaContextEmitter(final YangModuleWriter writer, final Map<QName, StatementDefinition> extensions,
1130                 final YangVersion yangVersion, final boolean emitInstantiated) {
1131             super(writer, extensions, yangVersion, emitInstantiated, true);
1132         }
1133
1134         void emitModule(final Module input) {
1135             super.writer.startModuleNode(input.getName());
1136             emitModuleHeader(input);
1137             emitLinkageNodes(input);
1138             emitMetaNodes(input);
1139             emitRevisionNodes(input);
1140             emitBodyNodes(input);
1141             super.writer.endNode();
1142         }
1143
1144         private void emitModuleHeader(final Module input) {
1145             emitYangVersionNode(input.getYangVersion());
1146             emitNamespace(input.getNamespace());
1147             emitPrefixNode(input.getPrefix());
1148         }
1149
1150         @SuppressWarnings("unused")
1151         private void emitSubmodule(final String input) {
1152             /*
1153              * FIXME: BUG-2444: Implement submodule export
1154              *
1155              * submoduleHeaderNodes linkageNodes metaNodes revisionNodes
1156              * bodyNodes super.writer.endNode();
1157              */
1158         }
1159
1160         @SuppressWarnings("unused")
1161         private void emitSubmoduleHeaderNodes(final Module input) {
1162             /*
1163              * FIXME: BUG-2444: Implement submodule headers properly
1164              *
1165              * :yangVersionNode //Optional
1166              *
1167              * :belongsToNode
1168              */
1169         }
1170
1171         private void emitMetaNodes(final Module input) {
1172             emitOrganizationNode(input.getOrganization());
1173             emitContact(input.getContact());
1174             emitDescriptionNode(input.getDescription());
1175             emitReferenceNode(input.getReference());
1176         }
1177
1178         private void emitLinkageNodes(final Module input) {
1179             for (final ModuleImport importNode : input.getImports()) {
1180                 emitImport(importNode);
1181             }
1182             /*
1183              * FIXME: BUG-2444: Emit include statements
1184              */
1185         }
1186
1187         private void emitRevisionNodes(final Module input) {
1188             /*
1189              * FIXME: BUG-2444: emit revisions properly, when parsed model will
1190              * provide enough information
1191              */
1192             input.getRevision().ifPresent(this::emitRevision);
1193         }
1194
1195         private void emitBodyNodes(final Module input) {
1196
1197             for (final ExtensionDefinition extension : input.getExtensionSchemaNodes()) {
1198                 emitExtension(extension);
1199             }
1200             for (final FeatureDefinition definition : input.getFeatures()) {
1201                 emitFeature(definition);
1202             }
1203             for (final IdentitySchemaNode identity : input.getIdentities()) {
1204                 emitIdentity(identity);
1205             }
1206             for (final Deviation deviation : input.getDeviations()) {
1207                 emitDeviation(deviation);
1208             }
1209
1210             emitDataNodeContainer(input);
1211
1212             for (final AugmentationSchemaNode augmentation : input.getAugmentations()) {
1213                 emitAugment(augmentation);
1214             }
1215             for (final RpcDefinition rpc : input.getRpcs()) {
1216                 emitRpc(rpc);
1217             }
1218
1219             emitNotifications(input.getNotifications());
1220         }
1221
1222         private void emitDataNodeContainer(final DataNodeContainer input) {
1223             for (final TypeDefinition<?> typedef : input.getTypeDefinitions()) {
1224                 emitTypedefNode(typedef);
1225             }
1226             for (final GroupingDefinition grouping : input.getGroupings()) {
1227                 emitGrouping(grouping);
1228             }
1229             for (final DataSchemaNode child : input.getChildNodes()) {
1230                 emitDataSchemaNode(child);
1231             }
1232             for (final UsesNode usesNode : input.getUses()) {
1233                 emitUsesNode(usesNode);
1234             }
1235         }
1236
1237         private void emitDataSchemaNode(final DataSchemaNode child) {
1238             if (!super.emitInstantiated && (child.isAddedByUses() || child.isAugmenting())) {
1239                 // We skip instantiated nodes.
1240                 return;
1241             }
1242
1243             if (child instanceof ContainerSchemaNode) {
1244                 emitContainer((ContainerSchemaNode) child);
1245             } else if (child instanceof LeafSchemaNode) {
1246                 emitLeaf((LeafSchemaNode) child);
1247             } else if (child instanceof LeafListSchemaNode) {
1248                 emitLeafList((LeafListSchemaNode) child);
1249             } else if (child instanceof ListSchemaNode) {
1250                 emitList((ListSchemaNode) child);
1251             } else if (child instanceof ChoiceSchemaNode) {
1252                 emitChoice((ChoiceSchemaNode) child);
1253             } else if (child instanceof AnyXmlSchemaNode) {
1254                 emitAnyxml((AnyXmlSchemaNode) child);
1255             } else if (child instanceof AnyDataSchemaNode) {
1256                 emitAnydata((AnyDataSchemaNode) child);
1257             } else {
1258                 throw new UnsupportedOperationException("Not supported DataSchemaNode type " + child.getClass());
1259             }
1260         }
1261
1262         private void emitYangVersionNode(final YangVersion input) {
1263             super.writer.startYangVersionNode(input.toString());
1264             super.writer.endNode();
1265         }
1266
1267         private void emitImport(final ModuleImport importNode) {
1268             super.writer.startImportNode(importNode.getModuleName());
1269             emitDescriptionNode(importNode.getDescription());
1270             emitReferenceNode(importNode.getReference());
1271             emitPrefixNode(importNode.getPrefix());
1272
1273             importNode.getRevision().ifPresent(this::emitRevisionDateNode);
1274             super.writer.endNode();
1275         }
1276
1277         @SuppressWarnings("unused")
1278         private void emitInclude(final String input) {
1279             /*
1280              * FIXME: BUG-2444: Implement proper export of include statements
1281              * startIncludeNode(IdentifierHelper.getIdentifier(String :input));
1282              *
1283              *
1284              * :revisionDateNode :super.writer.endNode();)
1285              */
1286         }
1287
1288         private void emitNamespace(final URI uri) {
1289             super.writer.startNamespaceNode(uri);
1290             super.writer.endNode();
1291
1292         }
1293
1294         private void emitPrefixNode(final String input) {
1295             super.writer.startPrefixNode(input);
1296             super.writer.endNode();
1297
1298         }
1299
1300         @SuppressWarnings("unused")
1301         private void emitBelongsTo(final String input) {
1302             /*
1303              * FIXME: BUG-2444: Implement proper export of belongs-to statements
1304              * startIncludeNode(IdentifierHelper.getIdentifier(String :input));
1305              *
1306              *
1307              * :super.writer.startBelongsToNode(IdentifierHelper.getIdentifier(
1308              * String :input));
1309              *
1310              *
1311              * :prefixNode :super.writer.endNode();
1312              *
1313              */
1314
1315         }
1316
1317         private void emitOrganizationNode(final String input) {
1318             if (!Strings.isNullOrEmpty(input)) {
1319                 super.writer.startOrganizationNode(input);
1320                 super.writer.endNode();
1321             }
1322         }
1323
1324         private void emitContact(final String input) {
1325             if (!Strings.isNullOrEmpty(input)) {
1326                 super.writer.startContactNode(input);
1327                 super.writer.endNode();
1328             }
1329         }
1330
1331         private void emitDescriptionNode(@Nullable final String input) {
1332             if (!Strings.isNullOrEmpty(input)) {
1333                 super.writer.startDescriptionNode(input);
1334                 super.writer.endNode();
1335             }
1336         }
1337
1338         private void emitReferenceNode(@Nullable final String input) {
1339             if (!Strings.isNullOrEmpty(input)) {
1340                 super.writer.startReferenceNode(input);
1341                 super.writer.endNode();
1342             }
1343         }
1344
1345         private void emitUnitsNode(@Nullable final String input) {
1346             if (!Strings.isNullOrEmpty(input)) {
1347                 super.writer.startUnitsNode(input);
1348                 super.writer.endNode();
1349             }
1350         }
1351
1352         private void emitRevision(final Revision date) {
1353             if (date != null) {
1354                 super.writer.startRevisionNode(date);
1355
1356                 // FIXME: BUG-2444: FIXME: BUG-2444: BUG-2417: descriptionNode
1357                 // //FIXME: BUG-2444: Optional
1358                 // FIXME: BUG-2444: FIXME: BUG-2444: BUG-2417: referenceNode
1359                 // //FIXME: BUG-2444: Optional
1360                 super.writer.endNode();
1361             }
1362         }
1363
1364         private void emitRevisionDateNode(final Revision date) {
1365             super.writer.startRevisionDateNode(date);
1366             super.writer.endNode();
1367         }
1368
1369         private void emitExtension(final ExtensionDefinition extension) {
1370             super.writer.startExtensionNode(extension.getQName());
1371             emitArgument(extension.getArgument(), extension.isYinElement());
1372             emitStatusNode(extension.getStatus());
1373             emitDescriptionNode(extension.getDescription());
1374             emitReferenceNode(extension.getReference());
1375             emitUnknownStatementNodes(extension.getUnknownSchemaNodes());
1376             super.writer.endNode();
1377
1378         }
1379
1380         private void emitArgument(final @Nullable String input, final boolean yinElement) {
1381             if (input != null) {
1382                 super.writer.startArgumentNode(input);
1383                 emitYinElement(yinElement);
1384                 super.writer.endNode();
1385             }
1386
1387         }
1388
1389         private void emitYinElement(final boolean yinElement) {
1390             super.writer.startYinElementNode(yinElement);
1391             super.writer.endNode();
1392
1393         }
1394
1395         private void emitIdentity(final IdentitySchemaNode identity) {
1396             super.writer.startIdentityNode(identity.getQName());
1397             emitBaseIdentities(identity.getBaseIdentities());
1398             emitStatusNode(identity.getStatus());
1399             emitDescriptionNode(identity.getDescription());
1400             emitReferenceNode(identity.getReference());
1401             super.writer.endNode();
1402         }
1403
1404         private void emitBaseIdentities(final Set<IdentitySchemaNode> identities) {
1405             for (final IdentitySchemaNode identitySchemaNode : identities) {
1406                 emitBase(identitySchemaNode.getQName());
1407             }
1408         }
1409
1410         private void emitBase(final QName qName) {
1411             super.writer.startBaseNode(qName);
1412             super.writer.endNode();
1413         }
1414
1415         private void emitFeature(final FeatureDefinition definition) {
1416             super.writer.startFeatureNode(definition.getQName());
1417
1418             // FIXME: BUG-2444: FIXME: BUG-2444: Expose ifFeature
1419             // *(ifFeatureNode )
1420             emitStatusNode(definition.getStatus());
1421             emitDescriptionNode(definition.getDescription());
1422             emitReferenceNode(definition.getReference());
1423             super.writer.endNode();
1424
1425         }
1426
1427         @SuppressWarnings("unused")
1428         private void emitIfFeature(final String input) {
1429             /*
1430              * FIXME: BUG-2444: Implement proper export of include statements
1431              * startIncludeNode(IdentifierHelper.getIdentifier(String :input));
1432              *
1433              */
1434         }
1435
1436         private void emitTypedefNode(final TypeDefinition<?> typedef) {
1437             super.writer.startTypedefNode(typedef.getQName());
1438             // Differentiate between derived type and existing type
1439             // name.
1440             emitTypeNodeDerived(typedef);
1441             emitUnitsNode(typedef.getUnits());
1442             emitDefaultNode(typedef.getDefaultValue());
1443             emitStatusNode(typedef.getStatus());
1444             emitDescriptionNode(typedef.getDescription());
1445             emitReferenceNode(typedef.getReference());
1446             emitUnknownStatementNodes(typedef.getUnknownSchemaNodes());
1447             super.writer.endNode();
1448
1449         }
1450
1451         private void emitTypeNode(final SchemaPath parentPath, final TypeDefinition<?> subtype) {
1452             final SchemaPath path = subtype.getPath();
1453             if (isPrefix(parentPath.getPathFromRoot(), path.getPathFromRoot())) {
1454                 emitTypeNodeDerived(subtype);
1455             } else {
1456                 emitTypeNodeReferenced(subtype);
1457             }
1458         }
1459
1460         private void emitTypeNodeReferenced(final TypeDefinition<?> typeDefinition) {
1461             super.writer.startTypeNode(typeDefinition.getQName());
1462             super.writer.endNode();
1463
1464         }
1465
1466         private void emitTypeNodeDerived(final TypeDefinition<?> typeDefinition) {
1467             final TypeDefinition<?> b = typeDefinition.getBaseType();
1468             final TypeDefinition<?> baseType = b == null ? typeDefinition : b;
1469             super.writer.startTypeNode(baseType.getQName());
1470             emitTypeBodyNodes(typeDefinition);
1471             super.writer.endNode();
1472
1473         }
1474
1475         private void emitTypeBodyNodes(final TypeDefinition<?> typeDef) {
1476             if (typeDef instanceof UnsignedIntegerTypeDefinition) {
1477                 emitUnsignedIntegerSpecification((UnsignedIntegerTypeDefinition) typeDef);
1478             } else if (typeDef instanceof IntegerTypeDefinition) {
1479                 emitIntegerSpefication((IntegerTypeDefinition) typeDef);
1480             } else if (typeDef instanceof DecimalTypeDefinition) {
1481                 emitDecimal64Specification((DecimalTypeDefinition) typeDef);
1482             } else if (typeDef instanceof StringTypeDefinition) {
1483                 emitStringRestrictions((StringTypeDefinition) typeDef);
1484             } else if (typeDef instanceof EnumTypeDefinition) {
1485                 emitEnumSpecification((EnumTypeDefinition) typeDef);
1486             } else if (typeDef instanceof LeafrefTypeDefinition) {
1487                 emitLeafrefSpecification((LeafrefTypeDefinition) typeDef);
1488             } else if (typeDef instanceof IdentityrefTypeDefinition) {
1489                 emitIdentityrefSpecification((IdentityrefTypeDefinition) typeDef);
1490             } else if (typeDef instanceof InstanceIdentifierTypeDefinition) {
1491                 emitInstanceIdentifierSpecification((InstanceIdentifierTypeDefinition) typeDef);
1492             } else if (typeDef instanceof BitsTypeDefinition) {
1493                 emitBitsSpecification((BitsTypeDefinition) typeDef);
1494             } else if (typeDef instanceof UnionTypeDefinition) {
1495                 emitUnionSpecification((UnionTypeDefinition) typeDef);
1496             } else if (typeDef instanceof BinaryTypeDefinition) {
1497                 ((BinaryTypeDefinition) typeDef).getLengthConstraint().ifPresent(this::emitLength);
1498             } else if (typeDef instanceof BooleanTypeDefinition || typeDef instanceof EmptyTypeDefinition) {
1499                 // NOOP
1500             } else {
1501                 throw new IllegalArgumentException("Not supported type " + typeDef.getClass());
1502             }
1503         }
1504
1505         private void emitIntegerSpefication(final IntegerTypeDefinition typeDef) {
1506             emitRangeNodeOptional(typeDef.getRangeConstraints());
1507         }
1508
1509         private void emitUnsignedIntegerSpecification(final UnsignedIntegerTypeDefinition typeDef) {
1510             emitRangeNodeOptional(typeDef.getRangeConstraints());
1511
1512         }
1513
1514         private void emitRangeNodeOptional(final List<RangeConstraint> list) {
1515             // FIXME: BUG-2444: Wrong decomposition in API, should be
1516             // LenghtConstraint
1517             // which contains ranges.
1518             if (!list.isEmpty()) {
1519                 super.writer.startRangeNode(toRangeString(list));
1520                 final RangeConstraint first = list.iterator().next();
1521                 emitErrorMessageNode(first.getErrorMessage());
1522                 emitErrorAppTagNode(first.getErrorAppTag());
1523                 emitDescriptionNode(first.getDescription());
1524                 emitReferenceNode(first.getReference());
1525                 super.writer.endNode();
1526             }
1527
1528         }
1529
1530         private void emitDecimal64Specification(final DecimalTypeDefinition typeDefinition) {
1531             emitFranctionDigitsNode(typeDefinition.getFractionDigits());
1532             emitRangeNodeOptional(typeDefinition.getRangeConstraints());
1533
1534         }
1535
1536         private void emitFranctionDigitsNode(final Integer fractionDigits) {
1537             super.writer.startFractionDigitsNode(fractionDigits);
1538             super.writer.endNode();
1539         }
1540
1541         private void emitStringRestrictions(final StringTypeDefinition typeDef) {
1542             typeDef.getLengthConstraint().ifPresent(this::emitLength);
1543
1544             for (final PatternConstraint pattern : typeDef.getPatternConstraints()) {
1545                 emitPatternNode(pattern);
1546             }
1547         }
1548
1549         private void emitLength(final LengthConstraint constraint) {
1550             super.writer.startLengthNode(toLengthString(constraint.getAllowedRanges()));
1551             emitErrorMessageNode(constraint.getErrorMessage());
1552             emitErrorAppTagNode(constraint.getErrorAppTag());
1553             emitDescriptionNode(constraint.getDescription());
1554             emitReferenceNode(constraint.getReference());
1555             super.writer.endNode();
1556         }
1557
1558         private static String toLengthString(final RangeSet<Integer> ranges) {
1559             final Iterator<Range<Integer>> it = ranges.asRanges().iterator();
1560             if (!it.hasNext()) {
1561                 return "";
1562             }
1563
1564             final StringBuilder sb = new StringBuilder();
1565             boolean haveNext;
1566             do {
1567                 final Range<Integer> current = it.next();
1568                 haveNext = it.hasNext();
1569                 appendRange(sb, current.lowerEndpoint(), current.upperEndpoint(), haveNext);
1570             } while (haveNext);
1571
1572             return sb.toString();
1573         }
1574
1575         private static String toRangeString(final List<RangeConstraint> list) {
1576             final Iterator<RangeConstraint> it = list.iterator();
1577             if (!it.hasNext()) {
1578                 return "";
1579             }
1580
1581             final StringBuilder sb = new StringBuilder();
1582             boolean haveNext;
1583             do {
1584                 final RangeConstraint current = it.next();
1585                 haveNext = it.hasNext();
1586                 appendRange(sb, current.getMin(), current.getMax(), haveNext);
1587             } while (haveNext);
1588
1589             return sb.toString();
1590         }
1591
1592         private static void appendRange(final StringBuilder sb, final Number min, final Number max,
1593                 final boolean haveNext) {
1594             sb.append(min);
1595             if (!min.equals(max)) {
1596                 sb.append("..");
1597                 sb.append(max);
1598             }
1599             if (haveNext) {
1600                 sb.append('|');
1601             }
1602         }
1603
1604         private void emitPatternNode(final PatternConstraint pattern) {
1605             super.writer.startPatternNode(pattern.getRawRegularExpression());
1606             // FIXME: BUG-2444: Optional
1607             emitErrorMessageNode(pattern.getErrorMessage());
1608             // FIXME: BUG-2444: Optional
1609             emitErrorAppTagNode(pattern.getErrorAppTag());
1610             emitDescriptionNode(pattern.getDescription());
1611             emitModifier(pattern.getModifier());
1612             super.writer.endNode();
1613         }
1614
1615         private void emitModifier(final ModifierKind modifier) {
1616             if (modifier != null) {
1617                 super.writer.startModifierNode(modifier);
1618                 super.writer.endNode();
1619             }
1620         }
1621
1622         private void emitDefaultNodes(final Collection<String> defaults) {
1623             for (final String defaultValue : defaults) {
1624                 emitDefaultNode(defaultValue);
1625             }
1626         }
1627
1628         private void emitDefaultNode(@Nullable final Object object) {
1629             if (object != null) {
1630                 super.writer.startDefaultNode(object.toString());
1631                 super.writer.endNode();
1632             }
1633         }
1634
1635         private void emitEnumSpecification(final EnumTypeDefinition typeDefinition) {
1636             for (final EnumPair enumValue : typeDefinition.getValues()) {
1637                 emitEnumNode(enumValue);
1638             }
1639         }
1640
1641         private void emitEnumNode(final EnumPair enumValue) {
1642             super.writer.startEnumNode(enumValue.getName());
1643             emitValueNode(enumValue.getValue());
1644             emitStatusNode(enumValue.getStatus());
1645             emitDescriptionNode(enumValue.getDescription());
1646             emitReferenceNode(enumValue.getReference());
1647             super.writer.endNode();
1648         }
1649
1650         private void emitLeafrefSpecification(final LeafrefTypeDefinition typeDefinition) {
1651             emitPathNode(typeDefinition.getPathStatement());
1652             if (YangVersion.VERSION_1_1 == super.yangVersion) {
1653                 emitRequireInstanceNode(typeDefinition.requireInstance());
1654             }
1655         }
1656
1657         private void emitPathNode(final RevisionAwareXPath revisionAwareXPath) {
1658             super.writer.startPathNode(revisionAwareXPath);
1659             super.writer.endNode();
1660         }
1661
1662         private void emitRequireInstanceNode(final boolean require) {
1663             super.writer.startRequireInstanceNode(require);
1664             super.writer.endNode();
1665         }
1666
1667         private void emitInstanceIdentifierSpecification(final InstanceIdentifierTypeDefinition typeDefinition) {
1668             emitRequireInstanceNode(typeDefinition.requireInstance());
1669         }
1670
1671         private void emitIdentityrefSpecification(final IdentityrefTypeDefinition typeDefinition) {
1672             emitBaseIdentities(typeDefinition.getIdentities());
1673         }
1674
1675         private void emitUnionSpecification(final UnionTypeDefinition typeDefinition) {
1676             for (final TypeDefinition<?> subtype : typeDefinition.getTypes()) {
1677                 // FIXME: BUG-2444: What if we have locally modified types here?
1678                 // is solution to look-up in schema path?
1679                 emitTypeNode(typeDefinition.getPath(), subtype);
1680             }
1681         }
1682
1683         private void emitBitsSpecification(final BitsTypeDefinition typeDefinition) {
1684             for (final Bit bit : typeDefinition.getBits()) {
1685                 emitBit(bit);
1686             }
1687         }
1688
1689         private void emitBit(final Bit bit) {
1690             super.writer.startBitNode(bit.getName());
1691             emitPositionNode(bit.getPosition());
1692             emitStatusNode(bit.getStatus());
1693             emitDescriptionNode(bit.getDescription());
1694             emitReferenceNode(bit.getReference());
1695             super.writer.endNode();
1696         }
1697
1698         private void emitPositionNode(@Nullable final Long position) {
1699             if (position != null) {
1700                 super.writer.startPositionNode(UnsignedInteger.valueOf(position));
1701                 super.writer.endNode();
1702             }
1703         }
1704
1705         private void emitStatusNode(@Nullable final Status status) {
1706             if (status != null) {
1707                 super.writer.startStatusNode(status);
1708                 super.writer.endNode();
1709             }
1710         }
1711
1712         private void emitConfigNode(final boolean config) {
1713             super.writer.startConfigNode(config);
1714             super.writer.endNode();
1715         }
1716
1717         private void emitMandatoryNode(final boolean mandatory) {
1718             super.writer.startMandatoryNode(mandatory);
1719             super.writer.endNode();
1720         }
1721
1722         private void emitPresenceNode(final boolean presence) {
1723             super.writer.startPresenceNode(presence);
1724             super.writer.endNode();
1725         }
1726
1727         private void emitOrderedBy(final boolean userOrdered) {
1728             if (userOrdered) {
1729                 super.writer.startOrderedByNode("user");
1730             } else {
1731                 super.writer.startOrderedByNode("system");
1732             }
1733             super.writer.endNode();
1734         }
1735
1736         private void emitMust(@Nullable final MustDefinition mustCondition) {
1737             if (mustCondition != null && mustCondition.getXpath() != null) {
1738                 super.writer.startMustNode(mustCondition.getXpath());
1739                 emitErrorMessageNode(mustCondition.getErrorMessage());
1740                 emitErrorAppTagNode(mustCondition.getErrorAppTag());
1741                 emitDescriptionNode(mustCondition.getDescription());
1742                 emitReferenceNode(mustCondition.getReference());
1743                 super.writer.endNode();
1744             }
1745
1746         }
1747
1748         private void emitErrorMessageNode(@Nullable final String input) {
1749             if (input != null && !input.isEmpty()) {
1750                 super.writer.startErrorMessageNode(input);
1751                 super.writer.endNode();
1752             }
1753         }
1754
1755         private void emitErrorAppTagNode(final String input) {
1756             if (input != null && !input.isEmpty()) {
1757                 super.writer.startErrorAppTagNode(input);
1758                 super.writer.endNode();
1759             }
1760         }
1761
1762         private void emitMinElementsNode(final Integer min) {
1763             if (min != null) {
1764                 super.writer.startMinElementsNode(min);
1765                 super.writer.endNode();
1766             }
1767         }
1768
1769         private void emitMaxElementsNode(final Integer max) {
1770             if (max != null) {
1771                 super.writer.startMaxElementsNode(max);
1772                 super.writer.endNode();
1773             }
1774         }
1775
1776         private void emitValueNode(@Nullable final Integer value) {
1777             if (value != null) {
1778                 super.writer.startValueNode(value);
1779                 super.writer.endNode();
1780             }
1781         }
1782
1783         private void emitDocumentedNode(final DocumentedNode.WithStatus input) {
1784             emitStatusNode(input.getStatus());
1785             emitDescriptionNode(input.getDescription());
1786             emitReferenceNode(input.getReference());
1787         }
1788
1789         private void emitGrouping(final GroupingDefinition grouping) {
1790             super.writer.startGroupingNode(grouping.getQName());
1791             emitDocumentedNode(grouping);
1792             emitDataNodeContainer(grouping);
1793             emitUnknownStatementNodes(grouping.getUnknownSchemaNodes());
1794             emitNotifications(grouping.getNotifications());
1795             emitActions(grouping.getActions());
1796             super.writer.endNode();
1797
1798         }
1799
1800         private void emitContainer(final ContainerSchemaNode child) {
1801             super.writer.startContainerNode(child.getQName());
1802             emitConstraints(child.getConstraints());
1803             // FIXME: BUG-2444: whenNode //:Optional
1804             // FIXME: BUG-2444: *(ifFeatureNode )
1805             emitPresenceNode(child.isPresenceContainer());
1806             emitConfigNode(child.isConfiguration());
1807             emitDocumentedNode(child);
1808             emitDataNodeContainer(child);
1809             emitUnknownStatementNodes(child.getUnknownSchemaNodes());
1810             emitNotifications(child.getNotifications());
1811             emitActions(child.getActions());
1812             super.writer.endNode();
1813
1814         }
1815
1816         private void emitConstraints(final ConstraintDefinition constraints) {
1817             emitWhen(constraints.getWhenCondition());
1818             for (final MustDefinition mustCondition : constraints.getMustConstraints()) {
1819                 emitMust(mustCondition);
1820             }
1821         }
1822
1823         private void emitLeaf(final LeafSchemaNode child) {
1824             super.writer.startLeafNode(child.getQName());
1825             emitWhen(child.getConstraints().getWhenCondition());
1826             // FIXME: BUG-2444: *(ifFeatureNode )
1827             emitTypeNode(child.getPath(), child.getType());
1828             emitUnitsNode(child.getUnits());
1829             emitMustNodes(child.getConstraints().getMustConstraints());
1830             emitDefaultNode(child.getDefault());
1831             emitConfigNode(child.isConfiguration());
1832             emitMandatoryNode(child.getConstraints().isMandatory());
1833             emitDocumentedNode(child);
1834             emitUnknownStatementNodes(child.getUnknownSchemaNodes());
1835             super.writer.endNode();
1836
1837         }
1838
1839         private void emitLeafList(final LeafListSchemaNode child) {
1840             super.writer.startLeafListNode(child.getQName());
1841
1842             emitWhen(child.getConstraints().getWhenCondition());
1843             // FIXME: BUG-2444: *(ifFeatureNode )
1844             emitTypeNode(child.getPath(), child.getType());
1845             emitUnitsNode(child.getType().getUnits());
1846             // FIXME: BUG-2444: unitsNode /Optional
1847             emitMustNodes(child.getConstraints().getMustConstraints());
1848             emitConfigNode(child.isConfiguration());
1849             emitDefaultNodes(child.getDefaults());
1850             emitMinElementsNode(child.getConstraints().getMinElements());
1851             emitMaxElementsNode(child.getConstraints().getMaxElements());
1852             emitOrderedBy(child.isUserOrdered());
1853             emitDocumentedNode(child);
1854             emitUnknownStatementNodes(child.getUnknownSchemaNodes());
1855             super.writer.endNode();
1856
1857         }
1858
1859         private void emitList(final ListSchemaNode child) {
1860             super.writer.startListNode(child.getQName());
1861             emitWhen(child.getConstraints().getWhenCondition());
1862
1863             // FIXME: BUG-2444: *(ifFeatureNode )
1864             emitMustNodes(child.getConstraints().getMustConstraints());
1865             emitKey(child.getKeyDefinition());
1866             emitUniqueConstraints(child.getUniqueConstraints());
1867             emitConfigNode(child.isConfiguration());
1868             emitMinElementsNode(child.getConstraints().getMinElements());
1869             emitMaxElementsNode(child.getConstraints().getMaxElements());
1870             emitOrderedBy(child.isUserOrdered());
1871             emitDocumentedNode(child);
1872             emitDataNodeContainer(child);
1873             emitUnknownStatementNodes(child.getUnknownSchemaNodes());
1874             emitNotifications(child.getNotifications());
1875             emitActions(child.getActions());
1876             super.writer.endNode();
1877
1878         }
1879
1880         private void emitMustNodes(final Set<MustDefinition> mustConstraints) {
1881             for (final MustDefinition must : mustConstraints) {
1882                 emitMust(must);
1883             }
1884         }
1885
1886         private void emitKey(final List<QName> keyList) {
1887             if (keyList != null && !keyList.isEmpty()) {
1888                 super.writer.startKeyNode(keyList);
1889                 super.writer.endNode();
1890             }
1891         }
1892
1893         private void emitUniqueConstraints(final Collection<UniqueConstraint> uniqueConstraints) {
1894             for (final UniqueConstraint uniqueConstraint : uniqueConstraints) {
1895                 emitUnique(uniqueConstraint);
1896             }
1897         }
1898
1899         private void emitUnique(final UniqueConstraint uniqueConstraint) {
1900             super.writer.startUniqueNode(uniqueConstraint);
1901             super.writer.endNode();
1902         }
1903
1904         private void emitChoice(final ChoiceSchemaNode choice) {
1905             super.writer.startChoiceNode(choice.getQName());
1906             emitWhen(choice.getConstraints().getWhenCondition());
1907             // FIXME: BUG-2444: *(ifFeatureNode )
1908             // FIXME: BUG-2444: defaultNode //Optional
1909             emitConfigNode(choice.isConfiguration());
1910             emitMandatoryNode(choice.getConstraints().isMandatory());
1911             emitDocumentedNode(choice);
1912             for (final ChoiceCaseNode caze : choice.getCases()) {
1913                 // TODO: emit short case?
1914                 emitCaseNode(caze);
1915             }
1916             emitUnknownStatementNodes(choice.getUnknownSchemaNodes());
1917             super.writer.endNode();
1918         }
1919
1920         private void emitCaseNode(final ChoiceCaseNode caze) {
1921             if (!super.emitInstantiated && caze.isAugmenting()) {
1922                 return;
1923             }
1924             super.writer.startCaseNode(caze.getQName());
1925             emitWhen(caze.getConstraints().getWhenCondition());
1926             // FIXME: BUG-2444: *(ifFeatureNode )
1927             emitDocumentedNode(caze);
1928             emitDataNodeContainer(caze);
1929             emitUnknownStatementNodes(caze.getUnknownSchemaNodes());
1930             super.writer.endNode();
1931
1932         }
1933
1934         private void emitAnyxml(final AnyXmlSchemaNode anyxml) {
1935             super.writer.startAnyxmlNode(anyxml.getQName());
1936             emitBodyOfDataSchemaNode(anyxml);
1937             super.writer.endNode();
1938         }
1939
1940         private void emitAnydata(final AnyDataSchemaNode anydata) {
1941             super.writer.startAnydataNode(anydata.getQName());
1942             emitBodyOfDataSchemaNode(anydata);
1943             super.writer.endNode();
1944         }
1945
1946         private void emitBodyOfDataSchemaNode(final DataSchemaNode dataSchemaNode) {
1947             emitWhen(dataSchemaNode.getConstraints().getWhenCondition());
1948             // FIXME: BUG-2444: *(ifFeatureNode )
1949             emitMustNodes(dataSchemaNode.getConstraints().getMustConstraints());
1950             emitConfigNode(dataSchemaNode.isConfiguration());
1951             emitMandatoryNode(dataSchemaNode.getConstraints().isMandatory());
1952             emitDocumentedNode(dataSchemaNode);
1953             emitUnknownStatementNodes(dataSchemaNode.getUnknownSchemaNodes());
1954         }
1955
1956         private void emitUsesNode(final UsesNode usesNode) {
1957             if (super.emitUses && !usesNode.isAddedByUses() && !usesNode.isAugmenting()) {
1958                 super.writer.startUsesNode(usesNode.getGroupingPath().getLastComponent());
1959                 /*
1960                  * FIXME: BUG-2444: whenNode / *(ifFeatureNode ) statusNode //
1961                  * Optional F : descriptionNode // Optional referenceNode //
1962                  * Optional
1963                  */
1964                 for (final Entry<SchemaPath, SchemaNode> refine : usesNode.getRefines().entrySet()) {
1965                     emitRefine(refine);
1966                 }
1967                 for (final AugmentationSchemaNode aug : usesNode.getAugmentations()) {
1968                     emitUsesAugmentNode(aug);
1969                 }
1970                 super.writer.endNode();
1971             }
1972         }
1973
1974         private void emitRefine(final Entry<SchemaPath, SchemaNode> refine) {
1975             final SchemaPath path = refine.getKey();
1976             final SchemaNode value = refine.getValue();
1977             super.writer.startRefineNode(path);
1978
1979             if (value instanceof LeafSchemaNode) {
1980                 emitRefineLeafNodes((LeafSchemaNode) value);
1981             } else if (value instanceof LeafListSchemaNode) {
1982                 emitRefineLeafListNodes((LeafListSchemaNode) value);
1983             } else if (value instanceof ListSchemaNode) {
1984                 emitRefineListNodes((ListSchemaNode) value);
1985             } else if (value instanceof ChoiceSchemaNode) {
1986                 emitRefineChoiceNodes((ChoiceSchemaNode) value);
1987             } else if (value instanceof ChoiceCaseNode) {
1988                 emitRefineCaseNodes((ChoiceCaseNode) value);
1989             } else if (value instanceof ContainerSchemaNode) {
1990                 emitRefineContainerNodes((ContainerSchemaNode) value);
1991             } else if (value instanceof AnyXmlSchemaNode) {
1992                 emitRefineAnyxmlNodes((AnyXmlSchemaNode) value);
1993             }
1994             super.writer.endNode();
1995
1996         }
1997
1998         private static <T extends SchemaNode> T getOriginalChecked(final T value) {
1999             final Optional<SchemaNode> original = SchemaNodeUtils.getOriginalIfPossible(value);
2000             Preconditions.checkArgument(original.isPresent(), "Original unmodified version of node is not present.");
2001             @SuppressWarnings("unchecked")
2002             final T ret = (T) original.get();
2003             return ret;
2004         }
2005
2006         private void emitDocumentedNodeRefine(final DocumentedNode original, final DocumentedNode value) {
2007             if (Objects.deepEquals(original.getDescription(), value.getDescription())) {
2008                 emitDescriptionNode(value.getDescription());
2009             }
2010             if (Objects.deepEquals(original.getReference(), value.getReference())) {
2011                 emitReferenceNode(value.getReference());
2012             }
2013         }
2014
2015         private void emitRefineContainerNodes(final ContainerSchemaNode value) {
2016             final ContainerSchemaNode original = getOriginalChecked(value);
2017
2018             // emitMustNodes(child.getConstraints().getMustConstraints());
2019             if (Objects.deepEquals(original.isPresenceContainer(), value.isPresenceContainer())) {
2020                 emitPresenceNode(value.isPresenceContainer());
2021             }
2022             if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
2023                 emitConfigNode(value.isConfiguration());
2024             }
2025             emitDocumentedNodeRefine(original, value);
2026
2027         }
2028
2029         private void emitRefineLeafNodes(final LeafSchemaNode value) {
2030             final LeafSchemaNode original = getOriginalChecked(value);
2031
2032             // emitMustNodes(child.getConstraints().getMustConstraints());
2033             if (Objects.deepEquals(original.getDefault(), value.getDefault())) {
2034                 emitDefaultNode(value.getDefault());
2035             }
2036             if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
2037                 emitConfigNode(value.isConfiguration());
2038             }
2039             emitDocumentedNodeRefine(original, value);
2040             if (Objects.deepEquals(original.getConstraints().isMandatory(), value.getConstraints().isMandatory())) {
2041                 emitMandatoryNode(value.getConstraints().isMandatory());
2042             }
2043
2044         }
2045
2046         private void emitRefineLeafListNodes(final LeafListSchemaNode value) {
2047             final LeafListSchemaNode original = getOriginalChecked(value);
2048
2049             // emitMustNodes(child.getConstraints().getMustConstraints());
2050             if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
2051                 emitConfigNode(value.isConfiguration());
2052             }
2053             if (Objects.deepEquals(original.getConstraints().getMinElements(),
2054                     value.getConstraints().getMinElements())) {
2055                 emitMinElementsNode(value.getConstraints().getMinElements());
2056             }
2057             if (Objects.deepEquals(original.getConstraints().getMaxElements(),
2058                     value.getConstraints().getMaxElements())) {
2059                 emitMaxElementsNode(value.getConstraints().getMaxElements());
2060             }
2061             emitDocumentedNodeRefine(original, value);
2062
2063         }
2064
2065         private void emitRefineListNodes(final ListSchemaNode value) {
2066             final ListSchemaNode original = getOriginalChecked(value);
2067
2068             // emitMustNodes(child.getConstraints().getMustConstraints());
2069             if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
2070                 emitConfigNode(value.isConfiguration());
2071             }
2072             if (Objects.deepEquals(original.getConstraints().getMinElements(),
2073                     value.getConstraints().getMinElements())) {
2074                 emitMinElementsNode(value.getConstraints().getMinElements());
2075             }
2076             if (Objects.deepEquals(original.getConstraints().getMaxElements(),
2077                     value.getConstraints().getMaxElements())) {
2078                 emitMaxElementsNode(value.getConstraints().getMaxElements());
2079             }
2080             emitDocumentedNodeRefine(original, value);
2081
2082         }
2083
2084         private void emitRefineChoiceNodes(final ChoiceSchemaNode value) {
2085             final ChoiceSchemaNode original = getOriginalChecked(value);
2086
2087             // FIXME: BUG-2444: defaultNode //FIXME: BUG-2444: Optional
2088             if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
2089                 emitConfigNode(value.isConfiguration());
2090             }
2091             if (Objects.deepEquals(original.getConstraints().isMandatory(), value.getConstraints().isMandatory())) {
2092                 emitMandatoryNode(value.getConstraints().isMandatory());
2093             }
2094             emitDocumentedNodeRefine(original, value);
2095
2096         }
2097
2098         private void emitRefineCaseNodes(final ChoiceCaseNode value) {
2099             final ChoiceCaseNode original = getOriginalChecked(value);
2100             emitDocumentedNodeRefine(original, value);
2101
2102         }
2103
2104         private void emitRefineAnyxmlNodes(final AnyXmlSchemaNode value) {
2105             final AnyXmlSchemaNode original = getOriginalChecked(value);
2106
2107             // FIXME: BUG-2444:
2108             // emitMustNodes(child.getConstraints().getMustConstraints());
2109             if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
2110                 emitConfigNode(value.isConfiguration());
2111             }
2112             if (Objects.deepEquals(original.getConstraints().isMandatory(), value.getConstraints().isMandatory())) {
2113                 emitMandatoryNode(value.getConstraints().isMandatory());
2114             }
2115             emitDocumentedNodeRefine(original, value);
2116
2117         }
2118
2119         private void emitUsesAugmentNode(final AugmentationSchemaNode aug) {
2120             /**
2121              * differs only in location in schema, otherwise currently (as of
2122              * RFC6020) it is same, so we could freely reuse path.
2123              */
2124             emitAugment(aug);
2125         }
2126
2127         private void emitAugment(final AugmentationSchemaNode augmentation) {
2128             super.writer.startAugmentNode(augmentation.getTargetPath());
2129             // FIXME: BUG-2444: whenNode //Optional
2130             // FIXME: BUG-2444: *(ifFeatureNode )
2131
2132             emitStatusNode(augmentation.getStatus());
2133             emitDescriptionNode(augmentation.getDescription());
2134             emitReferenceNode(augmentation.getReference());
2135             for (final UsesNode uses : augmentation.getUses()) {
2136                 emitUsesNode(uses);
2137             }
2138
2139             for (final DataSchemaNode childNode : augmentation.getChildNodes()) {
2140                 if (childNode instanceof ChoiceCaseNode) {
2141                     emitCaseNode((ChoiceCaseNode) childNode);
2142                 } else {
2143                     emitDataSchemaNode(childNode);
2144                 }
2145             }
2146             emitUnknownStatementNodes(augmentation.getUnknownSchemaNodes());
2147             emitNotifications(augmentation.getNotifications());
2148             emitActions(augmentation.getActions());
2149             super.writer.endNode();
2150         }
2151
2152         private void emitUnknownStatementNodes(final List<UnknownSchemaNode> unknownNodes) {
2153             for (final UnknownSchemaNode unknonwnNode : unknownNodes) {
2154                 if (!unknonwnNode.isAddedByAugmentation() && !unknonwnNode.isAddedByUses()) {
2155                     emitUnknownStatementNode(unknonwnNode);
2156                 }
2157             }
2158         }
2159
2160         private void emitUnknownStatementNode(final UnknownSchemaNode node) {
2161             final StatementDefinition def = getStatementChecked(node.getNodeType());
2162             if (def.getArgumentName() == null) {
2163                 super.writer.startUnknownNode(def);
2164             } else {
2165                 super.writer.startUnknownNode(def, node.getNodeParameter());
2166             }
2167             emitUnknownStatementNodes(node.getUnknownSchemaNodes());
2168             super.writer.endNode();
2169         }
2170
2171         private StatementDefinition getStatementChecked(final QName nodeType) {
2172             final StatementDefinition ret = super.extensions.get(nodeType);
2173             Preconditions.checkArgument(ret != null, "Unknown extension %s used during export.", nodeType);
2174             return ret;
2175         }
2176
2177         private void emitWhen(final RevisionAwareXPath revisionAwareXPath) {
2178             if (revisionAwareXPath != null) {
2179                 super.writer.startWhenNode(revisionAwareXPath);
2180                 super.writer.endNode();
2181             }
2182             // FIXME: BUG-2444: descriptionNode //FIXME: BUG-2444: Optional
2183             // FIXME: BUG-2444: referenceNode //FIXME: BUG-2444: Optional
2184             // FIXME: BUG-2444: super.writer.endNode();)
2185
2186         }
2187
2188         private void emitRpc(final RpcDefinition rpc) {
2189             super.writer.startRpcNode(rpc.getQName());
2190             emitOperationBody(rpc);
2191             super.writer.endNode();
2192         }
2193
2194         private void emitOperationBody(final OperationDefinition rpc) {
2195             // FIXME: BUG-2444: *(ifFeatureNode )
2196             emitStatusNode(rpc.getStatus());
2197             emitDescriptionNode(rpc.getDescription());
2198             emitReferenceNode(rpc.getReference());
2199
2200             for (final TypeDefinition<?> typedef : rpc.getTypeDefinitions()) {
2201                 emitTypedefNode(typedef);
2202             }
2203             for (final GroupingDefinition grouping : rpc.getGroupings()) {
2204                 emitGrouping(grouping);
2205             }
2206             emitInput(rpc.getInput());
2207             emitOutput(rpc.getOutput());
2208             emitUnknownStatementNodes(rpc.getUnknownSchemaNodes());
2209         }
2210
2211         private void emitActions(final Set<ActionDefinition> actions) {
2212             for (final ActionDefinition actionDefinition : actions) {
2213                 emitAction(actionDefinition);
2214             }
2215         }
2216
2217         private void emitAction(final ActionDefinition action) {
2218             if (!super.emitInstantiated && (action.isAddedByUses() || action.isAugmenting())) {
2219                 // We skip instantiated nodes.
2220                 return;
2221             }
2222             super.writer.startActionNode(action.getQName());
2223             emitOperationBody(action);
2224             super.writer.endNode();
2225         }
2226
2227         private void emitInput(@Nonnull final ContainerSchemaNode input) {
2228             if (isExplicitStatement(input)) {
2229                 super.writer.startInputNode();
2230                 emitConstraints(input.getConstraints());
2231                 emitDataNodeContainer(input);
2232                 emitUnknownStatementNodes(input.getUnknownSchemaNodes());
2233                 super.writer.endNode();
2234             }
2235
2236         }
2237
2238         private void emitOutput(@Nonnull final ContainerSchemaNode output) {
2239             if (isExplicitStatement(output)) {
2240                 super.writer.startOutputNode();
2241                 emitConstraints(output.getConstraints());
2242                 emitDataNodeContainer(output);
2243                 emitUnknownStatementNodes(output.getUnknownSchemaNodes());
2244                 super.writer.endNode();
2245             }
2246         }
2247
2248         private static boolean isExplicitStatement(final ContainerSchemaNode node) {
2249             return node instanceof EffectiveStatement && ((EffectiveStatement<?, ?>) node).getDeclared()
2250                     .getStatementSource() == StatementSource.DECLARATION;
2251         }
2252
2253         private void emitNotifications(final Set<NotificationDefinition> notifications) {
2254             for (final NotificationDefinition notification : notifications) {
2255                 emitNotificationNode(notification);
2256             }
2257         }
2258
2259         private void emitNotificationNode(final NotificationDefinition notification) {
2260             if (!super.emitInstantiated && (notification.isAddedByUses() || notification.isAugmenting())) {
2261                 // We skip instantiated nodes.
2262                 return;
2263             }
2264
2265             super.writer.startNotificationNode(notification.getQName());
2266             // FIXME: BUG-2444: *(ifFeatureNode )
2267             emitConstraints(notification.getConstraints());
2268             emitDocumentedNode(notification);
2269             emitDataNodeContainer(notification);
2270             emitUnknownStatementNodes(notification.getUnknownSchemaNodes());
2271             super.writer.endNode();
2272
2273         }
2274
2275         private void emitDeviation(final Deviation deviation) {
2276             /*
2277              * FIXME: BUG-2444: Deviation is not modeled properly and we are
2278              * loosing lot of information in order to export it properly
2279              *
2280              * super.writer.startDeviationNode(deviation.getTargetPath());
2281              *
2282              * :descriptionNode //:Optional
2283              *
2284              *
2285              * emitReferenceNode(deviation.getReference());
2286              * :(deviateNotSupportedNode :1*(deviateAddNode :deviateReplaceNode
2287              * :deviateDeleteNode)) :super.writer.endNode();
2288              */
2289         }
2290     }
2291 }