- android/ 167个模块 (app/content/os/view/widget/graphics/media/hardware/net/telephony/provider等) - java/ 35个模块 (lang/io/util/net/nio/security/crypto/sql/beans/rmi/awt等) - javax/ 4个模块 (net/crypto/security/sql) - org/ 5个模块 (json/w3c_dom/xml_sax/xml_pull/apache_http) - dalvik/ 1个模块 (system) - ~3053个类/接口,方法签名完全对齐Android SDK - 桌面跨平台运行 (Windows/macOS/Linux) - 修复所有导入错误和Python关键字冲突
1292 lines
39 KiB
Python
1292 lines
39 KiB
Python
"""
|
|
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 |