Override `HTMLExtractor` and create `etree` `Elements` for any elements which should have content parsed as Markdown.
| 35 | |
| 36 | |
| 37 | class HTMLExtractorExtra(HTMLExtractor): |
| 38 | """ |
| 39 | Override `HTMLExtractor` and create `etree` `Elements` for any elements which should have content parsed as |
| 40 | Markdown. |
| 41 | """ |
| 42 | |
| 43 | def __init__(self, md: Markdown, *args, **kwargs): |
| 44 | # Block-level tags in which the content only gets span level parsing |
| 45 | self.span_tags = set( |
| 46 | ['address', 'dd', 'dt', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'legend', 'li', 'p', 'summary', 'td', 'th'] |
| 47 | ) |
| 48 | # Block-level tags which never get their content parsed. |
| 49 | self.raw_tags = set(['canvas', 'math', 'option', 'pre', 'script', 'style', 'textarea']) |
| 50 | |
| 51 | super().__init__(md, *args, **kwargs) |
| 52 | |
| 53 | @property |
| 54 | def block_level_tags(self) -> set[str]: |
| 55 | # Read from the Markdown instance so tags registered after the |
| 56 | # extension is loaded (md.block_level_elements.append) are honored. |
| 57 | return set(self.md.block_level_elements) |
| 58 | |
| 59 | @property |
| 60 | def block_tags(self) -> set[str]: |
| 61 | return set(self.block_level_tags) - (self.span_tags | self.raw_tags | self.empty_tags) |
| 62 | |
| 63 | @property |
| 64 | def span_and_blocks_tags(self) -> set[str]: |
| 65 | return self.block_tags | self.span_tags |
| 66 | |
| 67 | def reset(self): |
| 68 | """Reset this instance. Loses all unprocessed data.""" |
| 69 | self.mdstack: list[str] = [] # When markdown=1, stack contains a list of tags |
| 70 | self.treebuilder = etree.TreeBuilder() |
| 71 | self.mdstate: list[Literal['block', 'span', 'off', None]] = [] |
| 72 | self.mdstarted: list[bool] = [] |
| 73 | super().reset() |
| 74 | |
| 75 | def close(self): |
| 76 | """Handle any buffered data.""" |
| 77 | super().close() |
| 78 | # Handle any unclosed tags. |
| 79 | if self.mdstack: |
| 80 | # Close the outermost parent. `handle_endtag` will close all unclosed children. |
| 81 | self.handle_endtag(self.mdstack[0]) |
| 82 | |
| 83 | def get_element(self) -> etree.Element: |
| 84 | """ Return element from `treebuilder` and reset `treebuilder` for later use. """ |
| 85 | element = self.treebuilder.close() |
| 86 | self.treebuilder = etree.TreeBuilder() |
| 87 | return element |
| 88 | |
| 89 | def get_state(self, tag, attrs: Mapping[str, str]) -> Literal['block', 'span', 'off', None]: |
| 90 | """ Return state from tag and `markdown` attribute. One of 'block', 'span', or 'off'. """ |
| 91 | md_attr = attrs.get('markdown', '0') |
| 92 | if md_attr == 'markdown': |
| 93 | # `<tag markdown>` is the same as `<tag markdown='1'>`. |
| 94 | md_attr = '1' |