X-Git-Url: https://git.mdrn.pl/librarian.git/blobdiff_plain/6d65ed2b0c5f9f6df14de211ea2bf1de0a5dac70..a1e43b7bba2a0c7cf33280143bb49af3fef5d0d0:/librarian/html.py diff --git a/librarian/html.py b/librarian/html.py index 4e9abd0..985970a 100644 --- a/librarian/html.py +++ b/librarian/html.py @@ -5,17 +5,16 @@ # import os import cStringIO -import re import copy from lxml import etree -from librarian.parser import WLDocument -from librarian import XHTMLNS, ParseError +from librarian import XHTMLNS, ParseError, IOFile from librarian import functions from lxml.etree import XMLSyntaxError, XSLTApplyError functions.reg_substitute_entities() +functions.reg_person_name() STYLESHEETS = { 'legacy': 'xslt/book2html.xslt', @@ -29,9 +28,8 @@ def get_stylesheet(name): def html_has_content(text): return etree.ETXPath('//p|//{%(ns)s}p|//h1|//{%(ns)s}h1' % {'ns': str(XHTMLNS)})(text) -def transform(input, output_filename=None, is_file=True, \ - parse_dublincore=True, stylesheet='legacy', options={}, flags=None): - """Transforms file input_filename in XML to output_filename in XHTML. +def transform(wldoc, stylesheet='legacy', options=None, flags=None): + """Transforms the WL document to XHTML. If output_filename is None, returns an XML, otherwise returns True if file has been written,False if it hasn't. @@ -42,12 +40,9 @@ def transform(input, output_filename=None, is_file=True, \ style_filename = get_stylesheet(stylesheet) style = etree.parse(style_filename) - if is_file: - document = WLDocument.from_file(input, True, \ - parse_dublincore=parse_dublincore) - else: - document = WLDocument.from_string(input, True, \ - parse_dublincore=parse_dublincore) + document = copy.deepcopy(wldoc) + del wldoc + document.swap_endlines() if flags: for flag in flags: @@ -55,6 +50,8 @@ def transform(input, output_filename=None, is_file=True, \ document.clean_ed_note() + if not options: + options = {} result = document.transform(style, **options) del document # no longer needed large object :) @@ -62,16 +59,10 @@ def transform(input, output_filename=None, is_file=True, \ add_anchors(result.getroot()) add_table_of_contents(result.getroot()) - if output_filename is not None: - result.write(output_filename, method='html', xml_declaration=False, pretty_print=True, encoding='utf-8') - else: - return result - return True + return IOFile.from_string(etree.tostring(result, method='html', + xml_declaration=False, pretty_print=True, encoding='utf-8')) else: - if output_filename is not None: - return False - else: - return "" + return None except KeyError: raise ValueError("'%s' is not a valid stylesheet.") except (XMLSyntaxError, XSLTApplyError), e: @@ -126,7 +117,13 @@ def extract_fragments(input_filename): open_fragments = {} closed_fragments = {} - for event, element in etree.iterparse(input_filename, events=('start', 'end')): + # iterparse would die on a HTML document + parser = etree.HTMLParser(encoding='utf-8') + buf = cStringIO.StringIO() + buf.write(etree.tostring(etree.parse(input_filename, parser).getroot()[0][0], encoding='utf-8')) + buf.seek(0) + + for event, element in etree.iterparse(buf, events=('start', 'end')): # Process begin and end elements if element.get('class', '') in ('theme-begin', 'theme-end'): if not event == 'end': continue # Process elements only once, on end event @@ -166,7 +163,8 @@ def extract_fragments(input_filename): # Process all elements except begin and end else: # Omit annotation tags - if len(element.get('name', '')) or element.get('class', '') == 'annotation': + if (len(element.get('name', '')) or + element.get('class', '') in ('annotation', 'anchor')): if event == 'end' and element.tail: for fragment_id in open_fragments: open_fragments[fragment_id].append('text', element.tail) @@ -223,18 +221,27 @@ def add_anchors(root): counter += 1 +def raw_printable_text(element): + working = copy.deepcopy(element) + for e in working.findall('a'): + if e.get('class') == 'annotation': + e.text = '' + return etree.tostring(working, method='text', encoding=unicode).strip() + + def add_table_of_contents(root): sections = [] counter = 1 for element in root.iterdescendants(): if element.tag in ('h2', 'h3'): - if any_ancestor(element, lambda e: e.get('id') in ('footnotes',) or e.get('class') in ('person-list',)): + if any_ancestor(element, lambda e: e.get('id') in ('footnotes', 'nota_red') or e.get('class') in ('person-list',)): continue + element_text = raw_printable_text(element) if element.tag == 'h3' and len(sections) and sections[-1][1] == 'h2': - sections[-1][3].append((counter, element.tag, ''.join(element.xpath('text()')), [])) + sections[-1][3].append((counter, element.tag, element_text, [])) else: - sections.append((counter, element.tag, ''.join(element.xpath('text()')), [])) + sections.append((counter, element.tag, element_text, [])) add_anchor(element, "s%d" % counter, with_link=False) counter += 1 @@ -256,3 +263,17 @@ def add_table_of_contents(root): root.insert(0, toc) + +def extract_annotations(html_path): + """For each annotation, yields a tuple: anchor, text, html.""" + parser = etree.HTMLParser(encoding='utf-8') + tree = etree.parse(html_path, parser) + footnotes = tree.find('//*[@id="footnotes"]') + if footnotes is not None: + for footnote in footnotes.findall('div'): + anchor = footnote.find('a[@name]').get('name') + del footnote[:2] + text_str = etree.tostring(footnote, method='text', encoding='utf-8').strip() + html_str = etree.tostring(footnote, method='html', encoding='utf-8') + yield anchor, text_str, html_str +