📄 doxproc.py
字号:
#!/usr/bin/python# Copyright 2006 Rene Rivera# Distributed under the Boost Software License, Version 1.0.# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)'''Processing of Doxygen generated XML.'''import osimport os.pathimport sysimport timeimport stringimport getoptimport globimport reimport xml.dom.minidom def usage(): print '''Usage: %s optionsOptions: --xmldir Directory with the Doxygen xml result files. --output Write the output BoostBook to the given location. --id The ID of the top level BoostBook section. --title The title of the top level BoostBook section. --enable-index Generate additional index sections for classes and types.''' % ( sys.argv[0] )def get_args( argv = sys.argv[1:] ): spec = [ 'xmldir=', 'output=', 'id=', 'title=', 'enable-index', 'help' ] options = { '--xmldir' : 'xml', '--output' : None, '--id' : 'dox', '--title' : 'Doxygen' } ( option_pairs, other ) = getopt.getopt( argv, '', spec ) map( lambda x: options.__setitem__( x[0], x[1] ), option_pairs ) if options.has_key( '--help' ): usage() sys.exit(1) return { 'xmldir' : options['--xmldir'], 'output' : options['--output'], 'id' : options['--id'], 'title' : options['--title'], 'index' : options.has_key('--enable-index') }def if_attribute(node, attribute, true_value, false_value=None): if node.getAttribute(attribute) == 'yes': return true_value else: return false_valueclass Doxygen2BoostBook: def __init__( self, **kwargs ): ## self.args = kwargs self.args.setdefault('id','') self.args.setdefault('title','') self.args.setdefault('last_revision', time.asctime()) self.args.setdefault('index', False) self.id = '%(id)s.reference' % self.args self.args['id'] = self.id #~ This is our template BoostBook document we insert the generated content into. self.boostbook = xml.dom.minidom.parseString('''<?xml version="1.0" encoding="UTF-8"?><section id="%(id)s" name="%(title)s" last-revision="%(last_revision)s"> <title>%(title)s</title> <library-reference id="%(id)s.headers"> <title>Headers</title> </library-reference> <index id="%(id)s.classes"> <title>Classes</title> </index> <index id="%(id)s.index"> <title>Index</title> </index></section>''' % self.args ) self.section = { 'headers' : self._getChild('library-reference',id='%(id)s.headers' % self.args), 'classes' : self._getChild('index',id='%(id)s.classes' % self.args), 'index' : self._getChild('index',id='%(id)s.index' % self.args) } #~ Remove the index sections if we aren't generating it. if not self.args['index']: self.section['classes'].parentNode.removeChild(self.section['classes']) self.section['classes'].unlink() del self.section['classes'] self.section['index'].parentNode.removeChild(self.section['index']) self.section['index'].unlink() del self.section['index'] #~ The symbols, per Doxygen notion, that we translated. self.symbols = {} #~ Map of Doxygen IDs and BoostBook IDs, so we can translate as needed. self.idmap = {} #~ Marks generation, to prevent redoing it. self.generated = False #~ Add an Doxygen generated XML document to the content we are translating. def addDox( self, document ): self._translateNode(document.documentElement) #~ Turns the internal XML tree into an output UTF-8 string. def tostring( self ): self._generate() #~ return self.boostbook.toprettyxml(' ') return self.boostbook.toxml('utf-8') #~ Does post-processing on the partial generated content to generate additional info #~ now that we have the complete source documents. def _generate( self ): if not self.generated: self.generated = True symbols = self.symbols.keys() symbols.sort() #~ Populate the header section. for symbol in symbols: if self.symbols[symbol]['kind'] in ('header'): self.section['headers'].appendChild(self.symbols[symbol]['dom']) for symbol in symbols: if self.symbols[symbol]['kind'] not in ('namespace', 'header'): container = self._resolveContainer(self.symbols[symbol], self.symbols[self.symbols[symbol]['header']]['dom']) if container.nodeName != 'namespace': ## The current BoostBook to Docbook translation doesn't ## respect, nor assign, IDs to inner types of any kind. ## So nuke the ID entry so as not create bogus links. del self.idmap[self.symbols[symbol]['id']] container.appendChild(self.symbols[symbol]['dom']) self._rewriteIDs(self.boostbook.documentElement) #~ Rewrite the various IDs from Doxygen references to the newly created #~ BoostBook references. def _rewriteIDs( self, node ): if node.nodeName in ('link'): if (self.idmap.has_key(node.getAttribute('linkend'))): #~ A link, and we have someplace to repoint it at. node.setAttribute('linkend',self.idmap[node.getAttribute('linkend')]) else: #~ A link, but we don't have a generated target for it. node.removeAttribute('linkend') elif hasattr(node,'hasAttribute') and node.hasAttribute('id') and self.idmap.has_key(node.getAttribute('id')): #~ Simple ID, and we have a translation. node.setAttribute('id',self.idmap[node.getAttribute('id')]) #~ Recurse, and iterate, depth-first traversal which turns out to be #~ left-to-right and top-to-bottom for the document. if node.firstChild: self._rewriteIDs(node.firstChild) if node.nextSibling: self._rewriteIDs(node.nextSibling) def _resolveContainer( self, cpp, root ): container = root for ns in cpp['namespace']: node = self._getChild('namespace',name=ns,root=container) if not node: node = container.appendChild( self._createNode('namespace',name=ns)) container = node for inner in cpp['name'].split('::'): node = self._getChild(name=inner,root=container) if not node: break container = node return container def _setID( self, id, name ): self.idmap[id] = name.replace('::','.').replace('/','.') #~ print '--| setID:',id,'::',self.idmap[id] #~ Translate a given node within a given context. #~ The translation dispatches to a local method of the form #~ "_translate[_context0,...,_contextN]", and the keyword args are #~ passed along. If there is no translation handling method we #~ return None. def _translateNode( self, *context, **kwargs ): node = None names = [ ] for c in context: if c: if not isinstance(c,xml.dom.Node): suffix = '_'+c.replace('-','_') else: suffix = '_'+c.nodeName.replace('-','_') node = c names.append('_translate') names = map(lambda x: x+suffix,names) if node: for name in names: if hasattr(self,name): return getattr(self,name)(node,**kwargs) return None #~ Translates the children of the given parent node, appending the results #~ to the indicated target. For nodes not translated by the translation method #~ it copies the child over and recurses on that child to translate any #~ possible interior nodes. Hence this will translate the entire subtree. def _translateChildren( self, parent, **kwargs ): target = kwargs['target'] for n in parent.childNodes: child = self._translateNode(n,target=target) if child: target.appendChild(child) else: child = n.cloneNode(False) if hasattr(child,'data'): child.data = re.sub(r'\s+',' ',child.data) target.appendChild(child) self._translateChildren(n,target=child) #~ Translate the given node as a description, into the description subnode #~ of the target. If no description subnode is present in the target it #~ is created. def _translateDescription( self, node, target=None, tag='description', **kwargs ): description = self._getChild(tag,root=target) if not description: description = target.appendChild(self._createNode(tag)) self._translateChildren(node,target=description) return description #~ Top level translation of: <doxygen ...>...</doxygen>, #~ translates the children. def _translate_doxygen( self, node ): #~ print '_translate_doxygen:', node.nodeName result = [] for n in node.childNodes: newNode = self._translateNode(n) if newNode: result.append(newNode) return result #~ Top level translation of: #~ <doxygenindex ...> #~ <compound ...> #~ <member ...> #~ <name>...</name> #~ </member> #~ ... #~ </compound> #~ ... #~ </doxygenindex> #~ builds the class and symbol sections, if requested. def _translate_doxygenindex( self, node ): #~ print '_translate_doxygenindex:', node.nodeName if self.args['index']: entries = [] classes = [] #~ Accumulate all the index entries we care about. for n in node.childNodes: if n.nodeName == 'compound': if n.getAttribute('kind') not in ('file','dir','define'): cpp = self._cppName(self._getChildData('name',root=n)) entry = { 'name' : cpp['name'], 'compoundname' : cpp['compoundname'], 'id' : n.getAttribute('refid') } if n.getAttribute('kind') in ('class','struct'): classes.append(entry) entries.append(entry) for m in n.childNodes: if m.nodeName == 'member': cpp = self._cppName(self._getChildData('name',root=m)) entry = { 'name' : cpp['name'], 'compoundname' : cpp['compoundname'], 'id' : n.getAttribute('refid') } if hasattr(m,'getAttribute') and m.getAttribute('kind') in ('class','struct'):
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -