2 Copyright 2008 Free Software Foundation, Inc.
3 This file is part of GNU Radio
5 GNU Radio Companion is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 GNU Radio Companion is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19 ##@package grc_gnuradio.utils.extract_docs
20 #Extract documentation from the gnuradio doxygen files.
22 from grc_gnuradio.Constants import DOCS_DIR
23 from lxml import etree
26 DOXYGEN_NAME_XPATH = '/doxygen/compounddef/compoundname'
27 DOXYGEN_BRIEFDESC_GR_XPATH = '/doxygen/compounddef/briefdescription'
28 DOXYGEN_DETAILDESC_GR_XPATH = '/doxygen/compounddef/detaileddescription'
29 DOXYGEN_BRIEFDESC_BLKS2_XPATH = '/doxygen/compounddef/sectiondef[@kind="public-func"]/memberdef/briefdescription'
30 DOXYGEN_DETAILDESC_BLKS2_XPATH = '/doxygen/compounddef/sectiondef[@kind="public-func"]/memberdef/detaileddescription'
32 def extract_txt(xml, parent_text=None):
34 Recursivly pull the text out of an xml tree.
35 @param xml the xml tree
36 @param parent_text the text of the parent element
40 tail = parent_text and xml.tail or ''
41 return text + ''.join(
42 map(lambda x: extract_txt(x, text), xml)
45 def is_match(key, file):
47 Is the block key a match for the given file name?
49 @param file the xml file name
50 @return true if matches
52 if not file.endswith('.xml'): return False
53 file = file.replace('.xml', '') #remove file ext
54 file = file.replace('__', '_') #doxygen xml files have 2 underscores
55 if key.startswith('gr_'):
56 if not file.startswith('classgr_'): return False
57 key = key.replace('gr_', 'classgr_')
58 elif key.startswith('trellis_'):
59 if not file.startswith('classtrellis_'): return False
60 key = key.replace('trellis_', 'classtrellis_')
61 elif key.startswith('blks2_'):
62 if not file.startswith('classgnuradio_'): return False
63 if 'blks2' not in file: return False
64 file = file.replace('_1_1', '_') #weird blks2 doxygen syntax
65 key = key.replace('blks2_', '')
67 for k, f in zip(*map(reversed, map(lambda x: x.split('_'), [key, file]))):
70 if len(ks) == 2 and f.startswith(ks[0]) and f.endswith(ks[1]): continue
71 if len(ks) > 2 and all(ki in ('x', fi) for ki, fi in zip(k, f)): continue
77 Extract the documentation from the doxygen generated xml files.
78 If multiple files match, combine the docs.
79 @param key the block key
80 @return a string with documentation
82 #get potential xml file matches for the key
83 if os.path.exists(DOCS_DIR) and os.path.isdir(DOCS_DIR):
84 matches = filter(lambda f: is_match(key, f), os.listdir(DOCS_DIR))
85 else: matches = list()
90 xml_file = DOCS_DIR + '/' + match
91 xml = etree.parse(xml_file)
93 comp_name = extract_txt(xml.xpath(DOXYGEN_NAME_XPATH)[0]).strip('\n')
94 comp_name = ' --- ' + comp_name + ' --- '
95 if key.startswith('gr_') or key.startswith('trellis_'):
96 brief_desc = extract_txt(xml.xpath(DOXYGEN_BRIEFDESC_GR_XPATH)[0]).strip('\n')
97 detailed_desc = extract_txt(xml.xpath(DOXYGEN_DETAILDESC_GR_XPATH)[0]).strip('\n')
98 elif key.startswith('blks2_'):
99 brief_desc = extract_txt(xml.xpath(DOXYGEN_BRIEFDESC_BLKS2_XPATH)[0]).strip('\n')
100 detailed_desc = extract_txt(xml.xpath(DOXYGEN_DETAILDESC_BLKS2_XPATH)[0]).strip('\n')
105 doc_strs.append('\n'.join([comp_name, brief_desc, detailed_desc]).strip('\n'))
106 except IndexError: pass #bad format
107 return '\n\n'.join(doc_strs)
109 if __name__ == '__main__':
111 print extract(sys.argv[1])