1 from docstructure import SITE_STRUCTURE, HREF_MAP, BASENAME_MAP
2 from lxml.etree import (parse, fromstring, ElementTree,
3 Element, SubElement, XPath)
4 import os, shutil, re, sys, copy, time
6 RST2HTML_OPTIONS = " ".join([
13 htmlnsmap = {"h" : "http://www.w3.org/1999/xhtml"}
15 find_title = XPath("/h:html/h:head/h:title/text()", namespaces=htmlnsmap)
16 find_title_tag = XPath("/h:html/h:head/h:title", namespaces=htmlnsmap)
17 find_headings = XPath("//h:h1[not(@class)]//text()", namespaces=htmlnsmap)
18 find_menu = XPath("//h:ul[@id=$name]", namespaces=htmlnsmap)
19 find_page_end = XPath("/h:html/h:body/h:div[last()]", namespaces=htmlnsmap)
21 find_words = re.compile('(\w+)').findall
22 replace_invalid = re.compile(r'[-_/.\s\\]').sub
24 def make_menu_section_head(section, menuroot):
25 section_id = section + '-section'
26 section_head = menuroot.xpath("//ul[@id=$section]/li", section=section_id)
28 ul = SubElement(menuroot, "ul", id=section_id)
29 section_head = SubElement(ul, "li")
30 title = SubElement(section_head, "span", {"class":"section title"})
33 section_head = section_head[0]
36 def build_menu(tree, basename, section_head):
37 page_title = find_title(tree)
39 page_title = page_title[0]
41 page_title = replace_invalid('', basename.capitalize())
42 build_menu_entry(page_title, basename+".html", section_head,
43 headings=find_headings(tree))
45 def build_menu_entry(page_title, url, section_head, headings=None):
46 page_id = replace_invalid(' ', os.path.splitext(url)[0]) + '-menu'
47 ul = SubElement(section_head, "ul", {"class":"menu foreign", "id":page_id})
49 title = SubElement(ul, "li", {"class":"menu title"})
50 a = SubElement(title, "a", href=url)
54 subul = SubElement(title, "ul", {"class":"submenu"})
55 for heading in headings:
56 li = SubElement(subul, "li", {"class":"menu item"})
57 ref = '-'.join(find_words(replace_invalid(' ', heading.lower())))
58 a = SubElement(li, "a", href=url+'#'+ref)
61 def merge_menu(tree, menu, name):
62 menu_root = copy.deepcopy(menu)
63 tree.getroot()[1][0].insert(0, menu_root) # html->body->div[class=document]
64 for el in menu_root.iter():
67 el.tag = "{http://www.w3.org/1999/xhtml}" + tag
68 current_menu = find_menu(
69 menu_root, name=replace_invalid(' ', name + '-menu'))
71 current_menu = find_menu(
72 menu_root, name=replace_invalid('-', name + '-menu'))
74 for submenu in current_menu:
75 submenu.set("class", submenu.get("class", "").
76 replace("foreign", "current"))
79 def rest2html(script, source_path, dest_path, stylesheet_url):
80 command = ('%s %s %s --stylesheet=%s --link-stylesheet %s > %s' %
81 (sys.executable, script, RST2HTML_OPTIONS,
82 stylesheet_url, source_path, dest_path))
85 def publish(dirname, lxml_path, release):
86 if not os.path.exists(dirname):
89 doc_dir = os.path.join(lxml_path, 'doc')
90 script = os.path.join(doc_dir, 'rest2html.py')
91 pubkey = os.path.join(doc_dir, 'pubkey.asc')
92 stylesheet_url = 'style.css'
94 shutil.copy(pubkey, dirname)
96 href_map = HREF_MAP.copy()
97 changelog_basename = 'changes-%s' % release
98 href_map['Release Changelog'] = changelog_basename + '.html'
101 menu = Element("div", {"class":"sidemenu"})
102 # build HTML pages and parse them back
103 for section, text_files in SITE_STRUCTURE:
104 section_head = make_menu_section_head(section, menu)
105 for filename in text_files:
106 if filename.startswith('@'):
108 page_title = filename[1:]
109 url = href_map[page_title]
110 build_menu_entry(page_title, url, section_head)
112 path = os.path.join(doc_dir, filename)
113 basename = os.path.splitext(os.path.basename(filename))[0]
114 basename = BASENAME_MAP.get(basename, basename)
115 outname = basename + '.html'
116 outpath = os.path.join(dirname, outname)
118 rest2html(script, path, outpath, stylesheet_url)
120 tree = parse(outpath)
121 trees[filename] = (tree, basename, outpath)
123 build_menu(tree, basename, section_head)
125 # also convert CHANGES.txt
127 os.path.join(lxml_path, 'CHANGES.txt'),
128 os.path.join(dirname, 'changes-%s.html' % release),
132 for tree, basename, outpath in trees.itervalues():
133 new_tree = merge_menu(tree, menu, basename)
134 title = find_title_tag(new_tree)
135 if title and title[0].text == 'lxml':
136 title[0].text = "lxml - Processing XML and HTML with Python"
137 new_tree.write(outpath)
139 if __name__ == '__main__':
140 publish(sys.argv[1], sys.argv[2], sys.argv[3])