From fe41ddbc51b4b7c6ce7d958ea7622983d7805b7e Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Sat, 17 Feb 2024 13:52:16 +0000 Subject: Support attributes in HTML paths in style mappings --- mammoth/styles/parser/html_path_parser.py | 74 ++++++++++++++++++++++++------- 1 file changed, 57 insertions(+), 17 deletions(-) (limited to 'mammoth/styles/parser/html_path_parser.py') 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): -- cgit v1.2.3