+import org.opendaylight.yangtools.yang.model.api.AugmentationTarget
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
+import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition
+import org.opendaylight.yangtools.yang.model.api.GroupingDefinition
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
+import org.opendaylight.yangtools.yang.model.api.Module
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
+import org.opendaylight.yangtools.yang.model.api.SchemaContext
+import org.opendaylight.yangtools.yang.model.api.SchemaNode
+import org.opendaylight.yangtools.yang.model.api.SchemaPath
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition
+import org.opendaylight.yangtools.yang.model.api.UsesNode
+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.IntegerTypeDefinition
+import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint
+import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint
+import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition
+import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition
+import org.opendaylight.yangtools.yang.model.util.ExtendedType
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+import org.sonatype.plexus.build.incremental.BuildContext
+import org.sonatype.plexus.build.incremental.DefaultBuildContext
+
+class GeneratorImpl {
+
+ File path
+ static val REVISION_FORMAT = new SimpleDateFormat("yyyy-MM-dd")
+ static val Logger LOG = LoggerFactory.getLogger(GeneratorImpl)
+ static val BuildContext CTX = new DefaultBuildContext();
+ var Module currentModule;
+ val Map<String, String> imports = new HashMap();
+ var SchemaContext ctx;
+
+ StringBuilder augmentChildNodesAsString
+
+ DataSchemaNode lastNodeInTargetPath = null
+
+ def generate(SchemaContext context, File targetPath, Set<Module> modulesToGen) throws IOException {
+ path = targetPath;
+ path.mkdirs();
+ val it = new HashSet;
+ for (module : modulesToGen) {
+ add(generateDocumentation(module, context));
+ }
+ return it;
+ }
+
+ def generateDocumentation(Module module, SchemaContext ctx) {
+ val destination = new File(path, '''«module.name».html''')
+ this.ctx = ctx;
+ module.imports.forEach[importModule | this.imports.put(importModule.prefix, importModule.moduleName)]
+ try {
+ val fw = new OutputStreamWriter(CTX.newFileOutputStream(destination))
+ val bw = new BufferedWriter(fw)
+ currentModule = module;
+ bw.append(generate(module, ctx));
+ bw.close();
+ fw.close();
+ } catch (IOException e) {
+ LOG.error(e.getMessage());
+ }
+ return destination;
+ }
+
+ def generate(Module module, SchemaContext ctx) '''
+ <!DOCTYPE html>
+ <html lang="en">
+ <head>
+ <title>«module.name»</title>
+ </head>
+ <body>
+ «body(module, ctx)»
+ </body>
+ </html>
+ '''
+
+ def body(Module module, SchemaContext ctx) '''
+ «header(module)»
+
+ «typeDefinitionsSummary(module)»
+ «identitiesSummary(module)»
+ «groupingsSummary(module)»
+ «augmentationsSummary(module, ctx)»
+ «objectsSummary(module)»
+ «notificationsSummary(module)»
+ «rpcsSummary(module)»
+ «extensionsSummary(module)»
+ «featuresSummary(module)»
+
+ «typeDefinitions(module)»
+
+ «identities(module)»
+
+ «groupings(module)»
+
+ «dataStore(module)»
+
+ «childNodes(module)»
+
+ «notifications(module)»
+
+ «augmentations(module, ctx)»
+
+ «rpcs(module)»
+
+ «extensions(module)»
+
+ «features(module)»
+
+ '''
+
+
+ private def typeDefinitionsSummary(Module module) {
+ val Set<TypeDefinition<?>> typedefs = module.typeDefinitions
+ if (typedefs.empty) {
+ return '';
+ }
+ return '''
+ <div>
+ <h3>Type Definitions Summary</h3>
+ <table>
+ <tr>
+ <th>Name</th>
+ <th>Description</th>
+ </tr>
+ «FOR typedef : typedefs»
+ <tr>
+ <td>
+ «anchorLink(typedef.QName.localName, strong(typedef.QName.localName))»
+ </td>
+ <td>
+ «typedef.description»
+ </td>
+ </tr>
+ «ENDFOR»
+ </table>
+ </div>
+ '''
+ }
+
+ def typeDefinitions(Module module) {
+ val Set<TypeDefinition<?>> typedefs = module.typeDefinitions
+ if (typedefs.empty) {
+ return '';
+ }
+ return '''
+ <h2>Type Definitions</h2>
+ <ul>
+ «FOR typedef : typedefs»
+ <li>
+ <h3 id="«typedef.QName.localName»">«typedef.QName.localName»</h3>
+ <ul>
+ «typedef.descAndRefLi»
+ «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>
+ <h3 id="«identity.QName.localName»">«identity.QName.localName»</h3>
+ <ul>
+ «identity.descAndRefLi»
+ «IF identity.baseIdentity !== null»
+ «listItem("base", identity.baseIdentity.QName.localName)»
+ «ENDIF»
+ </ul>
+ </li>
+ «ENDFOR»
+ </ul>
+ '''
+ }
+
+ private def identitiesSummary(Module module) {
+ if (module.identities.empty) {
+ return '';
+ }
+ return '''
+ <h3>Identities Summary</h3>
+ <table>
+ <tr>
+ <th>Name</th>
+ <th>Description</th>
+ </tr>
+ «FOR identity : module.identities»
+ <tr>
+ <td>
+ «anchorLink(identity.QName.localName, strong(identity.QName.localName))»
+ </td>
+ <td>
+ «identity.description»
+ </td>
+ </tr>
+ «ENDFOR»
+ </table>
+ '''
+ }
+
+ private def groupings(Module module) {
+ if (module.groupings.empty) {
+ return '';
+ }
+ return '''
+ <h2>Groupings</h2>
+ <ul>
+ «FOR grouping : module.groupings»
+ <li>
+ <h3 id="«grouping.QName.localName»">«grouping.QName.localName»</h3>
+ <ul>
+ «grouping.descAndRefLi»
+ «FOR childNode : grouping.childNodes»
+ «childNode.printSchemaNodeInfo»
+ «ENDFOR»
+ </ul>
+ </li>
+ «ENDFOR»
+ </ul>
+ '''
+ }
+
+ private def groupingsSummary(Module module) {
+ if (module.groupings.empty) {
+ return '';
+ }
+ return '''
+ <h3>Groupings Summary</h3>
+ <table>
+ <tr>
+ <th>Name</th>
+ <th>Description</th>
+ </tr>
+ «FOR grouping : module.groupings»
+ <tr>
+ <td>
+ «anchorLink(grouping.QName.localName, strong(grouping.QName.localName))»
+ </td>
+ <td>
+ «grouping.description»
+ </td>
+ </tr>
+ «ENDFOR»
+ </table>
+ '''
+ }
+
+ def dataStore(Module module) {
+ if (module.childNodes.empty) {
+ return '';
+ }
+ return '''
+ <h2>Datastore Structure</h2>
+ «tree(module)»
+ '''
+ }
+
+ def augmentations(Module module, SchemaContext context) {
+ if (module.augmentations.empty) {
+ return '';
+ }
+ return '''
+ <h2>Augmentations</h2>
+
+ <ul>
+ «FOR augment : module.augmentations»
+ <li>
+ <h3 id="«schemaPathToString(module, augment.targetPath, context, augment)»">
+ Target [«typeAnchorLink(augment.targetPath,schemaPathToString(module, augment.targetPath, context, augment))»]</h3>
+ «augment.description»
+ Status: «strong(String.valueOf(augment.status))»
+ «IF augment.reference !== null»
+ Reference «augment.reference»
+ «ENDIF»
+ «IF augment.whenCondition !== null»
+ When «augment.whenCondition.toString»
+ «ENDIF»
+ «FOR childNode : augment.childNodes»
+ «childNode.printSchemaNodeInfo»
+ «ENDFOR»
+
+ <h3>Example</h3>
+ «createAugmentChildNodesAsString(new ArrayList(augment.childNodes))»
+ «printNodeChildren(parseTargetPath(augment.targetPath))»
+ </li>
+ «ENDFOR»
+ </ul>
+ '''
+ }
+
+ private def createAugmentChildNodesAsString(List<DataSchemaNode> childNodes) {
+ augmentChildNodesAsString = new StringBuilder();
+ augmentChildNodesAsString.append(printNodeChildren(childNodes))
+ return ''
+ }
+
+ private def parseTargetPath(SchemaPath path) {
+ val List<DataSchemaNode> nodes = new ArrayList<DataSchemaNode>();
+ for (QName pathElement : path.pathFromRoot) {
+ val module = ctx.findModuleByNamespaceAndRevision(pathElement.namespace, pathElement.revision);
+ if (module !== null) {
+ var foundNode = module.getDataChildByName(pathElement)
+ if(foundNode == null) {
+ val child = nodes.last
+ if (child instanceof DataNodeContainer) {
+ val dataContNode = child as DataNodeContainer
+ foundNode = findNodeInChildNodes(pathElement, dataContNode.childNodes)
+ }
+ }
+ if(foundNode != null) {
+ nodes.add(foundNode);
+ }
+ }
+ }
+ if(! nodes.empty) {
+ lastNodeInTargetPath = nodes.get(nodes.size() - 1)
+ }
+
+ val List<DataSchemaNode> targetPathNodes = new ArrayList<DataSchemaNode>();
+ targetPathNodes.add(lastNodeInTargetPath)
+
+ return targetPathNodes
+ }
+
+ private def DataSchemaNode findNodeInChildNodes(QName findingNode, Iterable<DataSchemaNode> childNodes) {
+ for(child : childNodes) {
+ if (child.QName.equals(findingNode))
+ return child;
+ }
+ // find recursively
+ for(child : childNodes) {
+ if(child instanceof ContainerSchemaNode) {
+ val contChild = child as ContainerSchemaNode
+ val foundChild = findNodeInChildNodes(findingNode, contChild.childNodes)
+ if (foundChild != null)
+ return foundChild;
+ }
+ else if(child instanceof ListSchemaNode) {
+ val listChild = child as ListSchemaNode
+ val foundChild = findNodeInChildNodes(findingNode, listChild.childNodes)
+ if (foundChild != null)
+ return foundChild;
+ }
+ }
+ }
+
+ private def printNodeChildren(List<DataSchemaNode> childNodes) {
+ if (childNodes.empty) {
+ return ''
+ }
+
+ return
+ '''
+ <pre>
+ «printAugmentedNode(childNodes.get(0))»
+ </pre>
+ '''
+ }
+
+ private def CharSequence printAugmentedNode(DataSchemaNode child) {
+
+ if(child instanceof ChoiceCaseNode)
+ return ''
+
+ return
+ '''
+ «IF child instanceof ContainerSchemaNode»
+ «printContainerNode(child as ContainerSchemaNode)»
+ «ENDIF»
+ «IF child instanceof AnyXmlSchemaNode»
+ «printAnyXmlNode(child as AnyXmlSchemaNode)»
+ «ENDIF»
+ «IF child instanceof LeafSchemaNode»
+ «printLeafNode(child as LeafSchemaNode)»
+ «ENDIF»
+ «IF child instanceof LeafListSchemaNode»
+ «printLeafListNode(child as LeafListSchemaNode)»
+ «ENDIF»
+ «IF child instanceof ListSchemaNode»
+ «printListNode(child as ListSchemaNode)»
+ «ENDIF»
+ «IF child instanceof ChoiceNode»
+ «printChoiceNode(child as ChoiceNode)»
+ «ENDIF»
+ '''
+ }
+
+ private def printChoiceNode(ChoiceNode child) {
+ val List<ChoiceCaseNode> cases = new ArrayList(child.cases);
+ if(!cases.empty) {
+ val ChoiceCaseNode aCase = cases.get(0)
+ for(caseChildNode : aCase.childNodes)
+ printAugmentedNode(caseChildNode)
+ }
+ }
+
+ private def printListNode(ListSchemaNode listNode) {
+ return
+ '''
+ <«listNode.QName.localName»«IF !listNode.QName.namespace.equals(currentModule.namespace)» xmlns="«listNode.QName.namespace»"«ENDIF»>
+ «FOR child : listNode.childNodes»
+ «printAugmentedNode(child)»
+ «ENDFOR»
+ </«listNode.QName.localName»>
+ '''
+ }
+
+ private def printContainerNode(ContainerSchemaNode containerNode) {
+ return
+ '''
+ <«containerNode.QName.localName»«IF !containerNode.QName.namespace.equals(currentModule.namespace)» xmlns="«containerNode.QName.namespace»"«ENDIF»>
+ «FOR child : containerNode.childNodes»
+ «printAugmentedNode(child)»
+ «ENDFOR»
+ </«containerNode.QName.localName»>
+ '''
+ }
+
+ private def printLeafListNode(LeafListSchemaNode leafListNode) {
+ return
+ '''
+ <«leafListNode.QName.localName»>. . .</«leafListNode.QName.localName»>
+ <«leafListNode.QName.localName»>. . .</«leafListNode.QName.localName»>
+ <«leafListNode.QName.localName»>. . .</«leafListNode.QName.localName»>
+ '''
+ }
+
+ private def printAnyXmlNode(AnyXmlSchemaNode anyXmlNode) {
+ return
+ '''
+ <«anyXmlNode.QName.localName»>. . .</«anyXmlNode.QName.localName»>
+ '''
+ }
+
+ private def printLeafNode(LeafSchemaNode leafNode) {
+ return
+ '''
+ <«leafNode.QName.localName»>. . .</«leafNode.QName.localName»>
+ '''
+ }
+
+ private def augmentationsSummary(Module module, SchemaContext context) {
+ if (module.augmentations.empty) {
+ return '';
+ }
+ return '''
+ <h3>Augmentations Summary</h3>
+ <table>
+ <tr>
+ <th>Target</th>
+ <th>Description</th>
+ </tr>
+ «FOR augment : module.augmentations»
+ <tr>
+ <td>
+ «anchorLink(schemaPathToString(module, augment.targetPath, context, augment),
+ strong(schemaPathToString(module, augment.targetPath, context, augment)))»
+ </td>
+ <td>
+ «augment.description»
+ </td>
+ </tr>
+ «ENDFOR»
+ </table>
+ '''
+ }
+
+ def notifications(Module module) {
+ val Set<NotificationDefinition> notificationdefs = module.notifications
+ if (notificationdefs.empty) {
+ return '';
+ }
+
+ return '''
+ <h2>Notifications</h2>
+ «FOR notificationdef : notificationdefs»
+
+ <h3 id="«notificationdef.path.schemaPathToId»">«notificationdef.nodeName»</h3>
+ «notificationdef.descAndRef»
+ «FOR childNode : notificationdef.childNodes»
+ «childNode.printSchemaNodeInfo»
+ «ENDFOR»
+ «ENDFOR»
+ '''
+ }
+
+ private def notificationsSummary(Module module) {
+ if (module.notifications.empty) {
+ return '';
+ }
+ return '''
+ <h3>Notifications Summary</h3>
+ <table>
+ <tr>
+ <th>Name</th>
+ <th>Description</th>
+ </tr>
+ «FOR notification : module.notifications»
+ <tr>
+ <td>
+ «anchorLink(notification.path.schemaPathToId, strong(notification.QName.localName))»
+ </td>
+ <td>
+ «notification.description»
+ </td>
+ </tr>
+ «ENDFOR»
+ </table>
+ '''
+ }
+
+ def rpcs(Module module) {
+ if (module.rpcs.empty) {
+ return '';
+ }
+
+ return '''
+ <h2>RPC Definitions</h2>
+ «FOR rpc : module.rpcs»
+ <h3 id="«rpc.QName.localName»">«rpc.nodeName»</h3>
+ <ul>
+ «rpc.descAndRefLi»
+ «rpc.input.printSchemaNodeInfo»
+ «rpc.output.printSchemaNodeInfo»
+ </ul>
+ «ENDFOR»
+ </ul>
+ '''
+ }
+
+ private def rpcsSummary(Module module) {
+ if (module.rpcs.empty) {
+ return '';
+ }
+ return '''
+ <h3>RPCs Summary</h3>
+ <table>
+ <tr>
+ <th>Name</th>
+ <th>Description</th>
+ </tr>
+ «FOR rpc : module.rpcs»
+ <tr>
+ <td>
+ «anchorLink(rpc.QName.localName, strong(rpc.QName.localName))»
+ </td>
+ <td>
+ «rpc.description»
+ </td>
+ </tr>
+ «ENDFOR»
+ </table>
+ '''
+ }
+
+ def extensions(Module module) {
+ if (module.extensionSchemaNodes.empty) {
+ return '';
+ }
+ return '''
+ <h2>Extensions</h2>
+ «FOR ext : module.extensionSchemaNodes»
+ <li>
+ <h3 id="«ext.QName.localName»">«ext.nodeName»</h3>
+ </li>
+ «extensionInfo(ext)»
+ «ENDFOR»
+ '''
+ }
+
+ private def extensionsSummary(Module module) {
+ if (module.extensionSchemaNodes.empty) {
+ return '';
+ }
+ return '''
+ <h3>Extensions Summary</h3>
+ <table>
+ <tr>
+ <th>Name</th>
+ <th>Description</th>
+ </tr>
+ «FOR ext : module.extensionSchemaNodes»
+ <tr>
+ <td>
+ «anchorLink(ext.QName.localName, strong(ext.QName.localName))»
+ </td>
+ <td>
+ «ext.description»
+ </td>
+ </tr>
+ «ENDFOR»
+ </table>
+ '''
+ }
+
+ def features(Module module) {
+ if (module.features.empty) {
+ return '';
+ }
+ return '''
+ <h2>Features</h2>
+
+ <ul>
+ «FOR feature : module.features»
+ <li>
+ <h3 id="«feature.QName.localName»">«feature.QName.localName»</h3>
+ <ul>
+ «feature.descAndRefLi»
+ </ul>
+ </li>
+ «ENDFOR»
+ </ul>
+ '''
+ }
+
+ private def featuresSummary(Module module) {
+ if (module.features.empty) {
+ return '';
+ }
+ return '''
+ <h3>Features Summary</h3>
+ <table>
+ <tr>
+ <th>Name</th>
+ <th>Description</th>
+ </tr>
+ «FOR feature : module.features»
+ <tr>
+ <td>
+ «anchorLink(feature.QName.localName, strong(feature.QName.localName))»
+ </td>
+ <td>
+ «feature.description»
+ </td>
+ </tr>
+ «ENDFOR»
+ </table>
+ '''
+ }
+
+ private def objectsSummary(Module module) {
+ if (module.childNodes.empty) {
+ return '';
+ }
+ return '''
+ <h3>Child Nodes Summary</h3>
+ <table>
+ <tr>
+ <th>Name</th>
+ <th>Description</th>
+ </tr>
+ «FOR childNode : module.childNodes»
+ <tr>
+ <td>
+ «anchorLink(childNode.QName.localName, strong(childNode.QName.localName))»
+ </td>
+ <td>
+ «childNode.description»
+ </td>
+ </tr>
+ «ENDFOR»
+ </table>
+ '''
+ }
+
+ def header(Module module)
+ '''
+ <h1>«module.name»</h1>
+
+ <h2>Base Information</h2>
+ <table>
+ <tr>
+ <td>«strong("prefix")»</td>
+ <td>«module.prefix»</td>
+ </tr>
+ <tr>
+ <td>«strong("namespace")»</td>
+ <td>«module.namespace»</td>
+ </tr>
+ <tr>
+ <td>«strong("revision")»</td>
+ <td>«REVISION_FORMAT.format(module.revision)»</td>
+ </tr>
+ <tr>
+ <td>«strong("description")»</td>
+ <td>«module.description»</td>
+ </tr>
+ <tr>
+ <td>«strong("yang-version")»</td>
+ <td>«module.yangVersion»</td>
+ </tr>
+ <tr>
+ «FOR imp : module.imports BEFORE '''<td>«strong("imports")»</td><td>''' AFTER '''</td>'''»
+ «imp.prefix»:«imp.moduleName»«IF imp.revision !== null» «REVISION_FORMAT.format(imp.revision)»«ENDIF»;
+ «ENDFOR»
+ </tr>
+ </table>
+ '''
+
+ def CharSequence schemaPathToId(SchemaPath path) {
+ if(path !== null) {
+ return '''«FOR qName : path.path SEPARATOR "/"»«qName.localName»«ENDFOR»'''
+ }
+ }
+
+ def code(String string) '''<code>«string»</code>'''
+
+ def process(Module module) {
+ throw new UnsupportedOperationException("TODO: auto-generated method stub")
+ }
+
+ def CharSequence tree(Module module) '''
+ «strong(module.name)»
+ «module.childNodes.treeSet(YangInstanceIdentifier.builder.build())»
+ '''
+
+ private def dispatch CharSequence tree(ChoiceNode node,YangInstanceIdentifier path) '''
+ «node.nodeName» (choice)
+ «casesTree(node.cases,path)»
+ '''
+
+ def casesTree(Set<ChoiceCaseNode> nodes,YangInstanceIdentifier path) '''
+ <ul>
+ «FOR node : nodes»
+ <li>
+ «node.nodeName»
+ «node.childNodes.treeSet(path)»
+ </li>
+ «ENDFOR»
+ </ul>
+ '''
+
+ private def dispatch CharSequence tree(DataSchemaNode node,YangInstanceIdentifier path) '''
+ «node.nodeName»
+ '''
+
+ private def dispatch CharSequence tree(ListSchemaNode node,YangInstanceIdentifier path) '''
+ «val newPath = path.append(node)»
+ «localLink(newPath,node.nodeName)»
+ «node.childNodes.treeSet(newPath)»
+ '''
+
+ private def dispatch CharSequence tree(ContainerSchemaNode node,YangInstanceIdentifier path) '''
+ «val newPath = path.append(node)»
+ «localLink(newPath,node.nodeName)»
+ «node.childNodes.treeSet(newPath)»
+ '''
+
+ def CharSequence childNodes(Module module) '''
+ «val childNodes = module.childNodes»
+ «IF !childNodes.nullOrEmpty»
+ <h2>Child nodes</h2>
+
+ «childNodes.printChildren(3,YangInstanceIdentifier.builder().build())»
+ «ENDIF»
+ '''
+
+ def CharSequence printSchemaNodeInfo(DataSchemaNode node) {
+ return '''
+ <ul>
+ «node.printBaseInfo»
+ «IF node instanceof DataNodeContainer»
+ «val dataNode = node as DataNodeContainer»
+ <ul>
+ «FOR usesNode : dataNode.uses»
+ «usesNode.printUses»
+ «ENDFOR»
+ </ul>
+ <ul>
+ «val Set<TypeDefinition<?>> typeDefinitions = dataNode.typeDefinitions»
+ «FOR typeDef : typeDefinitions»
+ «typeDef.restrictions»
+ «ENDFOR»
+ </ul>
+ <ul>
+ «FOR grouping : dataNode.groupings»
+ «grouping.printGrouping»
+ «ENDFOR»
+ </ul>
+ <ul>
+ «FOR child : dataNode.childNodes»
+ «child.printSchemaNodeInfo»
+ «ENDFOR»
+ </ul>
+ «ENDIF»
+ </ul>
+ '''
+ }
+
+ def String typeAnchorLink(SchemaPath path, CharSequence text) {
+ if(path !== null) {
+ val lastElement = Iterables.getLast(path.pathFromRoot)
+ val ns = lastElement.namespace
+ if (ns == this.currentModule.namespace) {
+ return '''<a href="#«path.schemaPathToId»">«text»</a>'''
+ } else {
+ return '''(«ns»)«text»'''
+ //to enable external (import) links
+ //return '''<a href="«module».html#«path.schemaPathToId»">«prefix»:«text»</a>'''
+ }
+ }
+ }
+
+ def CharSequence printBaseInfo(SchemaNode node) {
+ if(node instanceof LeafSchemaNode) {
+ val LeafSchemaNode leafNode = (node as LeafSchemaNode)
+ return '''
+ «printInfo(node, "leaf")»
+ «listItem("type", typeAnchorLink(leafNode.type?.path, leafNode.type.QName.localName))»
+ «listItem("units", leafNode.units)»
+ «listItem("default", leafNode.^default)»
+ </ul>
+ '''
+ } else if(node instanceof LeafListSchemaNode) {
+ val LeafListSchemaNode leafListNode = (node as LeafListSchemaNode)
+ return '''
+ «printInfo(node, "leaf-list")»
+ «listItem("type", leafListNode.type?.QName.localName)»
+ </ul>
+ '''
+ } else if(node instanceof ListSchemaNode) {
+ val ListSchemaNode listNode = (node as ListSchemaNode)
+ return '''
+ «printInfo(node, "list")»
+ «FOR keyDef : listNode.keyDefinition»
+ «listItem("key definition", keyDef.localName)»
+ «ENDFOR»
+ </ul>
+ '''
+ } else if(node instanceof ChoiceNode) {
+ val ChoiceNode choiceNode = (node as ChoiceNode)
+ return '''
+ «printInfo(node, "choice")»
+ «listItem("default case", choiceNode.defaultCase)»
+ «FOR caseNode : choiceNode.cases»
+ «caseNode.printSchemaNodeInfo»
+ «ENDFOR»
+ </ul>
+ '''
+ } else if(node instanceof ChoiceCaseNode) {
+ return '''
+ «printInfo(node, "case")»
+ </ul>
+ '''
+ } else if(node instanceof ContainerSchemaNode) {
+ return '''
+ «printInfo(node, "container")»
+ </ul>
+ '''
+ } else if(node instanceof AnyXmlSchemaNode) {
+ return '''
+ «printInfo(node, "anyxml")»
+ </ul>
+ '''
+ }
+ }
+
+ def CharSequence printInfo(SchemaNode node, String nodeType) {
+ return '''
+ «IF node instanceof AugmentationTarget»
+ «IF node !== null»
+ <strong>
+ <li id="«node.path.schemaPathToId»">
+ «nodeType»: «node.QName.localName»
+ </li>
+ </strong>
+ «ENDIF»
+ «ELSE»
+ «strong(listItem(nodeType, node.QName.localName))»
+ «ENDIF»
+ <ul>
+ «listItem("description", node.description)»
+ «listItem("reference", node.reference)»
+ «IF node instanceof DataSchemaNode»
+ «listItem("when condition", (node as DataSchemaNode).constraints.whenCondition?.toString)»
+ «listItem("min elements", (node as DataSchemaNode).constraints.minElements?.toString)»
+ «listItem("max elements", (node as DataSchemaNode).constraints.maxElements?.toString)»
+ «ENDIF»
+ '''
+ }
+
+ def CharSequence printUses(UsesNode usesNode) {
+ return '''
+ «strong(listItem("uses", typeAnchorLink(usesNode.groupingPath, usesNode.groupingPath.pathTowardsRoot.iterator.next.localName)))»
+ <ul>
+ <li>refines:
+ <ul>
+ «FOR sp : usesNode.refines.keySet»
+ «listItem("node name", usesNode.refines.get(sp).QName.localName)»
+ «ENDFOR»
+ </ul>
+ </li>
+ «FOR augment : usesNode.augmentations»
+ «typeAnchorLink(augment.targetPath,schemaPathToString(currentModule, augment.targetPath, ctx, augment))»
+ «ENDFOR»
+ </ul>
+ '''
+ }
+
+ def CharSequence printGrouping(GroupingDefinition grouping) {
+ return '''
+ «strong(listItem("grouping", grouping.QName.localName))»
+ '''
+ }
+
+ def CharSequence printChildren(Iterable<DataSchemaNode> nodes, int level, YangInstanceIdentifier path) {
+ val anyxmlNodes = nodes.filter(AnyXmlSchemaNode)
+ val leafNodes = nodes.filter(LeafSchemaNode)
+ val leafListNodes = nodes.filter(LeafListSchemaNode)
+ val choices = nodes.filter(ChoiceNode)
+ val cases = nodes.filter(ChoiceCaseNode)
+ val containers = nodes.filter(ContainerSchemaNode)
+ val lists = nodes.filter(ListSchemaNode)
+ return '''
+ «IF ((anyxmlNodes.size + leafNodes.size + leafListNodes.size + containers.size + lists.size) > 0)»
+ <h3>Direct children</h3>
+ <ul>
+ «FOR childNode : anyxmlNodes»
+ «childNode.printShortInfo(level,path)»
+ «ENDFOR»
+ «FOR childNode : leafNodes»
+ «childNode.printShortInfo(level,path)»
+ «ENDFOR»
+ «FOR childNode : leafListNodes»
+ «childNode.printShortInfo(level,path)»
+ «ENDFOR»
+ «FOR childNode : containers»
+ «childNode.printShortInfo(level,path)»
+ «ENDFOR»
+ «FOR childNode : lists»
+ «childNode.printShortInfo(level,path)»
+ «ENDFOR»
+ </ul>
+ «ENDIF»
+
+ «IF path.pathArguments.iterator.hasNext»
+ <h3>XML example</h3>
+ «nodes.xmlExample(path.pathArguments.last.nodeType,path)»
+ </h3>
+ «ENDIF»
+ «FOR childNode : containers»
+ «childNode.printInfo(level,path)»
+ «ENDFOR»
+ «FOR childNode : lists»
+ «childNode.printInfo(level,path)»
+ «ENDFOR»
+ «FOR childNode : choices»
+ «childNode.printInfo(level,path)»
+ «ENDFOR»
+ «FOR childNode : cases»
+ «childNode.printInfo(level,path)»
+ «ENDFOR»
+ '''
+ }
+
+ def CharSequence xmlExample(Iterable<DataSchemaNode> nodes, QName name,YangInstanceIdentifier path) '''
+ <pre>
+ «xmlExampleTag(name,nodes.xmplExampleTags(path))»
+ </pre>
+ '''
+
+ def CharSequence xmplExampleTags(Iterable<DataSchemaNode> nodes, YangInstanceIdentifier identifier) '''
+ <!-- Child nodes -->
+ «FOR node : nodes»
+ <!-- «node.QName.localName» -->
+ «node.asXmlExampleTag(identifier)»
+ «ENDFOR»
+
+ '''
+
+ private def dispatch CharSequence asXmlExampleTag(LeafSchemaNode node, YangInstanceIdentifier identifier) '''
+ «node.QName.xmlExampleTag("...")»
+ '''
+
+ private def dispatch CharSequence asXmlExampleTag(LeafListSchemaNode node, YangInstanceIdentifier identifier) '''
+ <!-- This node could appear multiple times -->
+ «node.QName.xmlExampleTag("...")»
+ '''
+
+ private def dispatch CharSequence asXmlExampleTag(ContainerSchemaNode node, YangInstanceIdentifier identifier) '''
+ <!-- See «localLink(identifier.append(node),"definition")» for child nodes. -->
+ «node.QName.xmlExampleTag("...")»
+ '''
+
+
+ private def dispatch CharSequence asXmlExampleTag(ListSchemaNode node, YangInstanceIdentifier identifier) '''
+ <!-- See «localLink(identifier.append(node),"definition")» for child nodes. -->
+ <!-- This node could appear multiple times -->
+ «node.QName.xmlExampleTag("...")»
+ '''
+
+
+ private def dispatch CharSequence asXmlExampleTag(DataSchemaNode node, YangInstanceIdentifier identifier) '''
+ <!-- noop -->
+ '''
+
+
+ def xmlExampleTag(QName name, CharSequence data) {
+ return '''<«name.localName» xmlns="«name.namespace»">«data»</«name.localName»>'''
+ }
+
+ def header(int level,QName name) '''<h«level»>«name.localName»</h«level»>'''