]> git.saurik.com Git - wxWidgets.git/blobdiff - docs/doxygen/scripts/doxymlparser.py
Move the scripts into a separate directory and commit initial start on automatic...
[wxWidgets.git] / docs / doxygen / scripts / doxymlparser.py
diff --git a/docs/doxygen/scripts/doxymlparser.py b/docs/doxygen/scripts/doxymlparser.py
new file mode 100755 (executable)
index 0000000..414cf98
--- /dev/null
@@ -0,0 +1,233 @@
+"""
+Name: doxymlparser.py
+Author: Kevin Ollivier
+License: wxWidgets License
+"""
+
+__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 xml.dom import minidom
+
+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()
+
+def get_first_value(alist):
+    if len(alist) > 0:
+        return alist[0]
+    else:
+        return ""
+
+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):
+        self.classes = []
+
+    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 options.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__":
+    if len(arguments) < 1:
+        parser.print_usage()
+        sys.exit(1)
+    
+    doxyparse = DoxyMLParser()
+    for arg in arguments:
+        doxyparse.parse(arg)        
+
+    if options.report:
+        for aclass in doxyparse.classes:
+            print str(aclass)
+