CCCPaste

9683e0bc60247

from typing import List, Union

class SSMLNode:
    pass

class SSMLText(SSMLNode):
    def __init__(self, text: str):
        self.text = text

    def __eq__(self, other):
        return isinstance(other, SSMLText) and self.text == other.text

    def __repr__(self):
        return f"SSMLText({self.text!r})"

class SSMLAttribute:
    def __init__(self, name: str, value: str):
        self.name = name
        self.value = value

    def __eq__(self, other):
        return isinstance(other, SSMLAttribute) and self.name == other.name and self.value == other.value

    def __repr__(self):
        return f"SSMLAttribute({self.name!r}, {self.value!r})"

class SSMLElement(SSMLNode):
    def __init__(self, name: str, attributes: List[SSMLAttribute], children: List[SSMLNode]):
        self.name = name
        self.attributes = attributes
        self.children = children

    def __eq__(self, other):
        return (
            isinstance(other, SSMLElement) and
            self.name == other.name and
            self.attributes == other.attributes and
            self.children == other.children
        )

    def __repr__(self):
        return f"SSMLElement({self.name!r}, {self.attributes!r}, {self.children!r})"

class Ssml:
    @staticmethod
    def parse_ssml(ssml: str) -> SSMLNode:
        if not Ssml.validate_input_ssml(ssml):
            raise ValueError("Tags could not be parsed")
        return Ssml.get_ssml_node(ssml)

    @staticmethod
    def validate_input_ssml(input_string: str) -> bool:
        return input_string.startswith("")

    @staticmethod
    def get_ssml_node(input_string: str) -> SSMLNode:
        if not input_string:
            return None
        if not input_string.startswith("<") or not input_string.endswith(">"):
            raise ValueError("Tags could not be parsed")
        if "<" not in input_string or ">" not in input_string:
            return SSMLText(Ssml.unescape_xml_chars(input_string))
        name = input_string[input_string.index("<")+1:input_string.index(">")].strip()
        start_tag = f"<{name}>"
        ssml_attributes = []
        if " " in name:
            attribute_string = name[name.index(" ")+1:]
            if "=" not in attribute_string:
                raise ValueError("Attributes could not be parsed")
            while "=" in attribute_string:
                key = attribute_string[:attribute_string.index("=")].strip()
                if not key:
                    raise ValueError("Attributes could not be parsed")
                attribute_string = attribute_string[attribute_string.index("=")+1:].strip()
                end_index = len(attribute_string) if " " not in attribute_string else attribute_string.index(" ")
                value = attribute_string[:end_index].strip()
                if Ssml.count_double_quotes(value) != 2:
                    raise ValueError("Attributes could not be parsed")
                value = value.replace('"', '')
                ssml_attributes.append(SSMLAttribute(key, value))
                attribute_string = attribute_string[end_index:]
            name = name[:name.index(" ")]
        end_tag = f""
        if start_tag not in input_string or end_tag not in input_string:
            raise ValueError("Tags could not be parsed")
        body = input_string[len(start_tag):input_string.rindex(end_tag)]
        if not body:
            return SSMLElement(name, ssml_attributes, [])
        if "<" not in body and ">" not in body:
            return SSMLElement(name, ssml_attributes, [SSMLText(Ssml.unescape_xml_chars(body))])
        if ("<" not in body and ">" in body) or ("<" in body and ">" not in body):
            raise ValueError("Tags could not be parsed")
        before = body[:body.index("<")]
        after = body[body.rindex(">")+1:]
        children = body[len(before):body.rindex(">")+1]
        child_nodes = []
        if before:
            child_nodes.append(SSMLText(Ssml.unescape_xml_chars(before)))
        if children:
            child_nodes.append(Ssml.get_ssml_node(children))
        if after:
            child_nodes.append(SSMLText(Ssml.unescape_xml_chars(after)))
        return SSMLElement(name, ssml_attributes, child_nodes)

    @staticmethod
    def count_double_quotes(s: str) -> int:
        return s.count('"')

    @staticmethod
    def ssml_node_to_text(node: SSMLNode) -> str:
        ssml_text_list = Ssml.get_ssml_text_list(node)
        return ''.join([t.text for t in ssml_text_list])

    @staticmethod
    def get_ssml_text_list(node: SSMLNode) -> List[SSMLText]:
        ssml_text_list = []
        if isinstance(node, SSMLText):
            ssml_text_list.append(node)
        elif isinstance(node, SSMLElement):
            for child in node.children:
                ssml_text_list.extend(Ssml.get_ssml_text_list(child))
        return ssml_text_list

    @staticmethod
    def unescape_xml_chars(text: str) -> str:
        return text.replace("<", "<").replace(">", ">").replace("&", "&")