""" Java org.w3c.dom APIs implemented in Python. org.w3c.dom package - Document, Node, Element, Attr, Text, etc. Wraps Python xml.dom module. """ from __future__ import annotations from .._core import Stub, AndroidOnlyError import xml.dom as _dom import xml.dom.minidom as _minidom from typing import List, Optional __all__ = [ "Document", "Node", "Element", "Attr", "Text", "Comment", "CDATASection", "DocumentType", "Notation", "Entity", "EntityReference", "ProcessingInstruction", "NodeList", "NamedNodeMap", "DOMImplementation", "DOMConfiguration", "DOMException", "UserDataHandler", "DOMError", "DOMLocator", "DOMErrorHandler", "TypeInfo", ] # ============================================================ # Constants # ============================================================ class NodeConstants: ELEMENT_NODE: int = 1 ATTRIBUTE_NODE: int = 2 TEXT_NODE: int = 3 CDATA_SECTION_NODE: int = 4 ENTITY_REFERENCE_NODE: int = 5 ENTITY_NODE: int = 6 PROCESSING_INSTRUCTION_NODE: int = 7 COMMENT_NODE: int = 8 DOCUMENT_NODE: int = 9 DOCUMENT_TYPE_NODE: int = 10 DOCUMENT_FRAGMENT_NODE: int = 11 NOTATION_NODE: int = 12 DOCUMENT_POSITION_DISCONNECTED: int = 0x01 DOCUMENT_POSITION_PRECEDING: int = 0x02 DOCUMENT_POSITION_FOLLOWING: int = 0x04 DOCUMENT_POSITION_CONTAINS: int = 0x08 DOCUMENT_POSITION_CONTAINED_BY: int = 0x10 DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC: int = 0x20 # ============================================================ # DOMException # ============================================================ class DOMException(Exception, Stub): """ org.w3c.dom.DOMException Exception for DOM operations. """ INDEX_SIZE_ERR: int = 1 DOMSTRING_SIZE_ERR: int = 2 HIERARCHY_REQUEST_ERR: int = 3 WRONG_DOCUMENT_ERR: int = 4 INVALID_CHARACTER_ERR: int = 5 NO_DATA_ALLOWED_ERR: int = 6 NO_MODIFICATION_ALLOWED_ERR: int = 7 NOT_FOUND_ERR: int = 8 NOT_SUPPORTED_ERR: int = 9 INUSE_ATTRIBUTE_ERR: int = 10 INVALID_STATE_ERR: int = 11 SYNTAX_ERR: int = 12 INVALID_MODIFICATION_ERR: int = 13 NAMESPACE_ERR: int = 14 INVALID_ACCESS_ERR: int = 15 VALIDATION_ERR: int = 16 TYPE_MISMATCH_ERR: int = 17 def __init__(self, code: int = 0, message: str = None): super().__init__(message or f"DOM error code {code}") self._code = code self._message = message def code(self) -> int: return self._code def toString(self) -> str: return f"DOMException[{self._code}]: {self._message}" def equals(self, other) -> bool: if isinstance(other, DOMException): return self._code == other._code return False def hashCode(self) -> int: return hash(self._code) & 0x7FFFFFFF # ============================================================ # NodeList # ============================================================ class NodeList(Stub): """ org.w3c.dom.NodeList Ordered list of nodes. """ def __init__(self, nodes: List = None): super().__init__() self._nodes = list(nodes) if nodes else [] def getLength(self) -> int: return len(self._nodes) def item(self, index: int) -> Optional["Node"]: if 0 <= index < len(self._nodes): return self._nodes[index] return None def __len__(self): return len(self._nodes) def __iter__(self): return iter(self._nodes) def __getitem__(self, index): return self._nodes[index] def toString(self) -> str: return f"NodeList@{hex(id(self))}[length={len(self._nodes)}]" def equals(self, other) -> bool: return self is other def hashCode(self) -> int: return hash(self) & 0x7FFFFFFF # ============================================================ # NamedNodeMap # ============================================================ class NamedNodeMap(Stub): """ org.w3c.dom.NamedNodeMap Collection of nodes accessible by name. """ def __init__(self): super().__init__() self._nodes = {} def getNamedItem(self, name: str) -> Optional["Node"]: return self._nodes.get(name) def setNamedItem(self, arg: "Node") -> Optional["Node"]: name = arg.getNodeName() old = self._nodes.get(name) self._nodes[name] = arg return old def removeNamedItem(self, name: str) -> Optional["Node"]: return self._nodes.pop(name, None) def item(self, index: int) -> Optional["Node"]: keys = list(self._nodes.keys()) if 0 <= index < len(keys): return self._nodes[keys[index]] return None def getLength(self) -> int: return len(self._nodes) def getNamedItemNS(self, namespace_uri: str, local_name: str) -> Optional["Node"]: for name, node in self._nodes.items(): if node.getNamespaceURI() == namespace_uri and node.getLocalName() == local_name: return node return None def setNamedItemNS(self, arg: "Node") -> Optional["Node"]: return self.setNamedItem(arg) def removeNamedItemNS(self, namespace_uri: str, local_name: str) -> Optional["Node"]: for name, node in list(self._nodes.items()): if node.getNamespaceURI() == namespace_uri and node.getLocalName() == local_name: return self._nodes.pop(name, None) return None def toString(self) -> str: return f"NamedNodeMap@{hex(id(self))}[length={len(self._nodes)}]" def equals(self, other) -> bool: return self is other def hashCode(self) -> int: return hash(self) & 0x7FFFFFFF # ============================================================ # Node # ============================================================ class Node(Stub): """ org.w3c.dom.Node The primary datatype for the DOM. """ ELEMENT_NODE: int = NodeConstants.ELEMENT_NODE ATTRIBUTE_NODE: int = NodeConstants.ATTRIBUTE_NODE TEXT_NODE: int = NodeConstants.TEXT_NODE CDATA_SECTION_NODE: int = NodeConstants.CDATA_SECTION_NODE ENTITY_REFERENCE_NODE: int = NodeConstants.ENTITY_REFERENCE_NODE ENTITY_NODE: int = NodeConstants.ENTITY_NODE PROCESSING_INSTRUCTION_NODE: int = NodeConstants.PROCESSING_INSTRUCTION_NODE COMMENT_NODE: int = NodeConstants.COMMENT_NODE DOCUMENT_NODE: int = NodeConstants.DOCUMENT_NODE DOCUMENT_TYPE_NODE: int = NodeConstants.DOCUMENT_TYPE_NODE DOCUMENT_FRAGMENT_NODE: int = NodeConstants.DOCUMENT_FRAGMENT_NODE NOTATION_NODE: int = NodeConstants.NOTATION_NODE DOCUMENT_POSITION_DISCONNECTED: int = NodeConstants.DOCUMENT_POSITION_DISCONNECTED DOCUMENT_POSITION_PRECEDING: int = NodeConstants.DOCUMENT_POSITION_PRECEDING DOCUMENT_POSITION_FOLLOWING: int = NodeConstants.DOCUMENT_POSITION_FOLLOWING DOCUMENT_POSITION_CONTAINS: int = NodeConstants.DOCUMENT_POSITION_CONTAINS DOCUMENT_POSITION_CONTAINED_BY: int = NodeConstants.DOCUMENT_POSITION_CONTAINED_BY DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC: int = NodeConstants.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC def __init__(self, node_type: int = ELEMENT_NODE, node_name: str = "", node_value: str = None): super().__init__() self._node_type = node_type self._node_name = node_name self._node_value = node_value self._parent_node = None self._child_nodes = [] self._first_child = None self._last_child = None self._previous_sibling = None self._next_sibling = None self._attributes = NamedNodeMap() self._owner_document = None self._namespace_uri = None self._prefix = None self._local_name = None self._user_data = {} def getNodeName(self) -> str: return self._node_name def getNodeValue(self) -> Optional[str]: return self._node_value def setNodeValue(self, value: str): self._node_value = value def getNodeType(self) -> int: return self._node_type def getParentNode(self) -> Optional["Node"]: return self._parent_node def getChildNodes(self) -> NodeList: return NodeList(self._child_nodes) def getFirstChild(self) -> Optional["Node"]: return self._child_nodes[0] if self._child_nodes else None def getLastChild(self) -> Optional["Node"]: return self._child_nodes[-1] if self._child_nodes else None def getPreviousSibling(self) -> Optional["Node"]: return self._previous_sibling def getNextSibling(self) -> Optional["Node"]: return self._next_sibling def getAttributes(self) -> NamedNodeMap: return self._attributes def getOwnerDocument(self) -> Optional["Document"]: return self._owner_document def insertBefore(self, new_child: "Node", ref_child: Optional["Node"]) -> "Node": if ref_child is None: return self.appendChild(new_child) idx = self._child_nodes.index(ref_child) if ref_child in self._child_nodes else len(self._child_nodes) self._child_nodes.insert(idx, new_child) new_child._parent_node = self self._update_siblings() return new_child def replaceChild(self, new_child: "Node", old_child: "Node") -> "Node": if old_child in self._child_nodes: idx = self._child_nodes.index(old_child) self._child_nodes[idx] = new_child new_child._parent_node = self self._update_siblings() return old_child return None def removeChild(self, old_child: "Node") -> "Node": if old_child in self._child_nodes: self._child_nodes.remove(old_child) old_child._parent_node = None self._update_siblings() return old_child return None def appendChild(self, new_child: "Node") -> "Node": self._child_nodes.append(new_child) new_child._parent_node = self self._update_siblings() return new_child def hasChildNodes(self) -> bool: return len(self._child_nodes) > 0 def cloneNode(self, deep: bool) -> "Node": cloned = Node(self._node_type, self._node_name, self._node_value) if deep: for child in self._child_nodes: cloned.appendChild(child.cloneNode(True)) return cloned def normalize(self): """Merges adjacent text nodes.""" i = 0 while i < len(self._child_nodes) - 1: if (self._child_nodes[i].getNodeType() == Node.TEXT_NODE and self._child_nodes[i + 1].getNodeType() == Node.TEXT_NODE): combined = self._child_nodes[i].getNodeValue() + self._child_nodes[i + 1].getNodeValue() self._child_nodes[i].setNodeValue(combined) self._child_nodes.pop(i + 1) self._update_siblings() else: i += 1 def isSupported(self, feature: str, version: str) -> bool: return feature in ("XML", "DOM", "Core") def getNamespaceURI(self) -> Optional[str]: return self._namespace_uri def getPrefix(self) -> Optional[str]: return self._prefix def setPrefix(self, prefix: str): self._prefix = prefix def getLocalName(self) -> Optional[str]: return self._local_name def hasAttributes(self) -> bool: return self._attributes.getLength() > 0 def lookupNamespaceURI(self, prefix: str) -> Optional[str]: if self._prefix == prefix: return self._namespace_uri if self._parent_node: return self._parent_node.lookupNamespaceURI(prefix) return None def lookupPrefix(self, namespace_uri: str) -> Optional[str]: if self._namespace_uri == namespace_uri: return self._prefix if self._parent_node: return self._parent_node.lookupPrefix(namespace_uri) return None def isDefaultNamespace(self, namespace_uri: str) -> bool: return self._namespace_uri == namespace_uri def getBaseURI(self) -> Optional[str]: return None def compareDocumentPosition(self, other: "Node") -> int: """Compares the document position of two nodes.""" return Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC def getTextContent(self) -> str: parts = [] for child in self._child_nodes: if child.getNodeType() == Node.TEXT_NODE or child.getNodeType() == Node.CDATA_SECTION_NODE: parts.append(child.getNodeValue() or "") parts.append(child.getTextContent() or "") return "".join(parts) def setTextContent(self, text: str): self._child_nodes = [Text(text)] self._update_siblings() def isSameNode(self, other: "Node") -> bool: return self is other def isEqualNode(self, other: "Node") -> bool: if self._node_type != other._node_type or self._node_name != other._node_name: return False return self._node_value == other._node_value def getFeature(self, feature: str, version: str): return None def setUserData(self, key: str, data: Any, handler: Any = None) -> Any: old = self._user_data.get(key) self._user_data[key] = data return old def getUserData(self, key: str) -> Any: return self._user_data.get(key) def _update_siblings(self): for i, child in enumerate(self._child_nodes): child._previous_sibling = self._child_nodes[i - 1] if i > 0 else None child._next_sibling = self._child_nodes[i + 1] if i < len(self._child_nodes) - 1 else None def toString(self) -> str: return f"Node[{self._node_name}]" def equals(self, other) -> bool: return self is other def hashCode(self) -> int: return hash(self) & 0x7FFFFFFF # ============================================================ # Document # ============================================================ class Document(Node): """ org.w3c.dom.Document Represents an XML document. """ def __init__(self): super().__init__(Node.DOCUMENT_NODE, "#document", None) self._document_element = None self._doctype = None self._implementation = DOMImplementation() self._input_encoding = "UTF-8" self._xml_encoding = "UTF-8" self._xml_standalone = False self._xml_version = "1.0" self._strict_error_checking = True self._document_uri = None self._dom_config = DOMConfiguration() def getDocumentElement(self) -> Optional["Element"]: return self._document_element def getElementsByTagName(self, tagname: str) -> NodeList: result = [] self._collect_elements_by_tag(self._document_element, tagname, result) return NodeList(result) def _collect_elements_by_tag(self, node: Node, tagname: str, result: List): if node is None: return if isinstance(node, Element) and (tagname == "*" or node.getTagName() == tagname): result.append(node) for child in node._child_nodes: self._collect_elements_by_tag(child, tagname, result) def getElementById(self, element_id: str) -> Optional["Element"]: result = [] self._collect_elements_by_tag(self._document_element, "*", result) for el in result: if el.getAttribute("id") == element_id: return el return None def createElement(self, tag_name: str) -> "Element": el = Element(tag_name) el._owner_document = self return el def createDocumentFragment(self): frag = Node(Node.DOCUMENT_FRAGMENT_NODE, "#document-fragment", None) frag._owner_document = self return frag def createTextNode(self, data: str) -> "Text": tn = Text(data) tn._owner_document = self return tn def createComment(self, data: str) -> "Comment": c = Comment(data) c._owner_document = self return c def createCDATASection(self, data: str) -> "CDATASection": cs = CDATASection(data) cs._owner_document = self return cs def createProcessingInstruction(self, target: str, data: str) -> "ProcessingInstruction": pi = ProcessingInstruction(target, data) pi._owner_document = self return pi def createAttribute(self, name: str) -> "Attr": attr = Attr(name) attr._owner_document = self return attr def createEntityReference(self, name: str) -> "EntityReference": er = EntityReference(name) er._owner_document = self return er def importNode(self, imported_node: Node, deep: bool) -> Node: return imported_node.cloneNode(deep) def adoptNode(self, node: Node) -> Node: node._owner_document = self return node def createAttributeNS(self, namespace_uri: str, qualified_name: str) -> "Attr": attr = Attr(qualified_name) attr._namespace_uri = namespace_uri attr._owner_document = self return attr def createElementNS(self, namespace_uri: str, qualified_name: str) -> "Element": el = Element(qualified_name) el._namespace_uri = namespace_uri el._owner_document = self return el def getDoctype(self) -> Optional["DocumentType"]: return self._doctype def getImplementation(self) -> "DOMImplementation": return self._implementation def getInputEncoding(self) -> str: return self._input_encoding def getXmlEncoding(self) -> str: return self._xml_encoding def getXmlStandalone(self) -> bool: return self._xml_standalone def setXmlStandalone(self, standalone: bool): self._xml_standalone = standalone def getXmlVersion(self) -> str: return self._xml_version def setXmlVersion(self, version: str): self._xml_version = version def getStrictErrorChecking(self) -> bool: return self._strict_error_checking def setStrictErrorChecking(self, strict: bool): self._strict_error_checking = strict def getDocumentURI(self) -> Optional[str]: return self._document_uri def setDocumentURI(self, uri: str): self._document_uri = uri def getDomConfig(self) -> "DOMConfiguration": return self._dom_config def normalizeDocument(self): self.normalize() def renameNode(self, node: Node, namespace_uri: str, qualified_name: str) -> Node: node._node_name = qualified_name node._namespace_uri = namespace_uri return node def toString(self) -> str: return f"Document@{hex(id(self))}" def equals(self, other) -> bool: return self is other def hashCode(self) -> int: return hash(self) & 0x7FFFFFFF # ============================================================ # Element # ============================================================ class Element(Node): """ org.w3c.dom.Element Represents an element in an XML document. """ def __init__(self, tag_name: str): super().__init__(Node.ELEMENT_NODE, tag_name, None) self._tag_name = tag_name self._local_name = tag_name self._schema_type = None def getTagName(self) -> str: return self._tag_name def getAttribute(self, name: str) -> str: attr = self._attributes.getNamedItem(name) return attr.getNodeValue() if attr else "" def getAttributeNode(self, name: str) -> Optional["Attr"]: return self._attributes.getNamedItem(name) def getElementsByTagName(self, tagname: str) -> NodeList: result = [] doc = self.getOwnerDocument() if doc: doc._collect_elements_by_tag(self, tagname, result) return NodeList(result) def getAttributeNS(self, namespace_uri: str, local_name: str) -> str: attr = self._attributes.getNamedItemNS(namespace_uri, local_name) return attr.getNodeValue() if attr else "" def setAttribute(self, name: str, value: str): attr = Attr(name, value) self._attributes.setNamedItem(attr) def setAttributeNS(self, namespace_uri: str, qualified_name: str, value: str): attr = Attr(qualified_name, value) attr._namespace_uri = namespace_uri self._attributes.setNamedItem(attr) def removeAttribute(self, name: str): self._attributes.removeNamedItem(name) def removeAttributeNS(self, namespace_uri: str, local_name: str): self._attributes.removeNamedItemNS(namespace_uri, local_name) def getAttributeNodeNS(self, namespace_uri: str, local_name: str) -> Optional["Attr"]: return self._attributes.getNamedItemNS(namespace_uri, local_name) def setAttributeNode(self, new_attr: "Attr") -> Optional["Attr"]: return self._attributes.setNamedItem(new_attr) def setAttributeNodeNS(self, new_attr: "Attr") -> Optional["Attr"]: return self._attributes.setNamedItemNS(new_attr) def removeAttributeNode(self, old_attr: "Attr") -> Optional["Attr"]: return self._attributes.removeNamedItem(old_attr.getNodeName()) def getElementsByTagNameNS(self, namespace_uri: str, local_name: str) -> NodeList: result = [] self._collect_elements_by_tag_ns(self, namespace_uri, local_name, result) return NodeList(result) def _collect_elements_by_tag_ns(self, node, ns, name, result): if node is None: return if (isinstance(node, Element) and (ns == "*" or node.getNamespaceURI() == ns) and (name == "*" or node.getLocalName() == name)): result.append(node) for child in node._child_nodes: self._collect_elements_by_tag_ns(child, ns, name, result) def hasAttribute(self, name: str) -> bool: return self._attributes.getNamedItem(name) is not None def hasAttributeNS(self, namespace_uri: str, local_name: str) -> bool: return self._attributes.getNamedItemNS(namespace_uri, local_name) is not None def getSchemaTypeInfo(self): return self._schema_type def setIdAttribute(self, name: str, is_id: bool): pass def setIdAttributeNS(self, namespace_uri: str, local_name: str, is_id: bool): pass def setIdAttributeNode(self, id_attr: "Attr", is_id: bool): pass def toString(self) -> str: return f"Element[{self._tag_name}]" def equals(self, other) -> bool: return self is other def hashCode(self) -> int: return hash(self) & 0x7FFFFFFF # ============================================================ # Attr # ============================================================ class Attr(Node): """ org.w3c.dom.Attr Represents an attribute in a DOM document. """ def __init__(self, name: str, value: str = ""): super().__init__(Node.ATTRIBUTE_NODE, name, value) self._specified = True self._owner_element = None self._is_id = False self._schema_type = None self._local_name = name def getName(self) -> str: return self._node_name def getValue(self) -> str: return self._node_value or "" def setValue(self, value: str): self._node_value = value self._specified = True def getOwnerElement(self) -> Optional[Element]: return self._owner_element def getSpecified(self) -> bool: return self._specified def getSchemaTypeInfo(self): return self._schema_type def isId(self) -> bool: return self._is_id def toString(self) -> str: return f'Attr[{self._node_name}="{self._node_value}"]' def equals(self, other) -> bool: return self is other def hashCode(self) -> int: return hash(self) & 0x7FFFFFFF # ============================================================ # Text # ============================================================ class Text(Node): """ org.w3c.dom.Text Represents the textual content of an element or attribute. """ def __init__(self, data: str = ""): super().__init__(Node.TEXT_NODE, "#text", data) def splitText(self, offset: int) -> "Text": if offset >= len(self._node_value or ""): raise DOMException(DOMException.INDEX_SIZE_ERR, "Offset out of bounds") first_part = self._node_value[:offset] second_part = self._node_value[offset:] self._node_value = first_part new_text = Text(second_part) if self._parent_node: self._parent_node.insertBefore(new_text, self._next_sibling) return new_text def isElementContentWhitespace(self) -> bool: return (self._node_value or "").strip() == "" def getWholeText(self) -> str: parts = [self._node_value or ""] # Collect adjacent text nodes sibling = self._previous_sibling while sibling and sibling.getNodeType() in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE): parts.insert(0, sibling.getNodeValue() or "") sibling = sibling._previous_sibling sibling = self._next_sibling while sibling and sibling.getNodeType() in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE): parts.append(sibling.getNodeValue() or "") sibling = sibling._next_sibling return "".join(parts) def replaceWholeText(self, content: str) -> "Text": self._node_value = content # Remove adjacent text nodes siblings = [] sib = self._previous_sibling while sib and sib.getNodeType() in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE): siblings.append(sib) sib = sib._previous_sibling for s in siblings: if self._parent_node: self._parent_node.removeChild(s) siblings = [] sib = self._next_sibling while sib and sib.getNodeType() in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE): siblings.append(sib) sib = sib._next_sibling for s in siblings: if self._parent_node: self._parent_node.removeChild(s) return self def toString(self) -> str: return f"Text[{self._node_value}]" def equals(self, other) -> bool: return self is other def hashCode(self) -> int: return hash(self) & 0x7FFFFFFF # ============================================================ # Comment # ============================================================ class Comment(Node): """ org.w3c.dom.Comment Represents the content of an XML comment. """ def __init__(self, data: str = ""): super().__init__(Node.COMMENT_NODE, "#comment", data) def toString(self) -> str: return f"Comment[{self._node_value}]" def equals(self, other) -> bool: return self is other def hashCode(self) -> int: return hash(self) & 0x7FFFFFFF # ============================================================ # CDATASection # ============================================================ class CDATASection(Text): """ org.w3c.dom.CDATASection Represents a CDATA section. """ def __init__(self, data: str = ""): super().__init__(data) self._node_type = Node.CDATA_SECTION_NODE self._node_name = "#cdata-section" def toString(self) -> str: return f"CDATASection[{self._node_value}]" def equals(self, other) -> bool: return self is other def hashCode(self) -> int: return hash(self) & 0x7FFFFFFF # ============================================================ # DocumentType # ============================================================ class DocumentType(Node): """ org.w3c.dom.DocumentType Represents a document type declaration. """ def __init__(self, name: str = "", public_id: str = "", system_id: str = "", internal_subset: str = ""): super().__init__(Node.DOCUMENT_TYPE_NODE, name, None) self._name = name self._entities = NamedNodeMap() self._notations = NamedNodeMap() self._public_id = public_id self._system_id = system_id self._internal_subset = internal_subset def getName(self) -> str: return self._name def getEntities(self) -> NamedNodeMap: return self._entities def getNotations(self) -> NamedNodeMap: return self._notations def getPublicId(self) -> str: return self._public_id def getSystemId(self) -> str: return self._system_id def getInternalSubset(self) -> str: return self._internal_subset def toString(self) -> str: return f"DocumentType[{self._name}]" def equals(self, other) -> bool: return self is other def hashCode(self) -> int: return hash(self) & 0x7FFFFFFF # ============================================================ # Notation # ============================================================ class Notation(Node): """ org.w3c.dom.Notation Represents a notation in a DTD. """ def __init__(self, name: str = "", public_id: str = "", system_id: str = ""): super().__init__(Node.NOTATION_NODE, name, None) self._public_id = public_id self._system_id = system_id def getPublicId(self) -> str: return self._public_id def getSystemId(self) -> str: return self._system_id def toString(self) -> str: return f"Notation[{self._node_name}]" def equals(self, other) -> bool: return self is other def hashCode(self) -> int: return hash(self) & 0x7FFFFFFF # ============================================================ # Entity # ============================================================ class Entity(Node): """ org.w3c.dom.Entity Represents an entity in a DTD. """ def __init__(self, name: str = "", public_id: str = "", system_id: str = "", notation_name: str = ""): super().__init__(Node.ENTITY_NODE, name, None) self._public_id = public_id self._system_id = system_id self._notation_name = notation_name self._input_encoding = "UTF-8" self._xml_encoding = "UTF-8" self._xml_version = "1.0" def getPublicId(self) -> str: return self._public_id def getSystemId(self) -> str: return self._system_id def getNotationName(self) -> str: return self._notation_name def getInputEncoding(self) -> str: return self._input_encoding def getXmlEncoding(self) -> str: return self._xml_encoding def getXmlVersion(self) -> str: return self._xml_version def toString(self) -> str: return f"Entity[{self._node_name}]" def equals(self, other) -> bool: return self is other def hashCode(self) -> int: return hash(self) & 0x7FFFFFFF class EntityReference(Node): """ org.w3c.dom.EntityReference Represents an entity reference. """ def __init__(self, name: str = ""): super().__init__(Node.ENTITY_REFERENCE_NODE, name, None) def toString(self) -> str: return f"EntityReference[{self._node_name}]" def equals(self, other) -> bool: return self is other def hashCode(self) -> int: return hash(self) & 0x7FFFFFFF # ============================================================ # ProcessingInstruction # ============================================================ class ProcessingInstruction(Node): """ org.w3c.dom.ProcessingInstruction Represents a processing instruction. """ def __init__(self, target: str = "", data: str = ""): super().__init__(Node.PROCESSING_INSTRUCTION_NODE, target, data) self._target = target self._data = data def getTarget(self) -> str: return self._target def getData(self) -> str: return self._data def setData(self, data: str): self._data = data def toString(self) -> str: return f"ProcessingInstruction[{self._target}]" def equals(self, other) -> bool: return self is other def hashCode(self) -> int: return hash(self) & 0x7FFFFFFF # ============================================================ # DOMImplementation # ============================================================ class DOMImplementation(Stub): """ org.w3c.dom.DOMImplementation Interface for DOM implementation. """ def __init__(self): super().__init__() def hasFeature(self, feature: str, version: str) -> bool: return feature in ("XML", "Core", "DOM") and version in ("1.0", "2.0", "3.0", "") def createDocumentType(self, qualified_name: str, public_id: str, system_id: str) -> DocumentType: return DocumentType(qualified_name, public_id, system_id) def createDocument(self, namespace_uri: str, qualified_name: str, doctype: DocumentType = None) -> Document: doc = Document() if qualified_name: root = doc.createElementNS(namespace_uri or "", qualified_name) doc.appendChild(root) doc._document_element = root doc._doctype = doctype return doc def getFeature(self, feature: str, version: str): return self def toString(self) -> str: return f"DOMImplementation@{hex(id(self))}" def equals(self, other) -> bool: return self is other def hashCode(self) -> int: return hash(self) & 0x7FFFFFFF # ============================================================ # DOMConfiguration # ============================================================ class DOMConfiguration(Stub): """ org.w3c.dom.DOMConfiguration Configuration of a DOM document. """ def __init__(self): super().__init__() self._params = {} def setParameter(self, name: str, value: Any): self._params[name] = value def getParameter(self, name: str) -> Any: return self._params.get(name) def canSetParameter(self, name: str, value: Any) -> bool: return True def getParameterNames(self) -> NodeList: return NodeList([Node(Node.TEXT_NODE, k, str(v)) for k, v in self._params.items()]) def toString(self) -> str: return f"DOMConfiguration@{hex(id(self))}" def equals(self, other) -> bool: return self is other def hashCode(self) -> int: return hash(self) & 0x7FFFFFFF # ============================================================ # UserDataHandler # ============================================================ class UserDataHandler(Stub): """ org.w3c.dom.UserDataHandler Handler for user data events. """ NODE_ADOPTED: int = 5 NODE_CLONED: int = 1 NODE_IMPORTED: int = 2 NODE_DELETED: int = 3 NODE_RENAMED: int = 4 def handle(self, operation: int, key: str, data: Any, src: Node, dst: Node): """Called when a node is adopted, cloned, imported, deleted, or renamed.""" pass def toString(self) -> str: return f"UserDataHandler@{hex(id(self))}" def equals(self, other) -> bool: return self is other def hashCode(self) -> int: return hash(self) & 0x7FFFFFFF # ============================================================ # DOMError # ============================================================ class DOMError(Stub): """ org.w3c.dom.DOMError Represents an error in DOM operations. """ SEVERITY_WARNING: int = 1 SEVERITY_ERROR: int = 2 SEVERITY_FATAL_ERROR: int = 3 def __init__(self, severity: int = SEVERITY_ERROR, message: str = "", error_type: str = "", related_exception: Exception = None, related_data: Any = None, location: "DOMLocator" = None): super().__init__() self._severity = severity self._message = message self._type = error_type self._related_exception = related_exception self._related_data = related_data self._location = location def getSeverity(self) -> int: return self._severity def getMessage(self) -> str: return self._message def getType(self) -> str: return self._type def getRelatedException(self) -> Exception: return self._related_exception def getRelatedData(self) -> Any: return self._related_data def getLocation(self) -> "DOMLocator": return self._location def toString(self) -> str: return f"DOMError[{self._type}]: {self._message}" def equals(self, other) -> bool: return self is other def hashCode(self) -> int: return hash(self) & 0x7FFFFFFF # ============================================================ # DOMLocator # ============================================================ class DOMLocator(Stub): """ org.w3c.dom.DOMLocator Location information for DOM errors. """ def __init__(self, line: int = 0, column: int = 0, byte_offset: int = -1, utf16_offset: int = -1, related_node: Node = None, uri: str = ""): super().__init__() self._line = line self._column = column self._byte_offset = byte_offset self._utf16_offset = utf16_offset self._related_node = related_node self._uri = uri def getLineNumber(self) -> int: return self._line def getColumnNumber(self) -> int: return self._column def getByteOffset(self) -> int: return self._byte_offset def getUtf16Offset(self) -> int: return self._utf16_offset def getRelatedNode(self) -> Node: return self._related_node def getUri(self) -> str: return self._uri def toString(self) -> str: return f"DOMLocator[line={self._line}, col={self._column}]" def equals(self, other) -> bool: return self is other def hashCode(self) -> int: return hash(self) & 0x7FFFFFFF # ============================================================ # DOMErrorHandler # ============================================================ class DOMErrorHandler(Stub): """ org.w3c.dom.DOMErrorHandler Handler for DOM errors. """ def handleError(self, error: DOMError) -> bool: """Returns True to continue, False to stop processing.""" return True def toString(self) -> str: return f"DOMErrorHandler@{hex(id(self))}" def equals(self, other) -> bool: return self is other def hashCode(self) -> int: return hash(self) & 0x7FFFFFFF # ============================================================ # TypeInfo # ============================================================ class TypeInfo(Stub): """ org.w3c.dom.TypeInfo Represents type information about an element or attribute. """ DERIVATION_RESTRICTION: int = 1 DERIVATION_EXTENSION: int = 2 DERIVATION_UNION: int = 4 DERIVATION_LIST: int = 8 def __init__(self, type_name: str = "", type_namespace: str = ""): super().__init__() self._type_name = type_name self._type_namespace = type_namespace def getTypeName(self) -> str: return self._type_name def getTypeNamespace(self) -> str: return self._type_namespace def toString(self) -> str: return f"TypeInfo[{self._type_name}]" def equals(self, other) -> bool: return self is other def hashCode(self) -> int: return hash(self) & 0x7FFFFFFF