def _discover_toc(zf, opf_xmldoc, opf_filepath):
toc = None<EOL>tag = find_tag(opf_xmldoc, '<STR_LIT>', '<STR_LIT>', '<STR_LIT>')<EOL>if tag and '<STR_LIT>' in tag.attributes.keys():<EOL><INDENT>filepath = unquote(tag.attributes['<STR_LIT>'].value)<EOL>base_dir = os.path.dirname(opf_filepath)<EOL>npath = os.path.normpath(os.path.join(base_dir, filepath))<EOL>nav_content = zf.read(npath)<EOL>toc_xmldoc = minidom.parseString(nav_content)<EOL>_toc = []<EOL>for n in toc_xmldoc.getElementsByTagName('<STR_LIT:a>'):<EOL><INDENT>if n.firstChild and ('<STR_LIT>' in n.attributes.keys()):<EOL><INDENT>href = unquote(n.attributes['<STR_LIT>'].value)<EOL>if '<STR_LIT>' in href or '<STR_LIT>' in href:<EOL><INDENT>title = n.firstChild.nodeValue<EOL>if not title and n.firstChild.firstChild:<EOL><INDENT>title = n.firstChild.firstChild.nodeValue<EOL><DEDENT>title = title.strip() if title else None<EOL>if title:<EOL><INDENT>level = -<NUM_LIT:1><EOL>parentNode = n.parentNode<EOL>avoid_infinite_loop = <NUM_LIT:0> <EOL>while parentNode and parentNode.nodeName != '<STR_LIT>' and avoid_infinite_loop < <NUM_LIT:50>:<EOL><INDENT>if parentNode.nodeName == '<STR_LIT>': <EOL><INDENT>level += <NUM_LIT:1><EOL><DEDENT>parentNode = parentNode.parentNode<EOL>avoid_infinite_loop += <NUM_LIT:1><EOL><DEDENT>level = max(level, <NUM_LIT:0>) <EOL>_toc.append({'<STR_LIT:title>': title, '<STR_LIT:src>': href, '<STR_LIT>': level})<EOL><DEDENT><DEDENT><DEDENT><DEDENT>if _toc:<EOL><INDENT>toc = _toc<EOL><DEDENT><DEDENT>if not toc:<EOL><INDENT>tag = find_tag(opf_xmldoc, '<STR_LIT>', '<STR_LIT:id>', '<STR_LIT>')<EOL>if not tag:<EOL><INDENT>tag = find_tag(opf_xmldoc, '<STR_LIT>', '<STR_LIT:id>', '<STR_LIT>')<EOL><DEDENT>if tag and '<STR_LIT>' in tag.attributes.keys():<EOL><INDENT>filepath = unquote(tag.attributes['<STR_LIT>'].value)<EOL>base_dir = os.path.dirname(opf_filepath)<EOL>npath = os.path.normpath(os.path.join(base_dir, filepath))<EOL>ncx_content = zf.read(npath)<EOL>toc_xmldoc = minidom.parseString(ncx_content)<EOL>def read_nav_point(nav_point_node, level = <NUM_LIT:0>):<EOL><INDENT>items = []<EOL>item = {'<STR_LIT:title>': None, '<STR_LIT:src>': None, '<STR_LIT>': level}<EOL>children_points = []<EOL>for item_node in nav_point_node.childNodes:<EOL><INDENT>if item_node.nodeName in ('<STR_LIT>', '<STR_LIT>'):<EOL><INDENT>try:<EOL><INDENT>text = item_node.getElementsByTagName('<STR_LIT:text>')[<NUM_LIT:0>].firstChild<EOL><DEDENT>except IndexError:<EOL><INDENT>try:<EOL><INDENT>text = item_node.getElementsByTagName('<STR_LIT>')[<NUM_LIT:0>].firstChild<EOL><DEDENT>except IndexError:<EOL><INDENT>text = None<EOL><DEDENT><DEDENT>item['<STR_LIT:title>'] = text.nodeValue.strip() if text and text.nodeValue else None<EOL><DEDENT>elif item_node.nodeName in ('<STR_LIT:content>', '<STR_LIT>'):<EOL><INDENT>if item_node.hasAttribute('<STR_LIT:src>'):<EOL><INDENT>item['<STR_LIT:src>'] = item_node.attributes['<STR_LIT:src>'].value<EOL><DEDENT><DEDENT>elif item_node.nodeName in ('<STR_LIT>', '<STR_LIT>'):<EOL><INDENT>children_points.append(item_node)<EOL><DEDENT><DEDENT>if item['<STR_LIT:title>']:<EOL><INDENT>items.append(item)<EOL>for child_node in children_points:<EOL><INDENT>subitems = read_nav_point(child_node, level=level + <NUM_LIT:1>)<EOL>items.extend(subitems)<EOL><DEDENT><DEDENT>return items<EOL><DEDENT>def read_nav_map(toc_xmldoc, level=<NUM_LIT:0>):<EOL><INDENT>items = []<EOL>try:<EOL><INDENT>nav_map_node = toc_xmldoc.getElementsByTagName('<STR_LIT>')[<NUM_LIT:0>]<EOL><DEDENT>except IndexError:<EOL><INDENT>try:<EOL><INDENT>nav_map_node = toc_xmldoc.getElementsByTagName('<STR_LIT>')[<NUM_LIT:0>]<EOL><DEDENT>except IndexError:<EOL><INDENT>print('<STR_LIT>')<EOL>return items<EOL><DEDENT><DEDENT>for nav_point in nav_map_node.childNodes:<EOL><INDENT>if nav_point.nodeName in ('<STR_LIT>', '<STR_LIT>'):<EOL><INDENT>subitems = read_nav_point(nav_point, level=level)<EOL>items.extend(subitems)<EOL><DEDENT><DEDENT>return items<EOL><DEDENT>toc = read_nav_map(toc_xmldoc)<EOL><DEDENT><DEDENT>if toc:<EOL><INDENT>for i, t in enumerate(toc):<EOL><INDENT>t['<STR_LIT:index>'] = i<EOL><DEDENT><DEDENT>return toc<EOL>
Returns a list of objects: {title: str, src: str, level: int, index: int}