1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
|
"""
Name: doxymlparser.py
Author: Kevin Ollivier
Licence: wxWindows licence
"""
__description__ = """
Takes the output of Doxygen XML and parses it to retrieve metadata about the classes and methods.
To create the Doxygen XML files, from the wxWidgets/docs/doxygen directory, do:
./regen.sh xml
To see the results from parsing a particular class, do:
python doxymlparser.py --report out/xml/classwx_<whatever>.xml
"""
#!/usr/bin/env python
import optparse
import os
import string
import sys
import types
from common import *
from xml.dom import minidom
class ClassDefinition:
def __init__(self):
self.name = ""
self.constructors = []
self.destructors = []
self.methods = []
self.brief_description = ""
self.detailed_description = ""
self.includes = []
self.bases = []
self.enums = {}
def __str__(self):
str_repr = """
Class: %s
Bases: %s
Includes: %s
Brief Description:
%s
Detailed Description:
%s
""" % (self.name, string.join(self.bases, ", "), self.includes, self.brief_description, self.detailed_description)
str_repr += "Methods:\n"
for method in self.methods:
str_repr += str(method)
return str_repr
class MethodDefinition:
def __init__(self):
self.name = ""
self.return_type = ""
self.argsstring = ""
self.definition = ""
self.params = []
self.brief_description = ""
self.detailed_description = ""
def __str__(self):
str_repr = """
Method: %s
Return Type: %s
Params: %r
Prototype: %s
Brief Description:
%s
Detailed Description:
%s
""" % (self.name, self.return_type, self.params, self.definition + self.argsstring, self.brief_description, self.detailed_description)
return str_repr
def getTextValue(node, recursive=False):
text = ""
for child in node.childNodes:
if child.nodeType == child.ELEMENT_NODE and child.nodeName == "ref":
text += getTextValue(child)
if child.nodeType == child.TEXT_NODE:
# Add a space to ensure we have a space between qualifiers and parameter names
text += child.nodeValue.strip() + " "
return text.strip()
def doxyMLToText(node):
return text
class DoxyMLParser:
def __init__(self, verbose = False):
self.classes = []
self.verbose = verbose
def find_class(self, name):
for aclass in self.classes:
if aclass.name == name:
return aclass
return None
def get_enums_and_functions(self, filename, aclass):
file_path = os.path.dirname(filename)
enum_filename = os.path.join(file_path, aclass.name[2:] + "_8h.xml")
if os.path.exists(enum_filename):
root = minidom.parse(enum_filename).documentElement
for method in root.getElementsByTagName("memberdef"):
if method.getAttribute("kind") == "enum":
self.parse_enum(aclass, method, root)
def is_derived_from_base(self, aclass, abase):
base = get_first_value(aclass.bases)
while base and base != "":
if base == abase:
return True
parentclass = self.find_class(base)
if parentclass:
base = get_first_value(parentclass.bases)
else:
base = None
return False
def parse(self, filename):
self.xmldoc = minidom.parse(filename).documentElement
for node in self.xmldoc.getElementsByTagName("compounddef"):
new_class = self.parse_class(node)
self.classes.append(new_class)
self.get_enums_and_functions(filename, new_class)
def parse_class(self, class_node):
new_class = ClassDefinition()
new_class.name = getTextValue(class_node.getElementsByTagName("compoundname")[0])
for node in class_node.childNodes:
if node.nodeName == "basecompoundref":
new_class.bases.append(getTextValue(node))
elif node.nodeName == "briefdescription":
# let the post-processor determ
new_class.brief_description = node.toxml()
elif node.nodeName == "detaileddescription":
new_class.detailed_description = node.toxml()
elif node.nodeName == "includes":
new_class.includes.append(getTextValue(node))
self.parse_methods(new_class, class_node)
return new_class
def parse_enum(self, new_class, enum, root):
enum_name = ""
enum_values = []
for node in enum.childNodes:
if node.nodeName == "name":
enum_name = getTextValue(node)
elif node.nodeName == "enumvalue":
enum_values.append(getTextValue(node.getElementsByTagName("name")[0]))
new_class.enums[enum_name] = enum_values
def parse_methods(self, new_class, root):
for method in root.getElementsByTagName("memberdef"):
new_method = MethodDefinition()
for node in method.childNodes:
if node.nodeName == "name":
new_method.name = getTextValue(node)
elif node.nodeName == "type":
new_method.return_type = getTextValue(node)
elif node.nodeName == "definition":
new_method.definition = getTextValue(node)
elif node.nodeName == "argsstring":
new_method.argsstring = getTextValue(node)
elif node.nodeName == "param":
param = {}
for child in node.childNodes:
if child.nodeType == child.ELEMENT_NODE:
param[child.nodeName] = getTextValue(child)
new_method.params.append(param)
if self.verbose:
print "Adding %s" % (new_method.name + new_method.argsstring)
if new_method.name == new_class.name:
new_class.constructors.append(new_method)
elif new_method.name == "~" + new_class.name:
new_class.destructors.append(new_method)
else:
new_class.methods.append(new_method)
if __name__ == "__main__":
option_dict = {
"report" : (False, "Print out the classes and methods found by this script."),
"verbose" : (False, "Provide status updates and other information."),
}
parser = optparse.OptionParser(usage="usage: %prog [options] <doxyml files to parse>\n" + __description__, version="%prog 1.0")
for opt in option_dict:
default = option_dict[opt][0]
action = "store"
if type(default) == types.BooleanType:
action = "store_true"
parser.add_option("--" + opt, default=default, action=action, dest=opt, help=option_dict[opt][1])
options, arguments = parser.parse_args()
if len(arguments) < 1:
parser.print_usage()
sys.exit(1)
doxyparse = DoxyMLParser(verbose = options.verbose)
for arg in arguments:
doxyparse.parse(arg)
if options.report:
for aclass in doxyparse.classes:
print str(aclass)
|