# html_template = """ # # # # # # # # {content} # # # """ html_template = """ {content} """ import re import markdown from html.parser import HTMLParser from weasyprint import HTML class TOCHtmlRestructurer(HTMLParser): def __init__(self): super().__init__() self.output = [] self.level_stack = [] # Tracks nesting hierarchy self.parent_count = 0 self.child_count = 0 self.capture_text = False self.current_item_text = "" self.current_href = None # Tracks anchor references dynamically def handle_starttag(self, tag, attrs): if tag in ['ol', 'ul']: if not self.level_stack: self.level_stack.append('parent') else: self.level_stack.append('child') elif tag == 'li': self.capture_text = True self.current_item_text = "" self.current_href = None elif tag == 'a' and self.capture_text: # Capture the link anchor destination safely attrs_dict = dict(attrs) self.current_href = attrs_dict.get('href') def handle_endtag(self, tag): if tag in ['ol', 'ul']: if self.level_stack: self.level_stack.pop() elif tag == 'li': self.capture_text = False self.process_accumulated_item() def handle_data(self, data): if self.capture_text: self.current_item_text += data def process_accumulated_item(self): # 1. Clean out stray prefix digits and list flags safely clean = self.current_item_text.strip() clean = re.sub(r'^([\d\.\s\-•]*\d+\.\d+|[\d\.\s\-•]*\d+\.)\s*', '', clean) clean = re.sub(r'^\d+\s+(?=[A-Za-z])', '', clean) clean = re.sub(r'^[\s\-•]*', '', clean).strip() if not clean: return # 2. Check current depth level stack state current_state = self.level_stack[-1] if self.level_stack else 'parent' # 3. Rebuild the text as a clickable link if an anchor was present if self.current_href: display_text = f'{clean}' else: display_text = clean # 4. Generate structured HTML outputs with calculated taxonomy counters if current_state == 'parent': self.parent_count += 1 self.child_count = 0 self.output.append(f'
{self.parent_count}. {display_text}
') else: self.child_count += 1 self.output.append(f'
{self.parent_count}.{self.child_count} {display_text}
') def extract_and_fix_toc_blocks(html_content): """ Finds the compiled HTML lists block, intercepts it, clears numbering artifacts structurally via HTML parsing tree mechanics. """ match = re.search(r'(<(?:ol|ul)>[\s\S]*?)', html_content) if not match: return html_content raw_toc_html = match.group(1) parser = TOCHtmlRestructurer() parser.feed(raw_toc_html) new_toc_html = '
\n

Table of Contents

\n' new_toc_html += '\n'.join(parser.output) new_toc_html += '\n
' return html_content.replace(raw_toc_html, new_toc_html, 1) def export_to_pdf(inputText, filename): """ Processes plain dynamic markdown, captures structural compilation output, restructures TOC nodes downstream safely, and outputs a high-fidelity PDF. """ html_content = markdown.markdown(inputText, extensions=['tables', 'fenced_code']) final_body_content = extract_and_fix_toc_blocks(html_content) final_html = html_template.format(content=final_body_content) HTML(string=final_html).write_pdf(filename)