diff options
| author | Michael Williamson <mike@zwobble.org> | 2024-02-17 13:52:16 +0000 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2024-02-17 13:52:16 +0000 |
| commit | fe41ddbc51b4b7c6ce7d958ea7622983d7805b7e (patch) | |
| tree | 6a477e4a54657b5b89b87141ed85f088c2f03015 /mammoth/styles/parser | |
| parent | d037ef5cf7fc976047bed20859dbcd5c90f45d67 (diff) | |
Support attributes in HTML paths in style mappings
Diffstat (limited to 'mammoth/styles/parser')
| -rw-r--r-- | mammoth/styles/parser/html_path_parser.py | 74 | ||||
| -rw-r--r-- | mammoth/styles/parser/token_iterator.py | 25 |
2 files changed, 71 insertions, 28 deletions
diff --git a/mammoth/styles/parser/html_path_parser.py b/mammoth/styles/parser/html_path_parser.py index 9e155b6..8ed6fed 100644 --- a/mammoth/styles/parser/html_path_parser.py +++ b/mammoth/styles/parser/html_path_parser.py @@ -1,6 +1,15 @@ +import cobble + from ... import html_paths from .tokeniser import TokenType -from .token_parser import parse_identifier, parse_string, try_parse_class_name +from .token_parser import parse_identifier, parse_string + + +@cobble.data +class _AttributeOrClassName(object): + name = cobble.field() + value = cobble.field() + append = cobble.field() def parse_html_path(tokens): @@ -12,26 +21,33 @@ def parse_html_path(tokens): def _parse_html_path_elements(tokens): elements = [] - + if tokens.peek_token_type() == TokenType.IDENTIFIER: elements.append(_parse_element(tokens)) - + while tokens.try_skip_many(((TokenType.WHITESPACE, None), (TokenType.SYMBOL, ">"))): tokens.skip(TokenType.WHITESPACE) elements.append(_parse_element(tokens)) - + return elements def _parse_element(tokens): tag_names = _parse_tag_names(tokens) - class_names = _parse_class_names(tokens) + attributes_list = _parse_attribute_or_class_names(tokens) is_fresh = _parse_is_fresh(tokens) separator = _parse_separator(tokens) - + + attributes = {} + for attribute in attributes_list: + if attribute.append and attributes.get(attribute.name): + attributes[attribute.name] += " " + attribute.value + else: + attributes[attribute.name] = attribute.value + return html_paths.element( tag_names, - class_names=class_names, + attributes=attributes, fresh=is_fresh, separator=separator, ) @@ -39,24 +55,48 @@ def _parse_element(tokens): def _parse_tag_names(tokens): tag_names = [parse_identifier(tokens)] - + while tokens.try_skip(TokenType.SYMBOL, "|"): tag_names.append(parse_identifier(tokens)) - + return tag_names -def _parse_class_names(tokens): - class_names = [] - +def _parse_attribute_or_class_names(tokens): + attribute_or_class_names = [] + while True: - class_name = try_parse_class_name(tokens) - if class_name is None: + attribute_or_class_name = _try_parse_attribute_or_class_name(tokens) + if attribute_or_class_name is None: break else: - class_names.append(class_name) - - return class_names + attribute_or_class_names.append(attribute_or_class_name) + + return attribute_or_class_names + + +def _try_parse_attribute_or_class_name(tokens): + if tokens.is_next(TokenType.SYMBOL, "["): + return _parse_attribute(tokens) + if tokens.is_next(TokenType.SYMBOL, "."): + return _parse_class_name(tokens) + else: + return None + + +def _parse_attribute(tokens): + tokens.skip(TokenType.SYMBOL, "[") + name = parse_identifier(tokens) + tokens.skip(TokenType.SYMBOL, "=") + value = parse_string(tokens) + tokens.skip(TokenType.SYMBOL, "]") + return _AttributeOrClassName(name=name, value=value, append=False) + + +def _parse_class_name(tokens): + tokens.skip(TokenType.SYMBOL, ".") + class_name = parse_identifier(tokens) + return _AttributeOrClassName(name="class", value=class_name, append=True) def _parse_is_fresh(tokens): diff --git a/mammoth/styles/parser/token_iterator.py b/mammoth/styles/parser/token_iterator.py index fded56d..931b419 100644 --- a/mammoth/styles/parser/token_iterator.py +++ b/mammoth/styles/parser/token_iterator.py @@ -8,13 +8,13 @@ class TokenIterator(object): def __init__(self, tokens): self._tokens = tokens self._index = 0 - + def peek_token_type(self): return self._tokens[self._index].type - + def next_value(self, token_type=None): return self._next(token_type).value - + def _next(self, token_type=None): token = self._tokens[self._index] if token_type is None or token.type == token_type: @@ -22,7 +22,7 @@ class TokenIterator(object): return token else: raise self._unexpected_token_type(token_type, token) - + def skip(self, token_type, token_value=None): token = self._tokens[self._index] if token.type == token_type and (token_value is None or token.value == token_value): @@ -30,15 +30,14 @@ class TokenIterator(object): return True else: raise self._unexpected_token_type(token_type, token) - + def try_skip(self, token_type, token_value=None): - token = self._tokens[self._index] - if token.type == token_type and (token_value is None or token.value == token_value): + if self.is_next(token_type, token_value): self._index += 1 return True else: return False - + def try_skip_many(self, tokens): start = self._index for token_type, token_value in tokens: @@ -48,9 +47,13 @@ class TokenIterator(object): return False else: self._index += 1 - + return True - + + def is_next(self, token_type, token_value=None): + token = self._tokens[self._index] + return token.type == token_type and (token_value is None or token.value == token_value) + def _unexpected_token_type(self, token_type, token): raise LineParseError() - + |
