/*******************************************************************************
* Copyright (c) 2009 Red Hat, Inc.
* Copyright (c) 2015 Ezchip Semiconductor
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* EZchip Semiconductor - adding support for Doxygen XML files as input
*******************************************************************************/
package org.eclipse.linuxtools.internal.cdt.libhover.utils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.linuxtools.cdt.libhover.ClassInfo;
import org.eclipse.linuxtools.cdt.libhover.FunctionInfo;
import org.eclipse.linuxtools.cdt.libhover.LibHoverInfo;
import org.eclipse.linuxtools.cdt.libhover.MemberInfo;
import org.eclipse.linuxtools.cdt.libhover.TypedefInfo;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class CDoxygenLibhoverGen extends LibhoverInfoGenerator{
private static final String PROT3 = "prot";//$NON-NLS-1$
private static final String RETURN = "return";//$NON-NLS-1$
private static final String PARAMETERDESCRIPTION = "parameterdescription";//$NON-NLS-1$
private static final String PARAMETERNAME = "parametername";//$NON-NLS-1$
private static final String PARAMETERNAMELIST = "parameternamelist";//$NON-NLS-1$
private static final String PARAMETERITEM = "parameteritem";//$NON-NLS-1$
private static final String EXCEPTION = "exception";//$NON-NLS-1$
private static final String DEFINITION = "definition";//$NON-NLS-1$
private static final String TYPEDEF2 = "typedef";//$NON-NLS-1$
private static final String REFID2 = "refid";//$NON-NLS-1$
private static final String REF = "ref";//$NON-NLS-1$
private static final String PUBLIC_FUNC = "public-func";//$NON-NLS-1$
private static final String BASECOMPOUNDREF = "basecompoundref";//$NON-NLS-1$
private static final String INCLUDES = "includes";//$NON-NLS-1$
private static final String DECLNAME = "declname";//$NON-NLS-1$
private static final String TEMPLATEPARAMLIST = "templateparamlist";//$NON-NLS-1$
private static final String CLASS = "class";//$NON-NLS-1$
private static final String PUBLIC = "public";//$NON-NLS-1$
private static final String LOCATION = "location";//$NON-NLS-1$
private static final String SIMPLESECT = "simplesect";//$NON-NLS-1$
private static final String PARAMETERLIST = "parameterlist";//$NON-NLS-1$
private static final String DETAILEDDESCRIPTION = "detaileddescription";//$NON-NLS-1$
private static final String PARA = "para";//$NON-NLS-1$
private static final String BRIEFDESCRIPTION = "briefdescription";//$NON-NLS-1$
private static final String TYPE2 = "type";//$NON-NLS-1$
private static final String PARAM = "param";//$NON-NLS-1$
private static final String ARGSSTRING = "argsstring";//$NON-NLS-1$
private static final String NAME3 = "name";//$NON-NLS-1$
private static final String FUNCTION = "function";//$NON-NLS-1$
private static final String MEMBERDEF = "memberdef";//$NON-NLS-1$
private static final String FUNC = "func";//$NON-NLS-1$
private static final String SECTIONDEF = "sectiondef";//$NON-NLS-1$
private static final String COMPOUNDNAME = "compoundname";//$NON-NLS-1$
private static final String FILE = "file";//$NON-NLS-1$
private static final String COMPOUNDDEF = "compounddef";//$NON-NLS-1$
private static final String TYPEDEF = "typedef ";//$NON-NLS-1$
private Document document;
private Map<String, ClassInfo> classesById = new HashMap<>();
public CDoxygenLibhoverGen(Document document) {
this.document = document;
}
private String[] getTypedefTypes(String def) {
String[] result = null;
if (def.startsWith(TYPEDEF)) {
int startIndex = 8;
int count = 0;
int i = def.length() - 1;
// To break up types, we look for first blank outside of a template, working backwards.
// We need to work backwards because the transformed type may contain actual numeric parameters
// which could use the shift operators and we won't know whether they are shift operators or
// template specifiers without some actual parsing.
while (i >= 0) {
char ch = def.charAt(i);
if (ch == '<') {
--count;
} else if (ch == '>') {
++count;
}
// We look at last blank not in a template as being the delimeter between
// type name and definition.
if (count == 0 && ch == ' ') {
startIndex = i + 1;
break;
}
--i;
}
result = new String[2];
result[1] = def.substring(startIndex);
// Following is a bit of a hack knowing the docs don't add the namespace when the transformed
// type is in the same space
int namespace = result[1].indexOf("::"); //$NON-NLS-1$
if (namespace < 0) {
result[0] = def.substring(8, startIndex).trim();
} else {
result[0] = result[1].substring(0, namespace) + "::" + def.substring(8, startIndex).trim(); //$NON-NLS-1$
}
}
return result;
}
private String getElementText(Node node) {
StringBuffer d = new StringBuffer();
NodeList nl = node.getChildNodes();
for (int x = 0; x < nl.getLength(); ++x) {
Node text = nl.item(x);
if (text.getNodeType() == Node.TEXT_NODE) {
d.append(text.getNodeValue());
} else {
d.append(getElementText(text));
}
}
return d.toString();
}
private ClassInfo getClassInfo(LibHoverInfo libHoverInfo, String className) {
String typedefName = className.replaceAll("<.*>", "<>"); //$NON-NLS-1$ //$NON-NLS-2$
TypedefInfo typedef = libHoverInfo.typedefs.get(typedefName);
if (typedef != null) {
className = typedef.getTransformedType(className); // Reset class name to typedef transformation
}
int index = className.indexOf('<');
// Check if it is a template reference.
if (index != -1) {
// It is. We want to see if there are partial specific templates
// and we choose the first match. If nothing matches our particular
// case, we fall back on the initial generic template.
ClassInfo info = libHoverInfo.classes.get(className.substring(0, index));
if (info == null)
return null;
ArrayList<ClassInfo> children = info.getChildren();
if (children != null && children.size() > 0) {
for (int x = 0; x < children.size(); ++x) {
ClassInfo child = children.get(x);
if (className.matches(child.getClassName())) {
info = child;
break;
}
}
}
return info;
}
// Otherwise no template, just fetch the class info directly.
return libHoverInfo.classes.get(className);
}
@Override
public LibHoverInfo doGenerate(){
LibHoverInfo libHoverInfo = new LibHoverInfo();
// Create a hash table of all the class nodes mapped by class name. Trim any template info
// for the class name key value.
NodeList nl = document.getElementsByTagName(COMPOUNDDEF);
for (int i = 0; i < nl.getLength(); ++i) {
Node n = nl.item(i);
NamedNodeMap attrs = n.getAttributes();
Node kind = attrs.getNamedItem("kind"); //$NON-NLS-1$
Node id = attrs.getNamedItem("id"); //$NON-NLS-1$
Node prot = attrs.getNamedItem(PROT3);
// C functions
if (id != null && kind != null && FILE.equals(kind.getNodeValue())) {
NodeList nl2 = n.getChildNodes();
FunctionInfo fi = null;
String include = null;
for (int j = 0; j < nl2.getLength(); ++j) {
Node n2 = nl2.item(j);
String name2 = n2.getNodeName();
if (COMPOUNDNAME.equals(name2)) {
// compoundname for a file node is the filename
// this can be a .c or .h file
String filename = getElementText(n2);
if(filename.endsWith(".h")) { //$NON-NLS-1$
include = filename;
}
} else if (SECTIONDEF.equals(name2)) {
// We are only interested in functions
NamedNodeMap m = n2.getAttributes();
if (m != null) {
Node kind2 = m.getNamedItem("kind"); //$NON-NLS-1$
if (kind2 != null && FUNC.equals(kind2.getNodeValue())) {
NodeList pubfuncs = n2.getChildNodes();
int pubfuncLength = pubfuncs.getLength();
for (int j1 = 0; j1 < pubfuncLength; ++j1) {
Node n3 = pubfuncs.item(j1);
// Add all public member functions to the list of members
if (MEMBERDEF.equals(n3.getNodeName())) {
NamedNodeMap m3 = n3.getAttributes();
if (m3 != null) {
Node m3Kind = m3.getNamedItem("kind"); //$NON-NLS-1$
if (m3Kind != null && FUNCTION.equals(m3Kind.getNodeValue())) {
String name = null;
String type = null;
String args = null;
String desc = null;
boolean briefDescriptionProcessed = false;
boolean detailedDescriptionProcessed = false;
boolean parameterListProcessed = false;
boolean retValProcessed = false;
boolean locationProcessed = false;
ArrayList<String> parms = new ArrayList<>();
NodeList nl4 = n3.getChildNodes();
int memberLength = nl4.getLength();
for (int k = 0; k < memberLength; ++k) {
Node n4 = nl4.item(k);
String n4Name = n4.getNodeName();
if (TYPE2.equals(n4Name)) {
NodeList nl5 = n4.getChildNodes();
type = ""; //$NON-NLS-1$
for (int x = 0; x < nl5.getLength(); ++x) {
Node n5 = nl5.item(x);
if (n5.getNodeType() == Node.TEXT_NODE)
type += n5.getNodeValue();
}
} else if (NAME3.equals(n4Name)) {
name = n4.getTextContent();
} else if (ARGSSTRING.equals(n4Name)) {
args = getElementText(n4);
} else if (PARAM.equals(n4Name)) {
NodeList nl5 = n4.getChildNodes();
for (int x = 0; x < nl5.getLength(); ++x) {
Node n5 = nl5.item(x);
if (TYPE2.equals(n5.getNodeName())) {
parms.add(getElementText(n5));
}
}
} else if (BRIEFDESCRIPTION.equals(n4Name) && !briefDescriptionProcessed ) {
NodeList nl5 = n4.getChildNodes();
for (int x = 0; x < nl5.getLength(); ++x) {
Node n5 = nl5.item(x);
if (PARA.equals(n5.getNodeName())) {
if (desc == null) {
desc = ""; //$NON-NLS-1$
}
desc += "<p>" + getElementText(n5) + "</p>"; //$NON-NLS-1$ //$NON-NLS-2$
briefDescriptionProcessed = true;
}
}
} else if (DETAILEDDESCRIPTION.equals(n4Name)) {
NodeList nl5 = n4.getChildNodes();
for (int x = 0; x < nl5.getLength(); ++x) {
Node n5 = nl5.item(x);
if (n5.getNodeName().equals(PARA)) {
if (desc == null)
desc = new String(""); //$NON-NLS-1$
NodeList nl6 = n5.getChildNodes();
Node n6 = nl6.item(0);
if (n6.getNodeType() == Node.TEXT_NODE && !detailedDescriptionProcessed){
desc += "<p>" + getElementText(n5) + "</p>"; //$NON-NLS-1$ //$NON-NLS-2$
detailedDescriptionProcessed = true;
} else {
for (int x2 = 0; x2 < nl6.getLength(); ++x2) {
n6 = nl6.item(x2);
if (PARAMETERLIST.equals(n6.getNodeName()) && !parameterListProcessed) {
desc += getParameters(n6, false);
parameterListProcessed = true;
} else if (SIMPLESECT.equals(n6.getNodeName()) & !retValProcessed) {
desc += getReturn(n6);
retValProcessed = true;
}
}
}
}
}
} else if (LOCATION.equals(n4Name) && !locationProcessed) {
// Location is after all descriptions so we can now add the function
if (name != null) {
// Try to update existing function, in case information is split between .c and .h files
fi = libHoverInfo.functions.get(name);
if (fi == null) {
fi = new FunctionInfo(name);
}
if (type != null) {
fi.setReturnType(type);
}
if (args != null) {
// Strip ()s, as the plugin adds them back in
if(args.charAt(0) == '(' && args.charAt(args.length() - 1) == ')')
fi.setPrototype(args.substring(1, args.length() - 1));
else
fi.setPrototype(args);
}
if (desc != null) {
fi.setDescription(desc);
}
if(include != null) {
fi.addHeader(include);
}
//System.out.println(name + "|" + type + "|" + args + "|" + desc + "|" + include);
libHoverInfo.functions.put(name, fi);
locationProcessed = true;
}
break;
}
}
}
}
}
}
}
}
}
}
}
// We are only interested in cataloging public classes.
if (id != null && prot != null && PUBLIC.equals(prot.getNodeValue())
&& kind != null && CLASS.equals(kind.getNodeValue())) {
NodeList nl2 = n.getChildNodes();
ClassInfo d = null;
String hashName = null;
for (int j = 0; j < nl2.getLength(); ++j) {
Node n2 = nl2.item(j);
String name2 = n2.getNodeName();
if (name2.equals(COMPOUNDNAME)) {
String text = n2.getTextContent();
if (text != null && !text.equals("")) { //$NON-NLS-1$
String className = text;
text = text.replaceAll("<\\s*", "<"); //$NON-NLS-1$ //$NON-NLS-2$
text = text.replaceAll("\\s*>", ">"); //$NON-NLS-1$ //$NON-NLS-2$
int index = text.indexOf('<');
hashName = text;
if (index > 0)
hashName = text.substring(0, index);
d = new ClassInfo(className, n);
classesById.put(id.getNodeValue(), d);
ClassInfo e = libHoverInfo.classes.get(hashName);
if (e != null) { /* We are dealing with a partial specific template...add it to list */
if (!d.areTemplateParmsFilled())
d.setTemplateParms(getTemplateParms(n));
String[] templateParms = d.getTemplateParms();
// For each template parameter, replace with a generic regex so later we can compare
// and identify a match (e.g. A<_a, _b> and A<char, _b> are defined and we have an instance
// of A<char, int>. We want to to match with A<char, _b> and replace all occurrences of "_b"
// with "int". For speed, we assume that the template parameter is not a subset of any
// other variable (e.g. if _A is used, there is no __A or _AB). If this proves untrue in
// any instance, more refinement of the initial value to replace will be required.
for (int k = 0; k < templateParms.length; ++k) {
text = text.replaceAll(templateParms[k], "[a-zA-Z0-9_: *]+"); //$NON-NLS-1$
}
d.setClassName(text);
e.addTemplate(d);
}
else
libHoverInfo.classes.put(hashName, d);
}
} else if (TEMPLATEPARAMLIST.equals(name2)) {
ArrayList<String> templates = new ArrayList<>();
NodeList params = n2.getChildNodes();
int paramsLength = params.getLength();
for (int j2 = 0; j2 < paramsLength; ++j2) {
Node n3 = params.item(j2);
if (n3.getNodeName().equals(PARAM)) {
NodeList types = n3.getChildNodes();
int typesLength = types.getLength();
for (int j3 = 0; j3 < typesLength; ++j3) {
Node n4 = types.item(j3);
if (DECLNAME.equals(n4.getNodeName())) {
templates.add(getElementText(n4));
}
}
}
}
String[] templateNames = new String[templates.size()];
d.setTemplateParms(templates.toArray(templateNames));
} else if (INCLUDES.equals(name2)) {
String include = getElementText(n2);
if (d != null)
d.setInclude(include);
} else if (BASECOMPOUNDREF.equals(name2)) {
// We have a base class. If public, add it to the list of nodes to look at in case we don't find the member
// in the current class definition.
NamedNodeMap m = n2.getAttributes();
if (m != null) {
Node refid = m.getNamedItem(REFID2);
Node prot2 = m.getNamedItem(PROT3);
if (prot2 != null && PUBLIC.equals(prot2.getNodeValue())) {
ClassInfo baseClass = null;
if (refid != null) {
// If we have been given the id of the base class, fetch it directly
baseClass = classesById.get(refid.getNodeValue());
} else {
// We probably have a template that needs resolution
String baseClassName = n2.getTextContent();
// System.out.println("base class name is " + baseClassName);
baseClass = getClassInfo(libHoverInfo, baseClassName);
}
if (d != null && baseClass != null)
d.addBaseClass(baseClass);
}
}
} else if (SECTIONDEF.equals(name2)) {
// We are only interested in public member functions which are in their own section.
NamedNodeMap m = n2.getAttributes();
if (m != null) {
Node kind2 = m.getNamedItem("kind"); //$NON-NLS-1$
if (kind2 != null && PUBLIC_FUNC.equals(kind2.getNodeValue())) {
NodeList pubfuncs = n2.getChildNodes();
int pubfuncLength = pubfuncs.getLength();
for (int j1 = 0; j1 < pubfuncLength; ++j1) {
Node n3 = pubfuncs.item(j1);
// Add all public member functions to the list of members
if (MEMBERDEF.equals(n3.getNodeName())) {
NamedNodeMap m3 = n3.getAttributes();
if (m3 != null) {
Node m3Kind = m3.getNamedItem("kind"); //$NON-NLS-1$
if (m3Kind != null && FUNCTION.equals(m3Kind.getNodeValue())) {
String name = null;
String type = null;
String args = null;
String desc = null;
ArrayList<String> parms = new ArrayList<>();
NodeList nl4 = n3.getChildNodes();
int memberLength = nl4.getLength();
for (int k = 0; k < memberLength; ++k) {
Node n4 = nl4.item(k);
String n4Name = n4.getNodeName();
if (TYPE2.equals(n4Name)) {
NodeList nl5 = n4.getChildNodes();
type = ""; //$NON-NLS-1$
for (int x = 0; x < nl5.getLength(); ++x) {
Node n5 = nl5.item(x);
if (n5.getNodeType() == Node.TEXT_NODE)
type += n5.getNodeValue();
else if (REF.equals(n5.getNodeName())) {
NamedNodeMap n5m = n5.getAttributes();
Node n5id = n5m.getNamedItem(REFID2);
if (n5id != null) {
String refid = n5id.getNodeValue();
ClassInfo refClass = classesById.get(refid);
if (refClass != null)
type += refClass.getClassName();
}
}
}
} else if (NAME3.equals(n4Name)) {
name = n4.getTextContent();
} else if (ARGSSTRING.equals(n4Name)) {
args = getElementText(n4);
} else if (PARAM.equals(n4Name)) {
NodeList nl5 = n4.getChildNodes();
for (int x = 0; x < nl5.getLength(); ++x) {
Node n5 = nl5.item(x);
if (TYPE2.equals(n5.getNodeName())) {
parms.add(getElementText(n5));
}
}
} else if (BRIEFDESCRIPTION.equals(n4Name)) {
NodeList nl5 = n4.getChildNodes();
for (int x = 0; x < nl5.getLength(); ++x) {
Node n5 = nl5.item(x);
if (PARA.equals(n5.getNodeName())) {
if (desc == null) {
desc = ""; //$NON-NLS-1$
}
desc += "<p>" + getElementText(n5) + "</p>"; //$NON-NLS-1$ //$NON-NLS-2$
}
}
} else if (DETAILEDDESCRIPTION.equals(n4Name)) {
NodeList nl5 = n4.getChildNodes();
for (int x = 0; x < nl5.getLength(); ++x) {
Node n5 = nl5.item(x);
if (PARA.equals(n5.getNodeName())) {
if (desc == null)
desc = new String(""); //$NON-NLS-1$
NodeList nl6 = n5.getChildNodes();
Node n6 = nl6.item(0);
if (n6.getNodeType() == Node.TEXT_NODE)
desc += "<p>" + getElementText(n5) + "</p>"; //$NON-NLS-1$ //$NON-NLS-2$
else {
for (int x2 = 0; x2 < nl6.getLength(); ++x2) {
n6 = nl6.item(x2);
if (PARAMETERLIST.equals(n6.getNodeName())) {
desc += getParameters(n6, true);
} else if (SIMPLESECT.equals(n6.getNodeName())) {
desc += getReturn(n6);
}
}
}
}
}
} else if (LOCATION.equals(n4Name)) {
// Location is after all descriptions so we can now add the member
if (name != null) {
MemberInfo member = new MemberInfo(name);
member.setReturnType(type);
member.setPrototype(args);
member.setDescription(desc);
String[] argNames = new String[parms.size()];
member.setParamTypes(parms.toArray(argNames));
d.addMember(member);
}
break;
}
}
}
}
}
}
}
}
}
}
}
}
// Create a hash table of all the typedefs. Keep any template info.
nl = document.getElementsByTagName(MEMBERDEF);
for (int i = 0; i < nl.getLength(); ++i) {
Node n = nl.item(i);
NamedNodeMap attrs = n.getAttributes();
if (attrs != null) {
Node kind = attrs.getNamedItem("kind"); //$NON-NLS-1$
Node prot = attrs.getNamedItem(PROT3);
if (kind != null && TYPEDEF2.equals(kind.getNodeValue())
&& prot != null && PUBLIC.equals(prot.getNodeValue())) {
NodeList list = n.getChildNodes();
for (int x = 0; x < list.getLength(); ++x) {
Node n2 = list.item(x);
if (DEFINITION.equals(n2.getNodeName())) {
String def = n2.getTextContent();
if (def != null && !def.equals("")) { //$NON-NLS-1$
def = def.replaceAll("<\\s*", "<"); //$NON-NLS-1$ //$NON-NLS-2$
def = def.replaceAll("\\s*>", ">"); //$NON-NLS-1$ //$NON-NLS-2$
String[] types = getTypedefTypes(def);
if(types == null){
continue;
}
TypedefInfo d = new TypedefInfo(types[1], types[0]);
String hashName = d.getTypedefName();
int index = hashName.indexOf('<');
if (index > 0) {
String className = hashName.substring(0, index);
hashName = hashName.replaceAll("<.*>", "<>"); //$NON-NLS-1$ //$NON-NLS-2$
ClassInfo e = libHoverInfo.classes.get(className);
if (e == null)
break;
ArrayList<ClassInfo> children = e.getChildren();
if (children != null && children.size() > 0) {
for (int y = 0; y < children.size(); ++y) {
ClassInfo child = children.get(y);
String childName = child.getClassName().replaceAll("\\*", "\\\\*"); //$NON-NLS-1$ //$NON-NLS-2$
childName = childName.replace("[]", "\\[\\]"); //$NON-NLS-1$ //$NON-NLS-2$
if (types[1].matches(childName.concat("::.*"))) { //$NON-NLS-1$
e = child;
break;
}
}
}
String[] templates = e.getTemplateParms();
d.copyTemplates(templates);
TypedefInfo f = libHoverInfo.typedefs.get(hashName);
if (f != null) {
String typedefName = d.getTypedefName();
for (int z = 0; z < templates.length; ++z) {
typedefName = typedefName.replaceAll(templates[z], "[a-zA-Z0-9_: ]+"); //$NON-NLS-1$
}
d.setTypedefName(typedefName);
f.addTypedef(d);
}
else
libHoverInfo.typedefs.put(hashName, d);
break;
} else {
// Otherwise we have a non-template typedef name. Just add it to the list.
libHoverInfo.typedefs.put(hashName, d);
break;
}
}
}
}
}
}
}
return libHoverInfo;
}
private String getParameters(Node n6, boolean addHyphen) {
String desc = "<br><br><h3>Parameters:</h3>"; //$NON-NLS-1$
NamedNodeMap m = n6.getAttributes();
Node kind = m.getNamedItem("kind"); //$NON-NLS-1$
if (kind != null && EXCEPTION.equals(kind.getNodeValue())) {
desc = "<br><br><h3>Exceptions:</h3>"; //$NON-NLS-1$
}
NodeList nl = n6.getChildNodes();
for (int x = 0; x < nl.getLength(); ++x) {
Node n = nl.item(x);
if (PARAMETERITEM.equals(n.getNodeName())) {
NodeList nl2 = n.getChildNodes();
for (int y = 0; y < nl2.getLength(); ++y) {
Node n2 = nl2.item(y);
if (PARAMETERNAMELIST.equals(n2.getNodeName())) {
NodeList nl3 = n2.getChildNodes();
for (int z = 0; z < nl3.getLength(); ++z) {
Node n3 = nl3.item(z);
if (PARAMETERNAME.equals(n3.getNodeName())) {
desc += getElementText(n3);
if(addHyphen) {
desc += " - ";//$NON-NLS-1$
}
}
}
} else if (PARAMETERDESCRIPTION.equals(n2.getNodeName())) {
desc += getElementText(n2) + "<br>"; //$NON-NLS-1$
}
}
}
}
return desc;
}
private String getReturn(Node n6) {
String desc = ""; //$NON-NLS-1$
NamedNodeMap m = n6.getAttributes();
Node kind = m.getNamedItem("kind"); //$NON-NLS-1$
if (kind != null && RETURN.equals(kind.getNodeValue())) {
desc += "<br><h3>Returns:</h3>" + getElementText(n6) + "<br>"; //$NON-NLS-1$ //$NON-NLS-2$
}
return desc;
}
private String[] getTemplateParms(Node classNode) {
Node n = null;
ArrayList<String> templateArray = new ArrayList<>();
NodeList list = classNode.getChildNodes();
for (int i = 0; i < list.getLength(); ++i) {
n = list.item(i);
if (TEMPLATEPARAMLIST.equals(n.getNodeName())) {
break;
}
}
if (n != null) {
NodeList templateList = n.getChildNodes();
for (int j = 0; j < templateList.getLength(); ++j) {
Node p = templateList.item(j);
if (PARAM.equals(p.getNodeName())) {
NodeList paramList = p.getChildNodes();
for (int k = 0; k < paramList.getLength(); ++k) {
Node q = paramList.item(k);
if (DECLNAME.equals(q.getNodeName())) {
String templateName = q.getTextContent();
templateArray.add(templateName);
}
}
}
}
}
String[] templates = new String[templateArray.size()];
return templateArray.toArray(templates);
}
}