Added XML examples generation.
authorTony Tkacik <ttkacik@cisco.com>
Wed, 27 Nov 2013 20:01:22 +0000 (21:01 +0100)
committerTony Tkacik <ttkacik@cisco.com>
Wed, 27 Nov 2013 20:01:22 +0000 (21:01 +0100)
Change-Id: I2953cd01501dd9e26dcb69d2de2a30ca493d145e
Signed-off-by: Tony Tkacik <ttkacik@cisco.com>
code-generator/maven-sal-api-gen-plugin/pom.xml
code-generator/maven-sal-api-gen-plugin/src/main/java/org/opendaylight/yangtools/yang/unified/doc/generator/GeneratorImpl.xtend

index 97fe5d27347e6cbf8a9c0152a8d2c33d20b33298..ed004151367715fbe3de283e22d4bda123664764 100644 (file)
@@ -1,4 +1,5 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 
     <parent>
         <artifactId>binding-generator</artifactId>
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>binding-java-api-generator</artifactId>
         </dependency>
+
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-data-api</artifactId>
+        </dependency>
+
+
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
index 27408f44a2918c97b89ecc402bd70f0c8282ab3a..97ee2d8d8a28af19331d0a6a34b79439c2e64e97 100644 (file)
-package org.opendaylight.yangtools.yang.unified.doc.generator
-
-import org.opendaylight.yangtools.yang.model.api.SchemaContext
-import java.io.File
-import java.util.Set
-import org.opendaylight.yangtools.yang.model.api.Module
-import java.io.IOException
-import java.util.HashSet
-import java.io.FileWriter
-import java.io.BufferedWriter
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
-import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
-import org.opendaylight.yangtools.yang.model.api.TypeDefinition
-import org.opendaylight.yangtools.yang.model.api.SchemaNode
-import org.opendaylight.yangtools.yang.model.util.ExtendedType
-import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition
-import java.text.SimpleDateFormat
-import java.util.Collection
-import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint
-import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition
-import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition
-import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint
-import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition
-import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition
-import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
-import org.opendaylight.yangtools.yang.model.api.DataNodeContainer
-import org.slf4j.LoggerFactory
-import org.slf4j.Logger
-import org.opendaylight.yangtools.yang.model.api.AugmentationSchema
-import java.util.List
-import org.opendaylight.yangtools.yang.common.QName
-import org.opendaylight.yangtools.yang.model.api.RpcDefinition
-import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition
-import java.util.ArrayList
-import java.util.Map
-import org.opendaylight.yangtools.yang.model.api.SchemaPath
-import java.util.LinkedHashMap
-import org.opendaylight.yangtools.yang.model.api.ChoiceNode
-import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode
-
-class GeneratorImpl {
-
-    File path
-    static val REVISION_FORMAT = new SimpleDateFormat("yyyy-MM-dd")
-    static val Logger LOG = LoggerFactory.getLogger(GeneratorImpl)
-
-
-    def generate(SchemaContext context, File targetPath, Set<Module> modulesToGen) throws IOException {
-        path = targetPath;
-        path.mkdirs();
-        val it = new HashSet;
-        for (module : modulesToGen) {
-            add(module.generateDocumentation());
-        }
-        return it;
-    }
-
-    def generateDocumentation(Module module) {
-        val destination = new File(path, '''«module.name».html''')
-        try {
-            val fw = new FileWriter(destination)
-            destination.createNewFile();
-            val bw = new BufferedWriter(fw)
-
-            bw.append(module.generate);
-            bw.close();
-            fw.close();
-        } catch (IOException e) {
-            LOG.error(e.getMessage());
-        }
-        return destination;
-    }
-
-    def generate(Module module) '''
-        <!DOCTYPE html>
-        <html lang="en">
-          <head>
-            <title>«module.name»</title>
-          </head>
-          <body>
-            «module.body»
-          </body>
-        </html>
-    '''
-
-    def body(Module module) '''
-        «header(module)»
-
-        «typeDefinitions(module)»
-
-        «identities(module)»
-
-        «groupings(module)»
-
-        «childNodes(module)»
-
-        «dataStore(module)»
-
-        «notifications(module)»
-
-        «augmentations(module)»
-
-        «rpcs(module)»
-
-        «extensions(module)»
-
-        «features(module)»
-
-    '''
-
-
-    def typeDefinitions(Module module) {
-        val Set<TypeDefinition<?>> typedefs = module.typeDefinitions
-        if (typedefs.empty) {
-            return '';
-        }
-        return '''
-            <h2>Type Definitions</h2>
-            <ul>
-            «FOR typedef : typedefs»
-                <li>
-                    «strong("typedef " + typedef.QName.localName)»
-                    <ul>
-                    «typedef.descAndRef»
-                    «typedef.restrictions»
-                    </ul>
-                </li>
-            «ENDFOR»
-            </ul>
-        '''
-    }
-
-    private def identities(Module module) {
-        if (module.identities.empty) {
-            return '';
-        }
-        return '''
-            <h2>Identities</h2>
-            <ul>
-            «FOR identity : module.identities»
-                <li>
-                    «strong("identity " + identity.QName.localName)»
-                    <ul>
-                    «identity.descAndRef»
-                    «IF identity.baseIdentity != null»
-                        «listItem("base", identity.baseIdentity.QName.localName)»
-                    «ENDIF»
-                    </ul>
-                </li>
-            «ENDFOR»
-            </ul>
-        '''
-    }
-
-    private def groupings(Module module) {
-        if (module.groupings.empty) {
-            return '';
-        }
-        return '''
-            <h2>Groupings</h2>
-            <ul>
-            «FOR grouping : module.groupings»
-                <li>
-                    «strong("grouping " + grouping.QName.localName)»
-                    <ul>
-                        «grouping.descAndRef»
-                    </ul>
-                </li>
-            «ENDFOR»
-            </ul>
-        '''
-    }
-
-    def dataStore(Module module) {
-        if (module.childNodes.empty) {
-            return '';
-        }
-        return '''
-            <h2>Datastore Structure</h2>
-            «tree(module)»
-        '''
-    }
-
-    def augmentations(Module module) {
-        if (module.augmentations.empty) {
-            return '';
-        }
-        return '''
-            <h2>Augmentations</h2>
-
-            <ul>
-            «FOR augment : module.augmentations»
-                <li>
-                    augment
-                    «augment.tree»
-                </li>
-            «ENDFOR»
-            </ul>
-        '''
-    }
-
-    def notifications(Module module) {
-        val Set<NotificationDefinition> notificationdefs = module.notifications
-        if (notificationdefs.empty) {
-            return '';
-        }
-        return '''
-            <h2>Notifications</h2>
-
-            <ul>
-            «FOR notificationdef : notificationdefs»
-                <li>
-                    «notificationdef.nodeName»
-                    «notificationdef.tree»
-                </li>
-            «ENDFOR»
-            </ul>
-        '''
-    }
-
-    def rpcs(Module module) {
-        if (module.rpcs.empty) {
-            return '';
-        }
-        return '''
-            <h2>RPC Definitions</h2>
-
-            <ul>
-            «FOR rpc : module.rpcs»
-                <li>
-                    «rpc.nodeName»
-                    «rpc.tree»
-                </li>
-            «ENDFOR»
-            </ul>
-        '''
-    }
-
-    def extensions(Module module) {
-        if (module.extensionSchemaNodes.empty) {
-            return '';
-        }
-        return '''
-            <h2>Extensions</h2>
-
-            <ul>
-            «FOR ext : module.extensionSchemaNodes»
-                <li>
-                    «ext.nodeName»
-                    «ext.tree»
-                </li>
-            «ENDFOR»
-            </ul>
-        '''
-    }
-
-    def features(Module module) {
-        if (module.features.empty) {
-            return '';
-        }
-        return '''
-            <h2>Features</h2>
-
-            <ul>
-            «FOR feature : module.features»
-                <li>
-                    «strong("feature " + feature.QName.localName)»
-                    <ul>
-                        «feature.descAndRef»
-                    </ul>
-                </li>
-            «ENDFOR»
-            </ul>
-        '''
-    }
-
-    def header(Module module) '''
-        <h1>«module.name»</h1>
-        
-        <h2>Base Information</h2>
-        <dl>
-            <dt>Prefix</dt>
-            <dd>«pre(module.prefix)»</dd>
-            <dt>Namespace</dt>
-            <dd>«pre(module.namespace.toString)»</dd>
-            <dt>Revision</dt>
-            <dd>«pre(REVISION_FORMAT.format(module.revision))»</dd>
-            
-            «FOR imp : module.imports BEFORE "<dt>Imports</dt>" »
-                <dd>«pre(imp.prefix)» = «pre(imp.moduleName)»</dd>
-            «ENDFOR»
-        </dl>
-    '''
-
-    def process(Module module) {
-        throw new UnsupportedOperationException("TODO: auto-generated method stub")
-    }
-
-
-
-    /* #################### TREE STRUCTURE #################### */
-    def dispatch CharSequence tree(Module module) '''
-        «strong("module " + module.name)»
-        «module.childNodes.tree»
-    '''
-
-    def dispatch CharSequence tree(DataNodeContainer node) '''
-        «IF node instanceof SchemaNode»
-            «(node as SchemaNode).nodeName»
-        «ENDIF»
-        «node.childNodes.tree»
-    '''
-
-    def dispatch CharSequence tree(DataSchemaNode node) '''
-        «node.nodeName»
-    '''
-
-    def dispatch CharSequence tree(ListSchemaNode node) '''
-        «node.nodeName»
-        «node.childNodes.tree»
-    '''
-
-    def CharSequence childNodes(Module module) '''
-        «val Map<SchemaPath, DataSchemaNode> childNodes = new LinkedHashMap()»
-        «collectChildNodes(module.childNodes, childNodes)»
-        «IF childNodes !== null && !childNodes.empty»
-            <h2>Child nodes</h2>
-
-            «childNodes.childNodesInfoTree»
-        «ENDIF»
-    '''
-
-    def CharSequence childNodesInfoTree(Map<SchemaPath, DataSchemaNode> childNodes) '''
-        «IF childNodes !== null && !childNodes.empty»
-            <ul>
-            «FOR child : childNodes.values»
-                «childInfo(child, childNodes)»
-            «ENDFOR»
-            </ul>
-        «ENDIF»
-    '''
-
-    def CharSequence childInfo(DataSchemaNode node, Map<SchemaPath, DataSchemaNode> childNodes) '''
-        «val String path = nodeSchemaPathToPath(node, childNodes)»
-        «IF path != null»
-            «listItem(strong(path))»
-                «IF node !== null»
-                <ul>
-                «node.descAndRef»
-                </ul>
-            «ENDIF»
-        «ENDIF»
-    '''
-
-    def dispatch CharSequence tree(Collection<DataSchemaNode> childNodes) '''
-        «IF childNodes !== null && !childNodes.empty»
-            <ul>
-            «FOR child : childNodes»
-                <li>
-                    «child.tree»
-                </li>
-            «ENDFOR»
-            </ul>
-        «ENDIF»
-    '''
-
-    def listKeys(ListSchemaNode node) '''
-        [«FOR key : node.keyDefinition SEPARATOR " "»«key.localName»«ENDFOR»]
-    '''
-
-    def dispatch CharSequence tree(AugmentationSchema augment) '''
-        <ul>
-            «listItem(augment.description)»
-            «listItem("Reference", augment.reference)»
-            «IF augment.whenCondition !== null»
-                «listItem("When", augment.whenCondition.toString)»
-            «ENDIF»
-            <li>
-                Path «augment.targetPath.path.pathToTree»
-            </li>
-            <li>
-                Child nodes
-                «augment.childNodes.tree»
-            </li>
-        </ul>
-    '''
-
-    def dispatch CharSequence tree(NotificationDefinition notification) '''
-        <ul>
-            «notification.descAndRef»
-            <li>
-                Child nodes
-                «notification.childNodes.tree»
-            </li>
-        </ul>
-    '''
-
-    def dispatch CharSequence tree(RpcDefinition rpc) '''
-        <ul>
-            «rpc.descAndRef»
-            <li>
-                «rpc.input.tree»
-            </li>
-            <li>
-                «rpc.output.tree»
-            </li>
-        </ul>
-    '''
-
-    def dispatch CharSequence tree(ExtensionDefinition ext) '''
-        <ul>
-            «ext.descAndRef»
-            «listItem("Argument", ext.argument)»
-        </ul>
-    '''
-
-    def dispatch CharSequence tree(Void obj) '''
-    '''
-
-
-
-    /* #################### RESTRICTIONS #################### */
-    private def restrictions(TypeDefinition<?> type) '''
-        «type.toLength»
-        «type.toRange»
-    '''
-
-    def dispatch toLength(TypeDefinition<?> type) {
-    }
-
-    def dispatch toLength(BinaryTypeDefinition type) '''
-        «type.lengthConstraints.toLengthStmt»
-    '''
-
-    def dispatch toLength(StringTypeDefinition type) '''
-        «type.lengthConstraints.toLengthStmt»
-    '''
-
-    def dispatch toLength(ExtendedType type) '''
-        «type.lengthConstraints.toLengthStmt»
-    '''
-
-    def dispatch toRange(TypeDefinition<?> type) {
-    }
-
-    def dispatch toRange(DecimalTypeDefinition type) '''
-        «type.rangeConstraints.toRangeStmt»
-    '''
-
-    def dispatch toRange(IntegerTypeDefinition type) '''
-        «type.rangeConstraints.toRangeStmt»
-    '''
-
-    def dispatch toRange(UnsignedIntegerTypeDefinition type) '''
-        «type.rangeConstraints.toRangeStmt»
-    '''
-
-    def dispatch toRange(ExtendedType type) '''
-        «type.rangeConstraints.toRangeStmt»
-    '''
-
-    def toLengthStmt(Collection<LengthConstraint> lengths) '''
-        «IF lengths != null && !lengths.empty»
-            «listItem("Length restrictions")»
-            <ul>
-            «FOR length : lengths»
-                <li>
-                «IF length.min == length.max»
-                    «length.min»
-                «ELSE»
-                    &lt;«length.min», «length.max»&gt;
-                «ENDIF»
-                </li>
-            «ENDFOR»
-            </ul>
-        «ENDIF»
-    '''
-
-    def toRangeStmt(Collection<RangeConstraint> ranges) '''
-        «IF ranges != null && !ranges.empty»
-            «listItem("Range restrictions")»
-            <ul>
-            «FOR range : ranges»
-                <li>
-                «IF range.min == range.max»
-                    «range.min»
-                «ELSE»
-                    &lt;«range.min», «range.max»&gt;
-                «ENDIF»
-                </li>
-            «ENDFOR»
-            </ul>
-        «ENDIF»
-    '''
-
-
-
-    /* #################### UTILITY #################### */
-    private def String strong(String str) '''<strong>«str»</strong>'''
-    private def italic(String str) '''<i>«str»</i>'''
-    private def pre(String str) '''<pre>«str»</pre>'''
-
-    def CharSequence descAndRef(SchemaNode node) '''
-        «listItem(node.description)»
-        «listItem("Reference", node.reference)»
-    '''
-
-    private def listItem(String value) '''
-        «IF value !== null && !value.empty»
-            <li>
-                «value»
-            </li>
-        «ENDIF»
-    '''
-
-    private def listItem(String name, String value) '''
-        «IF value !== null && !value.empty»
-            <li>
-                «name»
-                <ul>
-                    <li>
-                        «value»
-                    </li>
-                </ul>
-            </li>
-        «ENDIF»
-    '''
-
-    private def String nodeSchemaPathToPath(DataSchemaNode node, Map<SchemaPath, DataSchemaNode> childNodes) {
-        if (node instanceof ChoiceNode || node instanceof ChoiceCaseNode) {
-            return null
-        }
-
-        val path = node.path.path
-        val absolute = node.path.absolute;
-        var StringBuilder result = new StringBuilder
-        if (absolute) {
-            result.append("/")
-        }
-        if (path !== null && !path.empty) {
-            val List<QName> actual = new ArrayList()
-            var i = 0;
-            for (pathElement : path) {
-                actual.add(pathElement)
-                val DataSchemaNode nodeByPath = childNodes.get(new SchemaPath(actual, absolute)) 
-                if (!(nodeByPath instanceof ChoiceNode) && !(nodeByPath instanceof ChoiceCaseNode)) {
-                    result.append(pathElement.localName)
-                    if (i != path.size - 1) {
-                        result.append("/")
-                    }
-                }
-                i = i + 1
-            }
-        }
-        return result.toString
-    }
-
-    private def void collectChildNodes(Collection<DataSchemaNode> source, Map<SchemaPath, DataSchemaNode> destination) {
-        for (node : source) {
-            destination.put(node.path, node)
-            if (node instanceof DataNodeContainer) {
-                collectChildNodes((node as DataNodeContainer).childNodes, destination)
-            }
-            if (node instanceof ChoiceNode) {
-                val List<DataSchemaNode> choiceCases = new ArrayList()
-                for (caseNode : (node as ChoiceNode).cases) {
-                    choiceCases.add(caseNode)
-                }
-                collectChildNodes(choiceCases, destination)
-            }
-        }
-    }
-
-    private def CharSequence pathToTree(List<QName> path) '''
-        «IF path !== null && !path.empty»
-            <ul>
-            «FOR pathElement : path»
-                <li>
-                    «pathElement.namespace» «pathElement.localName»
-                </li>
-            «ENDFOR»
-            </ul>
-        «ENDIF»
-    '''
-
-    def dispatch addedByInfo(SchemaNode node) '''
-    '''
-
-    def dispatch addedByInfo(DataSchemaNode node) '''
-        «IF node.augmenting»(A)«ENDIF»«IF node.addedByUses»(U)«ENDIF»
-    '''
-
-    def dispatch isAddedBy(SchemaNode node) {
-        return false;
-    }
-
-    def dispatch isAddedBy(DataSchemaNode node) {
-        if (node.augmenting || node.addedByUses) {
-            return true
-        } else {
-            return false;
-        }
-    }
-
-    def dispatch nodeName(SchemaNode node) '''
-        «IF node.isAddedBy»
-            «italic(node.QName.localName)»«node.addedByInfo»
-        «ELSE»
-            «strong(node.QName.localName)»«node.addedByInfo»
-        «ENDIF»
-    '''
-
-    def dispatch nodeName(ListSchemaNode node) '''
-        «IF node.isAddedBy»
-            «italic(node.QName.localName)» «IF node.keyDefinition !== null && !node.keyDefinition.empty»«node.listKeys»«ENDIF»«node.addedByInfo»
-        «ELSE»
-            «strong(node.QName.localName)» «IF node.keyDefinition !== null && !node.keyDefinition.empty»«node.listKeys»«ENDIF»
-        «ENDIF»
-    '''
-
-}
+package org.opendaylight.yangtools.yang.unified.doc.generator\r
+\r
+import org.opendaylight.yangtools.yang.model.api.SchemaContext\r
+import java.io.File\r
+import java.util.Set\r
+import org.opendaylight.yangtools.yang.model.api.Module\r
+import java.io.IOException\r
+import java.util.HashSet\r
+import java.io.FileWriter\r
+import java.io.BufferedWriter\r
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode\r
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode\r
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition\r
+import org.opendaylight.yangtools.yang.model.api.SchemaNode\r
+import org.opendaylight.yangtools.yang.model.util.ExtendedType\r
+import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition\r
+import java.text.SimpleDateFormat\r
+import java.util.Collection\r
+import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint\r
+import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition\r
+import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition\r
+import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint\r
+import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition\r
+import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition\r
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition\r
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer\r
+import org.slf4j.LoggerFactory\r
+import org.slf4j.Logger\r
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema\r
+import java.util.List\r
+import org.opendaylight.yangtools.yang.common.QName\r
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition\r
+import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition\r
+import java.util.ArrayList\r
+import java.util.Map\r
+import org.opendaylight.yangtools.yang.model.api.SchemaPath\r
+\r
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode\r
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode\r
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode\r
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier\r
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates\r
+import java.util.LinkedHashMap\r
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier\r
+import com.google.common.collect.FluentIterable\r
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode\r
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode\r
+import java.net.URLEncoder\r
+import javax.swing.text.StyledEditorKit.ForegroundAction\r
+\r
+class GeneratorImpl {\r
+\r
+    File path\r
+    static val REVISION_FORMAT = new SimpleDateFormat("yyyy-MM-dd")\r
+    static val Logger LOG = LoggerFactory.getLogger(GeneratorImpl)\r
+    var Module currentModule;\r
+\r
+\r
+    def generate(SchemaContext context, File targetPath, Set<Module> modulesToGen) throws IOException {\r
+        path = targetPath;\r
+        path.mkdirs();\r
+        val it = new HashSet;\r
+        for (module : modulesToGen) {\r
+            add(module.generateDocumentation());\r
+        }\r
+        return it;\r
+    }\r
+\r
+    def generateDocumentation(Module module) {\r
+        val destination = new File(path, '''«module.name».html''')\r
+        try {\r
+            val fw = new FileWriter(destination)\r
+            destination.createNewFile();\r
+            val bw = new BufferedWriter(fw)\r
+            currentModule = module;\r
+            bw.append(module.generate);\r
+            bw.close();\r
+            fw.close();\r
+        } catch (IOException e) {\r
+            LOG.error(e.getMessage());\r
+        }\r
+        return destination;\r
+    }\r
+\r
+    def generate(Module module) '''\r
+        <!DOCTYPE html>\r
+        <html lang="en">\r
+          <head>\r
+            <title>«module.name»</title>\r
+          </head>\r
+          <body>\r
+            «module.body»\r
+          </body>\r
+        </html>\r
+    '''\r
+\r
+    def body(Module module) '''\r
+        «header(module)»\r
+\r
+        «typeDefinitions(module)»\r
+\r
+        «identities(module)»\r
+\r
+        «groupings(module)»\r
+\r
+        «dataStore(module)»\r
+\r
+        «childNodes(module)»\r
+\r
+        «notifications(module)»\r
+\r
+        «augmentations(module)»\r
+\r
+        «rpcs(module)»\r
+\r
+        «extensions(module)»\r
+\r
+        «features(module)»\r
+\r
+    '''\r
+\r
+\r
+    def typeDefinitions(Module module) {\r
+        val Set<TypeDefinition<?>> typedefs = module.typeDefinitions\r
+        if (typedefs.empty) {\r
+            return '';\r
+        }\r
+        return '''\r
+            <h2>Type Definitions</h2>\r
+            <ul>\r
+            «FOR typedef : typedefs»\r
+                <li>\r
+                    «strong("typedef " + typedef.QName.localName)»\r
+                    <ul>\r
+                    «typedef.descAndRef»\r
+                    «typedef.restrictions»\r
+                    </ul>\r
+                </li>\r
+            «ENDFOR»\r
+            </ul>\r
+        '''\r
+    }\r
+\r
+    private def identities(Module module) {\r
+        if (module.identities.empty) {\r
+            return '';\r
+        }\r
+        return '''\r
+            <h2>Identities</h2>\r
+            <ul>\r
+            «FOR identity : module.identities»\r
+                <li>\r
+                    «strong("identity " + identity.QName.localName)»\r
+                    <ul>\r
+                    «identity.descAndRef»\r
+                    «IF identity.baseIdentity != null»\r
+                        «listItem("base", identity.baseIdentity.QName.localName)»\r
+                    «ENDIF»\r
+                    </ul>\r
+                </li>\r
+            «ENDFOR»\r
+            </ul>\r
+        '''\r
+    }\r
+\r
+    private def groupings(Module module) {\r
+        if (module.groupings.empty) {\r
+            return '';\r
+        }\r
+        return '''\r
+            <h2>Groupings</h2>\r
+            <ul>\r
+            «FOR grouping : module.groupings»\r
+                <li>\r
+                    «strong("grouping " + grouping.QName.localName)»\r
+                    <ul>\r
+                        «grouping.descAndRef»\r
+                    </ul>\r
+                </li>\r
+            «ENDFOR»\r
+            </ul>\r
+        '''\r
+    }\r
+\r
+    def dataStore(Module module) {\r
+        if (module.childNodes.empty) {\r
+            return '';\r
+        }\r
+        return '''\r
+            <h2>Datastore Structure</h2>\r
+            «tree(module)»\r
+        '''\r
+    }\r
+\r
+    def augmentations(Module module) {\r
+        if (module.augmentations.empty) {\r
+            return '';\r
+        }\r
+        return '''\r
+            <h2>Augmentations</h2>\r
+\r
+            <ul>\r
+            «FOR augment : module.augmentations»\r
+                <li>\r
+                    augment\r
+                    «augment.augmentationInfo(InstanceIdentifier.builder().toInstance())»\r
+                </li>\r
+            «ENDFOR»\r
+            </ul>\r
+        '''\r
+    }\r
+\r
+    def notifications(Module module) {\r
+        val Set<NotificationDefinition> notificationdefs = module.notifications\r
+        if (notificationdefs.empty) {\r
+            return '';\r
+        }\r
+        \r
+        return '''\r
+            <h2>Notifications</h2>\r
+            «FOR notificationdef : notificationdefs»\r
+                \r
+                <h3>«notificationdef.nodeName»</h3>\r
+                    «notificationdef.notificationInfo(InstanceIdentifier.builder().node(notificationdef.QName).toInstance())»\r
+            «ENDFOR»\r
+        '''\r
+    }\r
+\r
+    def rpcs(Module module) {\r
+        if (module.rpcs.empty) {\r
+            return '';\r
+        }\r
+        \r
+        return '''\r
+            <h2>RPC Definitions</h2>\r
+            «FOR rpc : module.rpcs»\r
+                <h3>«rpc.nodeName»</h3>\r
+                    «rpc.rpcInfo(InstanceIdentifier.builder().node(rpc.QName).toInstance())»\r
+            «ENDFOR»\r
+            </ul>\r
+        '''\r
+    }\r
+\r
+    def extensions(Module module) {\r
+        if (module.extensionSchemaNodes.empty) {\r
+            return '';\r
+        }\r
+        return '''\r
+            <h2>Extensions</h2>\r
+            «FOR ext : module.extensionSchemaNodes»\r
+                <li>\r
+                    <h3>«ext.nodeName»</h3>\r
+                </li>\r
+            «ENDFOR»\r
+        '''\r
+    }\r
+\r
+    def features(Module module) {\r
+        if (module.features.empty) {\r
+            return '';\r
+        }\r
+        return '''\r
+            <h2>Features</h2>\r
+\r
+            <ul>\r
+            «FOR feature : module.features»\r
+                <li>\r
+                    «strong("feature " + feature.QName.localName)»\r
+                    <ul>\r
+                        «feature.descAndRef»\r
+                    </ul>\r
+                </li>\r
+            «ENDFOR»\r
+            </ul>\r
+        '''\r
+    }\r
+\r
+    def header(Module module) '''\r
+        <h1>«module.name»</h1>\r
+        \r
+        <h2>Base Information</h2>\r
+        <dl>\r
+            <dt>Prefix</dt>\r
+            <dd>«pre(module.prefix)»</dd>\r
+            <dt>Namespace</dt>\r
+            <dd>«pre(module.namespace.toString)»</dd>\r
+            <dt>Revision</dt>\r
+            <dd>«pre(REVISION_FORMAT.format(module.revision))»</dd>\r
+            \r
+            «FOR imp : module.imports BEFORE "<dt>Imports</dt>" »\r
+                <dd>«code(imp.prefix)» = «code(imp.moduleName)»</dd>\r
+            «ENDFOR»\r
+        </dl>\r
+    '''\r
+    \r
+    def code(String string) '''<code>«string»</code>'''\r
+        \r
+    def process(Module module) {\r
+        throw new UnsupportedOperationException("TODO: auto-generated method stub")\r
+    }\r
+\r
+    def CharSequence tree(Module module) '''\r
+        «strong("module " + module.name)»\r
+        «module.childNodes.treeSet(InstanceIdentifier.builder.toInstance())»\r
+    '''\r
+    \r
+    private def dispatch CharSequence tree(ChoiceNode node,InstanceIdentifier path) '''\r
+        «node.nodeName» (choice)\r
+        «casesTree(node.cases,path)»\r
+    '''\r
+    \r
+    def casesTree(Set<ChoiceCaseNode> nodes,InstanceIdentifier path) '''\r
+        <ul>\r
+        «FOR node : nodes»\r
+            <li>\r
+            «node.nodeName»\r
+            «node.childNodes.treeSet(path)»\r
+            </li>\r
+        «ENDFOR»\r
+        </ul>\r
+    '''\r
+\r
+    private def dispatch CharSequence tree(DataSchemaNode node,InstanceIdentifier path) '''\r
+        «node.nodeName»\r
+    '''\r
+\r
+    private def dispatch CharSequence tree(ListSchemaNode node,InstanceIdentifier path) '''\r
+        «val newPath = path.append(node)»\r
+        «localLink(newPath,node.nodeName)»\r
+        «node.childNodes.treeSet(newPath)»\r
+    '''\r
+    \r
+    private def dispatch CharSequence tree(ContainerSchemaNode node,InstanceIdentifier path) '''\r
+        «val newPath = path.append(node)»\r
+        «localLink(newPath,node.nodeName)»\r
+        «node.childNodes.treeSet(newPath)»\r
+    '''\r
+\r
+    def CharSequence childNodes(Module module) '''\r
+        «val childNodes = module.childNodes»\r
+        «IF childNodes !== null && !childNodes.empty»\r
+            <h2>Child nodes</h2>\r
+\r
+            «childNodes.printChildren(2,InstanceIdentifier.builder().toInstance())»\r
+        «ENDIF»\r
+    '''\r
+    \r
+    def CharSequence printChildren(Set<DataSchemaNode> nodes, int level, InstanceIdentifier path) {\r
+    val leafNodes = nodes.filter(LeafSchemaNode)\r
+    val leafListNodes = nodes.filter(LeafListSchemaNode)\r
+    val choices = nodes.filter(ChoiceNode)\r
+    val containers = nodes.filter(ContainerSchemaNode)\r
+    val lists = nodes.filter(ListSchemaNode)\r
+    return '''\r
+        <h3>Direct children</h3>\r
+        <ul>\r
+        «FOR childNode : leafNodes»\r
+            «childNode.printShortInfo(level,path)»\r
+        «ENDFOR»\r
+        «FOR childNode : leafListNodes»\r
+            «childNode.printShortInfo(level,path)»\r
+        «ENDFOR»\r
+        «FOR childNode : containers»\r
+            «childNode.printShortInfo(level,path)»\r
+        «ENDFOR»\r
+        «FOR childNode : lists»\r
+            «childNode.printShortInfo(level,path)»\r
+        «ENDFOR»\r
+        </ul>\r
+        \r
+        «IF !path.path.empty»\r
+        <h3>XML example</h3>\r
+        «nodes.xmlExample(path.path.last.nodeType,path)»\r
+        </h3>\r
+        «ENDIF»\r
+        «FOR childNode : containers»\r
+            «childNode.printInfo(level,path)»\r
+        «ENDFOR»\r
+        «FOR childNode : lists»\r
+            «childNode.printInfo(level,path)»\r
+        «ENDFOR»\r
+        \r
+    '''\r
+    }\r
+    \r
+    def CharSequence xmlExample(Set<DataSchemaNode> nodes, QName name,InstanceIdentifier path) '''\r
+    <pre>\r
+        «xmlExampleTag(name,nodes.xmplExampleTags(path))»\r
+    </pre>\r
+    '''\r
+    \r
+    def CharSequence xmplExampleTags(Set<DataSchemaNode> nodes, InstanceIdentifier identifier) '''\r
+        <!-- Child nodes -->\r
+        «FOR node : nodes»\r
+        <!-- «node.QName.localName» -->\r
+            «node.asXmlExampleTag(identifier)»\r
+        «ENDFOR»\r
+        \r
+    '''\r
+    \r
+    private def dispatch CharSequence asXmlExampleTag(LeafSchemaNode node, InstanceIdentifier identifier) '''\r
+        «node.QName.xmlExampleTag("...")»\r
+    '''\r
+    \r
+    private def dispatch CharSequence asXmlExampleTag(LeafListSchemaNode node, InstanceIdentifier identifier) '''\r
+        &lt!-- This node could appear multiple times --&gt\r
+        «node.QName.xmlExampleTag("...")»\r
+    '''\r
+    \r
+    private def dispatch CharSequence asXmlExampleTag(ContainerSchemaNode node, InstanceIdentifier identifier) '''\r
+        &lt!-- See «localLink(identifier.append(node),"definition")» for child nodes.  --&gt\r
+        «node.QName.xmlExampleTag("...")»\r
+    '''\r
+    \r
+    \r
+    private def dispatch CharSequence asXmlExampleTag(ListSchemaNode node, InstanceIdentifier identifier) '''\r
+        &lt!-- See «localLink(identifier.append(node),"definition")» for child nodes.  --&gt\r
+        &lt!-- This node could appear multiple times --&gt\r
+        «node.QName.xmlExampleTag("...")»\r
+    '''\r
+    \r
+    \r
+    private def dispatch CharSequence asXmlExampleTag(DataSchemaNode node, InstanceIdentifier identifier) '''\r
+        <!-- noop -->\r
+    '''\r
+    \r
+    \r
+    def xmlExampleTag(QName name, CharSequence data) {\r
+        return '''&lt;«name.localName» xmlns="«name.namespace»"&gt;«data»&lt;/«name.localName»&gt;'''\r
+    }\r
+    \r
+    private def dispatch CharSequence printInfo(ContainerSchemaNode node, int level, InstanceIdentifier path) '''\r
+        «val newPath = path.append(node)»\r
+        «header(level,newPath)»\r
+        <dl>\r
+          <dt>XML Path</dt>\r
+          <dd>«newPath.asXmlPath»</dd>\r
+          <dt>Restconf path</dt>\r
+          <dd>«code(newPath.asRestconfPath)»</dd>\r
+        </dl>\r
+        «node.childNodes.printChildren(level,newPath)»\r
+    '''\r
+    \r
+    def header(int level,QName name) '''<h«level»>«name.localName»</h«level»>'''\r
+    \r
+    \r
+    def header(int level,InstanceIdentifier name) \r
+        '''\r
+        <h«level» id="«FOR cmp : name.path SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»">\r
+            «FOR cmp : name.path SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»\r
+        </h«level»>'''\r
+    \r
+    \r
+    private def dispatch CharSequence printInfo(ListSchemaNode node, int level, InstanceIdentifier path) '''\r
+        «val newPath = path.append(node)»\r
+        «header(level,newPath)»\r
+        <dl>\r
+          <dt>XML Path</dt>\r
+          <dd>«newPath.asXmlPath»</dd>\r
+          <dt>Restconf path</dt>\r
+          <dd>«code(newPath.asRestconfPath)»</dd>\r
+        </dl>\r
+        «node.childNodes.printChildren(level,newPath)»\r
+    '''\r
+    \r
+    def CharSequence printShortInfo(ContainerSchemaNode node, int level, InstanceIdentifier path) {\r
+        val newPath = path.append(node);\r
+        return '''\r
+            <li>«strong(localLink(newPath,node.QName.localName))» (container)</li>\r
+        '''\r
+    }\r
+    \r
+    def CharSequence printShortInfo(ListSchemaNode node, int level, InstanceIdentifier path) {\r
+        val newPath = path.append(node);\r
+        return '''\r
+            <li>«strong(localLink(newPath,node.QName.localName))» (list)</li>\r
+        '''\r
+    }\r
+    \r
+    def CharSequence printShortInfo(LeafSchemaNode node, int level, InstanceIdentifier path) {\r
+        return '''\r
+            <li>«strong((node.QName.localName))» (leaf)</li>\r
+        '''\r
+    }\r
+    \r
+    def CharSequence printShortInfo(LeafListSchemaNode node, int level, InstanceIdentifier path) {\r
+        return '''\r
+            <li>«strong((node.QName.localName))» (leaf-list)</li>\r
+        '''\r
+    }\r
+    \r
+    def CharSequence localLink(InstanceIdentifier identifier, CharSequence text) '''\r
+        <a href="#«FOR cmp : identifier.path SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»">«text»</a>\r
+    '''\r
+    \r
+    \r
+    private def dispatch InstanceIdentifier append(InstanceIdentifier identifier, ContainerSchemaNode node) {\r
+        val pathArguments = new ArrayList(identifier.path)\r
+        pathArguments.add(new NodeIdentifier(node.QName));\r
+        return new InstanceIdentifier(pathArguments);\r
+    }\r
+    \r
+    private def dispatch InstanceIdentifier append(InstanceIdentifier identifier, ListSchemaNode node) {\r
+        val pathArguments = new ArrayList(identifier.path)\r
+        val keyValues = new LinkedHashMap<QName,Object>();\r
+        if(node.keyDefinition != null) {\r
+            for(definition : node.keyDefinition) {\r
+                keyValues.put(definition,new Object);\r
+            }\r
+        }\r
+        pathArguments.add(new NodeIdentifierWithPredicates(node.QName,keyValues));\r
+        return new InstanceIdentifier(pathArguments);\r
+    }\r
+    \r
+    \r
+    def asXmlPath(InstanceIdentifier identifier) {\r
+        return "";\r
+    }\r
+    \r
+    def asRestconfPath(InstanceIdentifier identifier) {\r
+        val it = new StringBuilder();\r
+        append(currentModule.name)\r
+        append(":")\r
+        var previous = false;\r
+        for(arg : identifier.path) {\r
+            if(previous) append("/")\r
+            append(arg.nodeType.localName);\r
+            previous = true;\r
+            if(arg instanceof NodeIdentifierWithPredicates) {\r
+                val nodeIdentifier = arg as NodeIdentifierWithPredicates;\r
+                for(qname : nodeIdentifier.keyValues.keySet) {\r
+                    append("/{");\r
+                    append(qname.localName)\r
+                    append("}")\r
+                }\r
+            }\r
+        }\r
+        \r
+        return it.toString;\r
+    }\r
+    \r
+    \r
+    private def dispatch CharSequence printInfo(DataSchemaNode node, int level, InstanceIdentifier path) '''\r
+        «header(level+1,node.QName)»\r
+    '''\r
+    \r
+\r
+\r
+\r
+\r
+    def CharSequence childNodesInfoTree(Map<SchemaPath, DataSchemaNode> childNodes) '''\r
+        «IF childNodes !== null && !childNodes.empty»\r
+            «FOR child : childNodes.values»\r
+                «childInfo(child, childNodes)»\r
+            «ENDFOR»\r
+        «ENDIF»\r
+    '''\r
+\r
+    def CharSequence childInfo(DataSchemaNode node, Map<SchemaPath, DataSchemaNode> childNodes) '''\r
+        «val String path = nodeSchemaPathToPath(node, childNodes)»\r
+        «IF path != null»\r
+            «code(path)»\r
+                «IF node !== null»\r
+                <ul>\r
+                «node.descAndRef»\r
+                </ul>\r
+            «ENDIF»\r
+        «ENDIF»\r
+    '''\r
+\r
+    private def CharSequence treeSet(Collection<DataSchemaNode> childNodes, InstanceIdentifier path) '''\r
+        «IF childNodes !== null && !childNodes.empty»\r
+            <ul>\r
+            «FOR child : childNodes»\r
+                <li>\r
+                    «child.tree(path)»\r
+                </li>\r
+            «ENDFOR»\r
+            </ul>\r
+        «ENDIF»\r
+    '''\r
+\r
+    def listKeys(ListSchemaNode node) '''\r
+        [«FOR key : node.keyDefinition SEPARATOR " "»«key.localName»«ENDFOR»]\r
+    '''\r
+\r
+    private def CharSequence augmentationInfo(AugmentationSchema augment, InstanceIdentifier path) '''\r
+        <ul>\r
+            «listItem(augment.description)»\r
+            «listItem("Reference", augment.reference)»\r
+            «IF augment.whenCondition !== null»\r
+                «listItem("When", augment.whenCondition.toString)»\r
+            «ENDIF»\r
+            <li>\r
+                Path «augment.targetPath.path.pathToTree»\r
+            </li>\r
+            <li>\r
+                Child nodes\r
+                «augment.childNodes.treeSet(path)»\r
+            </li>\r
+        </ul>\r
+    '''\r
+\r
+    private def CharSequence notificationInfo(NotificationDefinition notification,InstanceIdentifier path) '''\r
+        <ul>\r
+            «notification.descAndRef»\r
+            <li>\r
+                Child nodes\r
+                «notification.childNodes.treeSet(path)»\r
+            </li>\r
+        </ul>\r
+    '''\r
+\r
+    private def CharSequence rpcInfo(RpcDefinition rpc,InstanceIdentifier path) '''\r
+        <ul>\r
+            «rpc.descAndRef»\r
+            <li>\r
+                «rpc.input.tree(path)»\r
+            </li>\r
+            <li>\r
+                «rpc.output.tree(path)»\r
+            </li>\r
+        </ul>\r
+    '''\r
+\r
+    private def CharSequence extensionInfo(ExtensionDefinition ext, InstanceIdentifier path) '''\r
+        <ul>\r
+            «ext.descAndRef»\r
+            «listItem("Argument", ext.argument)»\r
+        </ul>\r
+    '''\r
+\r
+    private def dispatch CharSequence tree(Void obj, InstanceIdentifier path) '''\r
+    '''\r
+\r
+\r
+\r
+    /* #################### RESTRICTIONS #################### */\r
+    private def restrictions(TypeDefinition<?> type) '''\r
+        «type.toLength»\r
+        «type.toRange»\r
+    '''\r
+\r
+    private def dispatch toLength(TypeDefinition<?> type) {\r
+    }\r
+\r
+    private def dispatch toLength(BinaryTypeDefinition type) '''\r
+        «type.lengthConstraints.toLengthStmt»\r
+    '''\r
+\r
+    private def dispatch toLength(StringTypeDefinition type) '''\r
+        «type.lengthConstraints.toLengthStmt»\r
+    '''\r
+\r
+    private def dispatch toLength(ExtendedType type) '''\r
+        «type.lengthConstraints.toLengthStmt»\r
+    '''\r
+\r
+    private def dispatch toRange(TypeDefinition<?> type) {\r
+    }\r
+\r
+    private def dispatch toRange(DecimalTypeDefinition type) '''\r
+        «type.rangeConstraints.toRangeStmt»\r
+    '''\r
+\r
+    private def dispatch toRange(IntegerTypeDefinition type) '''\r
+        «type.rangeConstraints.toRangeStmt»\r
+    '''\r
+\r
+    private def dispatch toRange(UnsignedIntegerTypeDefinition type) '''\r
+        «type.rangeConstraints.toRangeStmt»\r
+    '''\r
+\r
+    private def dispatch toRange(ExtendedType type) '''\r
+        «type.rangeConstraints.toRangeStmt»\r
+    '''\r
+\r
+    def toLengthStmt(Collection<LengthConstraint> lengths) '''\r
+        «IF lengths != null && !lengths.empty»\r
+            «listItem("Length restrictions")»\r
+            <ul>\r
+            «FOR length : lengths»\r
+                <li>\r
+                «IF length.min == length.max»\r
+                    «length.min»\r
+                «ELSE»\r
+                    &lt;«length.min», «length.max»&gt;\r
+                «ENDIF»\r
+                </li>\r
+            «ENDFOR»\r
+            </ul>\r
+        «ENDIF»\r
+    '''\r
+\r
+    def toRangeStmt(Collection<RangeConstraint> ranges) '''\r
+        «IF ranges != null && !ranges.empty»\r
+            «listItem("Range restrictions")»\r
+            <ul>\r
+            «FOR range : ranges»\r
+                <li>\r
+                «IF range.min == range.max»\r
+                    «range.min»\r
+                «ELSE»\r
+                    &lt;«range.min», «range.max»&gt;\r
+                «ENDIF»\r
+                </li>\r
+            «ENDFOR»\r
+            </ul>\r
+        «ENDIF»\r
+    '''\r
+\r
+\r
+\r
+    /* #################### UTILITY #################### */\r
+    private def String strong(CharSequence str) '''<strong>«str»</strong>'''\r
+    private def italic(CharSequence str) '''<i>«str»</i>'''\r
+    private def pre(CharSequence str) '''<pre>«str»</pre>'''\r
+\r
+    def CharSequence descAndRef(SchemaNode node) '''\r
+        «listItem(node.description)»\r
+        «listItem("Reference", node.reference)»\r
+    '''\r
+\r
+    private def listItem(String value) '''\r
+        «IF value !== null && !value.empty»\r
+            <li>\r
+                «value»\r
+            </li>\r
+        «ENDIF»\r
+    '''\r
+\r
+    private def listItem(String name, String value) '''\r
+        «IF value !== null && !value.empty»\r
+            <li>\r
+                «name»\r
+                <ul>\r
+                    <li>\r
+                        «value»\r
+                    </li>\r
+                </ul>\r
+            </li>\r
+        «ENDIF»\r
+    '''\r
+\r
+    private def String nodeSchemaPathToPath(DataSchemaNode node, Map<SchemaPath, DataSchemaNode> childNodes) {\r
+        if (node instanceof ChoiceNode || node instanceof ChoiceCaseNode) {\r
+            return null\r
+        }\r
+\r
+        val path = node.path.path\r
+        val absolute = node.path.absolute;\r
+        var StringBuilder result = new StringBuilder\r
+        if (absolute) {\r
+            result.append("/")\r
+        }\r
+        if (path !== null && !path.empty) {\r
+            val List<QName> actual = new ArrayList()\r
+            var i = 0;\r
+            for (pathElement : path) {\r
+                actual.add(pathElement)\r
+                val DataSchemaNode nodeByPath = childNodes.get(new SchemaPath(actual, absolute)) \r
+                if (!(nodeByPath instanceof ChoiceNode) && !(nodeByPath instanceof ChoiceCaseNode)) {\r
+                    result.append(pathElement.localName)\r
+                    if (i != path.size - 1) {\r
+                        result.append("/")\r
+                    }\r
+                }\r
+                i = i + 1\r
+            }\r
+        }\r
+        return result.toString\r
+    }\r
+\r
+    private def void collectChildNodes(Collection<DataSchemaNode> source, Map<SchemaPath, DataSchemaNode> destination) {\r
+        for (node : source) {\r
+            destination.put(node.path, node)\r
+            if (node instanceof DataNodeContainer) {\r
+                collectChildNodes((node as DataNodeContainer).childNodes, destination)\r
+            }\r
+            if (node instanceof ChoiceNode) {\r
+                val List<DataSchemaNode> choiceCases = new ArrayList()\r
+                for (caseNode : (node as ChoiceNode).cases) {\r
+                    choiceCases.add(caseNode)\r
+                }\r
+                collectChildNodes(choiceCases, destination)\r
+            }\r
+        }\r
+    }\r
+\r
+    private def CharSequence pathToTree(List<QName> path) '''\r
+        «IF path !== null && !path.empty»\r
+            <ul>\r
+            «FOR pathElement : path»\r
+                <li>\r
+                    «pathElement.namespace» «pathElement.localName»\r
+                </li>\r
+            «ENDFOR»\r
+            </ul>\r
+        «ENDIF»\r
+    '''\r
+\r
+    private def dispatch addedByInfo(SchemaNode node) '''\r
+    '''\r
+\r
+    private def dispatch addedByInfo(DataSchemaNode node) '''\r
+        «IF node.augmenting»(A)«ENDIF»«IF node.addedByUses»(U)«ENDIF»\r
+    '''\r
+\r
+    private def dispatch isAddedBy(SchemaNode node) {\r
+        return false;\r
+    }\r
+\r
+    private def dispatch isAddedBy(DataSchemaNode node) {\r
+        if (node.augmenting || node.addedByUses) {\r
+            return true\r
+        } else {\r
+            return false;\r
+        }\r
+    }\r
+\r
+    private def dispatch nodeName(SchemaNode node) '''\r
+        «IF node.isAddedBy»\r
+            «italic(node.QName.localName)»«node.addedByInfo»\r
+        «ELSE»\r
+            «node.QName.localName»«node.addedByInfo»\r
+        «ENDIF»\r
+    '''\r
+    \r
+    private def dispatch nodeName(ContainerSchemaNode node) '''\r
+        «IF node.isAddedBy»\r
+            «strong(italic(node.QName.localName))»«node.addedByInfo»\r
+        «ELSE»\r
+            «strong(node.QName.localName)»«node.addedByInfo»\r
+        «ENDIF»\r
+    '''\r
+\r
+    private def dispatch nodeName(ListSchemaNode node) '''\r
+        «IF node.isAddedBy»\r
+            «strong(italic(node.QName.localName))» «IF node.keyDefinition !== null && !node.keyDefinition.empty»«node.listKeys»«ENDIF»«node.addedByInfo»\r
+        «ELSE»\r
+            «strong(node.QName.localName)» «IF node.keyDefinition !== null && !node.keyDefinition.empty»«node.listKeys»«ENDIF»\r
+        «ENDIF»\r
+    '''\r
+\r
+}\r