feat: 大规模扩充至212个模块/175K行代码 — 覆盖android/java/javax/org/dalvik全包
- 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关键字冲突
This commit is contained in:
1 parent
506f9ac725
commit
a51854455b
128 files changed
+100571
-3
No files matched your search
Whitespace-only changes.
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,589 @@
|
||||
"""
|
||||
Java org.xmlpull.v1 APIs implemented in Python.
|
||||
org.xmlpull.v1 package - XmlPullParser, XmlSerializer, XmlPullParserFactory.
|
||||
Wraps Python xml.etree.ElementTree.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from .._core import Stub, AndroidOnlyError
|
||||
import xml.etree.ElementTree as _ET
|
||||
from io import StringIO as _StringIO
|
||||
from typing import List, Optional
|
||||
|
||||
__all__ = [
|
||||
"XmlPullParser", "XmlSerializer", "XmlPullParserFactory", "Factory",
|
||||
]
|
||||
|
||||
|
||||
# ============================================================
|
||||
# XmlPullParser
|
||||
# ============================================================
|
||||
|
||||
class XmlPullParser(Stub):
|
||||
"""
|
||||
org.xmlpull.v1.XmlPullParser
|
||||
An XML pull parser interface.
|
||||
"""
|
||||
# Event types
|
||||
START_TAG: int = 2
|
||||
END_TAG: int = 3
|
||||
TEXT: int = 4
|
||||
CDSECT: int = 5
|
||||
ENTITY_REF: int = 6
|
||||
IGNORABLE_WHITESPACE: int = 7
|
||||
PROCESSING_INSTRUCTION: int = 8
|
||||
COMMENT: int = 9
|
||||
DOCDECL: int = 10
|
||||
START_DOCUMENT: int = 0
|
||||
END_DOCUMENT: int = 1
|
||||
TYPES: List[str] = [
|
||||
"START_DOCUMENT", "END_DOCUMENT", "START_TAG", "END_TAG",
|
||||
"TEXT", "CDSECT", "ENTITY_REF", "IGNORABLE_WHITESPACE",
|
||||
"PROCESSING_INSTRUCTION", "COMMENT", "DOCDECL",
|
||||
]
|
||||
NO_TYPES: List[str] = []
|
||||
# Features
|
||||
FEATURE_PROCESS_NAMESPACES: str = "http://xmlpull.org/v1/doc/features.html#process-ns"
|
||||
FEATURE_REPORT_NAMESPACE_ATTRIBUTES: str = "http://xmlpull.org/v1/doc/features.html#report-ns-attributes"
|
||||
FEATURE_PROCESS_DOCDECL: str = "http://xmlpull.org/v1/doc/features.html#process-docdecl"
|
||||
FEATURE_VALIDATION: str = "http://xmlpull.org/v1/doc/features.html#validation"
|
||||
|
||||
class _Event:
|
||||
def __init__(self, type_=0, name="", text="", namespace="", prefix="",
|
||||
attributes=None, depth=0, line=0, column=0):
|
||||
self.type = type_
|
||||
self.name = name
|
||||
self.text = text
|
||||
self.namespace = namespace
|
||||
self.prefix = prefix
|
||||
self.attributes = attributes or []
|
||||
self.depth = depth
|
||||
self.line = line
|
||||
self.column = column
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._events = []
|
||||
self._pos = -1
|
||||
self._depth = 0
|
||||
self._features = {
|
||||
self.FEATURE_PROCESS_NAMESPACES: True,
|
||||
self.FEATURE_REPORT_NAMESPACE_ATTRIBUTES: False,
|
||||
self.FEATURE_PROCESS_DOCDECL: False,
|
||||
self.FEATURE_VALIDATION: False,
|
||||
}
|
||||
self._properties = {}
|
||||
self._input_encoding = "UTF-8"
|
||||
self._namespace_stack = []
|
||||
|
||||
def setInput(self, source: Any, input_encoding: str = None):
|
||||
"""Set the input source for parsing."""
|
||||
if input_encoding:
|
||||
self._input_encoding = input_encoding
|
||||
|
||||
if isinstance(source, str):
|
||||
# Parse directly from XML string
|
||||
self._parse_string(source)
|
||||
elif hasattr(source, 'read'):
|
||||
# File-like object
|
||||
data = source.read()
|
||||
if isinstance(data, bytes):
|
||||
data = data.decode(input_encoding or "UTF-8")
|
||||
self._parse_string(data)
|
||||
else:
|
||||
self._parse_string(str(source))
|
||||
|
||||
def _parse_string(self, xml_str: str):
|
||||
"""Parse XML string into a list of events."""
|
||||
self._events = []
|
||||
self._pos = -1
|
||||
|
||||
try:
|
||||
root = _ET.fromstring(xml_str)
|
||||
except _ET.ParseError as e:
|
||||
# Create minimal events if parsing fails
|
||||
self._events.append(XmlPullParser._Event(XmlPullParser.START_DOCUMENT))
|
||||
self._events.append(XmlPullParser._Event(XmlPullParser.END_DOCUMENT))
|
||||
return
|
||||
|
||||
self._events.append(XmlPullParser._Event(XmlPullParser.START_DOCUMENT))
|
||||
self._build_events(root, 0)
|
||||
self._events.append(XmlPullParser._Event(XmlPullParser.END_DOCUMENT))
|
||||
|
||||
def _build_events(self, element: _ET.Element, depth: int):
|
||||
"""Recursively build events from ElementTree."""
|
||||
attrs = []
|
||||
for k, v in element.attrib.items():
|
||||
ns = ""
|
||||
name = k
|
||||
prefix = ""
|
||||
if "}" in k:
|
||||
ns = k[1:k.index("}")]
|
||||
name = k[k.index("}") + 1:]
|
||||
attrs.append({"namespace": ns, "name": name, "prefix": prefix, "value": v})
|
||||
|
||||
# START_TAG
|
||||
tag = element.tag
|
||||
ns = ""
|
||||
prefix = ""
|
||||
if "}" in tag:
|
||||
ns = tag[1:tag.index("}")]
|
||||
tag = tag[tag.index("}") + 1:]
|
||||
|
||||
self._events.append(XmlPullParser._Event(
|
||||
XmlPullParser.START_TAG, tag, "", ns, prefix, attrs, depth))
|
||||
|
||||
# Text content
|
||||
if element.text and element.text.strip():
|
||||
self._events.append(XmlPullParser._Event(
|
||||
XmlPullParser.TEXT, "", element.text, "", "", [], depth + 1))
|
||||
|
||||
# Child elements
|
||||
for child in element:
|
||||
self._build_events(child, depth + 1)
|
||||
|
||||
# END_TAG
|
||||
self._events.append(XmlPullParser._Event(
|
||||
XmlPullParser.END_TAG, tag, "", ns, prefix, [], depth))
|
||||
|
||||
# Tail text
|
||||
if element.tail and element.tail.strip():
|
||||
self._events.append(XmlPullParser._Event(
|
||||
XmlPullParser.TEXT, "", element.tail, "", "", [], depth))
|
||||
|
||||
# --- Event navigation ---
|
||||
|
||||
def getEventType(self) -> int:
|
||||
if 0 <= self._pos < len(self._events):
|
||||
return self._events[self._pos].type
|
||||
return self.END_DOCUMENT
|
||||
|
||||
def next(self) -> int:
|
||||
"""Move to next event."""
|
||||
if self._pos < len(self._events) - 1:
|
||||
self._pos += 1
|
||||
return self.getEventType()
|
||||
|
||||
def nextToken(self) -> int:
|
||||
"""Move to next token (same as next for this impl)."""
|
||||
return self.next()
|
||||
|
||||
def nextText(self) -> str:
|
||||
"""Returns the text content of the current element."""
|
||||
if self.getEventType() != self.START_TAG:
|
||||
return ""
|
||||
self.next()
|
||||
text = self.getText()
|
||||
self.next() # Move to END_TAG
|
||||
return text or ""
|
||||
|
||||
def nextTag(self) -> int:
|
||||
"""Move to next tag event."""
|
||||
self.next()
|
||||
while self.getEventType() not in (self.START_TAG, self.END_TAG, self.END_DOCUMENT):
|
||||
self.next()
|
||||
return self.getEventType()
|
||||
|
||||
def require(self, type_: int, namespace: str, name: str):
|
||||
"""Check that the current event matches expectations."""
|
||||
if self.getEventType() != type_:
|
||||
raise AndroidOnlyError(f"Expected event {type_}, got {self.getEventType()}")
|
||||
if namespace is not None and self.getNamespace() != namespace:
|
||||
raise AndroidOnlyError(f"Expected namespace '{namespace}', got '{self.getNamespace()}'")
|
||||
if name is not None and self.getName() != name:
|
||||
raise AndroidOnlyError(f"Expected name '{name}', got '{self.getName()}'")
|
||||
|
||||
# --- Position info ---
|
||||
|
||||
def getDepth(self) -> int:
|
||||
if 0 <= self._pos < len(self._events):
|
||||
return self._events[self._pos].depth
|
||||
return 0
|
||||
|
||||
def getLineNumber(self) -> int:
|
||||
if 0 <= self._pos < len(self._events):
|
||||
return self._events[self._pos].line
|
||||
return -1
|
||||
|
||||
def getColumnNumber(self) -> int:
|
||||
if 0 <= self._pos < len(self._events):
|
||||
return self._events[self._pos].column
|
||||
return -1
|
||||
|
||||
def getInputEncoding(self) -> str:
|
||||
return self._input_encoding
|
||||
|
||||
# --- Current event data ---
|
||||
|
||||
def getName(self) -> str:
|
||||
if 0 <= self._pos < len(self._events):
|
||||
return self._events[self._pos].name
|
||||
return ""
|
||||
|
||||
def getNamespace(self) -> str:
|
||||
if 0 <= self._pos < len(self._events):
|
||||
return self._events[self._pos].namespace
|
||||
return ""
|
||||
|
||||
def getPrefix(self) -> str:
|
||||
if 0 <= self._pos < len(self._events):
|
||||
return self._events[self._pos].prefix
|
||||
return ""
|
||||
|
||||
def getText(self) -> Optional[str]:
|
||||
if 0 <= self._pos < len(self._events):
|
||||
return self._events[self._pos].text
|
||||
return None
|
||||
|
||||
def getTextCharacters(self, holder_for_start: List[int]) -> List[str]:
|
||||
"""Returns text characters and fills start/length in holder."""
|
||||
text = self.getText() or ""
|
||||
if len(holder_for_start) >= 2:
|
||||
holder_for_start[0] = 0
|
||||
holder_for_start[1] = len(text)
|
||||
return list(text)
|
||||
|
||||
# --- Attributes ---
|
||||
|
||||
def getAttributeCount(self) -> int:
|
||||
if 0 <= self._pos < len(self._events):
|
||||
return len(self._events[self._pos].attributes)
|
||||
return 0
|
||||
|
||||
def getAttributeName(self, index: int) -> str:
|
||||
if 0 <= self._pos < len(self._events):
|
||||
attrs = self._events[self._pos].attributes
|
||||
if 0 <= index < len(attrs):
|
||||
return attrs[index]["name"]
|
||||
return ""
|
||||
|
||||
def getAttributeNamespace(self, index: int) -> str:
|
||||
if 0 <= self._pos < len(self._events):
|
||||
attrs = self._events[self._pos].attributes
|
||||
if 0 <= index < len(attrs):
|
||||
return attrs[index]["namespace"]
|
||||
return ""
|
||||
|
||||
def getAttributePrefix(self, index: int) -> str:
|
||||
if 0 <= self._pos < len(self._events):
|
||||
attrs = self._events[self._pos].attributes
|
||||
if 0 <= index < len(attrs):
|
||||
return attrs[index]["prefix"]
|
||||
return ""
|
||||
|
||||
def getAttributeType(self, index: int) -> str:
|
||||
return "CDATA"
|
||||
|
||||
def getAttributeValue(self, index_or_name: Any, namespace: str = None) -> str:
|
||||
if isinstance(index_or_name, int):
|
||||
if 0 <= self._pos < len(self._events):
|
||||
attrs = self._events[self._pos].attributes
|
||||
if 0 <= index_or_name < len(attrs):
|
||||
return attrs[index_or_name]["value"]
|
||||
else:
|
||||
# Lookup by name
|
||||
if 0 <= self._pos < len(self._events):
|
||||
attrs = self._events[self._pos].attributes
|
||||
for attr in attrs:
|
||||
if attr["name"] == index_or_name:
|
||||
if namespace is None or attr["namespace"] == namespace:
|
||||
return attr["value"]
|
||||
return ""
|
||||
|
||||
def isAttributeDefault(self, index: int) -> bool:
|
||||
return False
|
||||
|
||||
# --- Element state ---
|
||||
|
||||
def isEmptyElementTag(self) -> bool:
|
||||
"""Returns True if the current event is an empty element tag."""
|
||||
if self.getEventType() == self.START_TAG:
|
||||
if self._pos + 1 < len(self._events):
|
||||
next_event = self._events[self._pos + 1]
|
||||
return next_event.type == self.END_TAG and next_event.name == self.getName()
|
||||
return False
|
||||
|
||||
def isWhitespace(self) -> bool:
|
||||
text = self.getText() or ""
|
||||
return text.strip() == ""
|
||||
|
||||
# --- Namespace support ---
|
||||
|
||||
def getNamespaceCount(self, depth: int) -> int:
|
||||
return len(self._namespace_stack)
|
||||
|
||||
def getNamespacePrefix(self, index: int) -> str:
|
||||
if 0 <= index < len(self._namespace_stack):
|
||||
return self._namespace_stack[index][0]
|
||||
return ""
|
||||
|
||||
def getNamespaceUri(self, prefix: str) -> str:
|
||||
for p, uri in self._namespace_stack:
|
||||
if p == prefix:
|
||||
return uri
|
||||
return ""
|
||||
|
||||
# --- Features / Properties ---
|
||||
|
||||
def getFeature(self, name: str) -> bool:
|
||||
return self._features.get(name, False)
|
||||
|
||||
def setFeature(self, name: str, value: bool):
|
||||
if name in self._features:
|
||||
self._features[name] = value
|
||||
else:
|
||||
raise AndroidOnlyError(f"Unknown feature: {name}")
|
||||
|
||||
def getProperty(self, name: str):
|
||||
return self._properties.get(name)
|
||||
|
||||
def setProperty(self, name: str, value: Any):
|
||||
self._properties[name] = value
|
||||
|
||||
def toString(self) -> str:
|
||||
return f"XmlPullParser@{hex(id(self))}[event={self.getEventType()}]"
|
||||
|
||||
def equals(self, other) -> bool:
|
||||
return self is other
|
||||
|
||||
def hashCode(self) -> int:
|
||||
return hash(self) & 0x7FFFFFFF
|
||||
|
||||
|
||||
# ============================================================
|
||||
# XmlSerializer
|
||||
# ============================================================
|
||||
|
||||
class XmlSerializer(Stub):
|
||||
"""
|
||||
org.xmlpull.v1.XmlSerializer
|
||||
Interface for serializing XML documents.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._output = []
|
||||
self._depth = 0
|
||||
self._features = {}
|
||||
self._properties = {}
|
||||
self._prefixes = {}
|
||||
self._output_stream = None
|
||||
self._encoding = "UTF-8"
|
||||
|
||||
def setOutput(self, output_stream, encoding: str = None):
|
||||
"""Sets the output writer/stream."""
|
||||
self._output_stream = output_stream
|
||||
self._encoding = encoding or "UTF-8"
|
||||
|
||||
def getFeature(self, name: str) -> bool:
|
||||
return self._features.get(name, False)
|
||||
|
||||
def setFeature(self, name: str, value: bool):
|
||||
self._features[name] = value
|
||||
|
||||
def getProperty(self, name: str):
|
||||
return self._properties.get(name)
|
||||
|
||||
def setProperty(self, name: str, value: Any):
|
||||
self._properties[name] = value
|
||||
|
||||
def setPrefix(self, prefix: str, namespace_uri: str):
|
||||
"""Sets the prefix for a namespace."""
|
||||
self._prefixes[namespace_uri] = prefix
|
||||
if prefix:
|
||||
self._write(f' xmlns:{prefix}="{namespace_uri}"')
|
||||
else:
|
||||
self._write(f' xmlns="{namespace_uri}"')
|
||||
|
||||
def startTag(self, namespace: str, name: str) -> "XmlSerializer":
|
||||
"""Writes a start tag."""
|
||||
self._write(f"<{name}")
|
||||
self._depth += 1
|
||||
return self
|
||||
|
||||
def attribute(self, namespace: str, name: str, value: str) -> "XmlSerializer":
|
||||
"""Writes an attribute."""
|
||||
if value is not None:
|
||||
escaped = value.replace("&", "&").replace("<", "<").replace(">", ">").replace('"', """)
|
||||
self._write(f' {name}="{escaped}"')
|
||||
return self
|
||||
|
||||
def endTag(self, namespace: str, name: str) -> "XmlSerializer":
|
||||
"""Writes an end tag."""
|
||||
self._depth -= 1
|
||||
self._write(f"</{name}>")
|
||||
return self
|
||||
|
||||
def text(self, text_or_buf: Any, start: int = None, length: int = None) -> "XmlSerializer":
|
||||
"""Writes text content."""
|
||||
if isinstance(text_or_buf, str):
|
||||
escaped = text_or_buf.replace("&", "&").replace("<", "<").replace(">", ">")
|
||||
self._write(escaped)
|
||||
elif isinstance(text_or_buf, (list, tuple)) and start is not None and length is not None:
|
||||
chars = text_or_buf[start:start + length]
|
||||
self._write("".join(chars))
|
||||
return self
|
||||
|
||||
def cdsect(self, text: str) -> "XmlSerializer":
|
||||
"""Writes a CDATA section."""
|
||||
self._write(f"<![CDATA[{text}]]>")
|
||||
return self
|
||||
|
||||
def entityRef(self, name: str) -> "XmlSerializer":
|
||||
"""Writes an entity reference."""
|
||||
self._write(f"&{name};")
|
||||
return self
|
||||
|
||||
def processingInstruction(self, text: str) -> "XmlSerializer":
|
||||
"""Writes a processing instruction."""
|
||||
self._write(f"<?{text}?>")
|
||||
return self
|
||||
|
||||
def comment(self, text: str) -> "XmlSerializer":
|
||||
"""Writes a comment."""
|
||||
self._write(f"<!--{text}-->")
|
||||
return self
|
||||
|
||||
def docdecl(self, text: str) -> "XmlSerializer":
|
||||
"""Writes a document declaration."""
|
||||
self._write(f"<!{text}>")
|
||||
return self
|
||||
|
||||
def startDocument(self, encoding: str = None, standalone: bool = None):
|
||||
"""Writes the XML declaration."""
|
||||
encoding = encoding or self._encoding
|
||||
decl = f'<?xml version="1.0" encoding="{encoding}"'
|
||||
if standalone is not None:
|
||||
decl += f' standalone="{"yes" if standalone else "no"}"'
|
||||
decl += "?>"
|
||||
self._write(decl)
|
||||
|
||||
def endDocument(self):
|
||||
"""Finishes the document."""
|
||||
self.flush()
|
||||
|
||||
def flush(self):
|
||||
"""Flushes the output."""
|
||||
content = "".join(self._output)
|
||||
if self._output_stream:
|
||||
if hasattr(self._output_stream, 'write'):
|
||||
self._output_stream.write(content)
|
||||
self._output = []
|
||||
|
||||
def getDepth(self) -> int:
|
||||
return self._depth
|
||||
|
||||
def getName(self) -> str:
|
||||
return ""
|
||||
|
||||
def getNamespace(self) -> str:
|
||||
return ""
|
||||
|
||||
def getPrefix(self, namespace: str, prefix: bool = False) -> str:
|
||||
return self._prefixes.get(namespace, "")
|
||||
|
||||
def _write(self, s: str):
|
||||
self._output.append(s)
|
||||
|
||||
def verbatim(self, text: str) -> "XmlSerializer":
|
||||
"""Writes raw text without escaping."""
|
||||
self._write(text)
|
||||
return self
|
||||
|
||||
def write(self, text: str) -> "XmlSerializer":
|
||||
"""Writes text."""
|
||||
return self.text(text)
|
||||
|
||||
def toString(self) -> str:
|
||||
return f"XmlSerializer@{hex(id(self))}"
|
||||
|
||||
def equals(self, other) -> bool:
|
||||
return self is other
|
||||
|
||||
def hashCode(self) -> int:
|
||||
return hash(self) & 0x7FFFFFFF
|
||||
|
||||
|
||||
# ============================================================
|
||||
# XmlPullParserFactory
|
||||
# ============================================================
|
||||
|
||||
class XmlPullParserFactory(Stub):
|
||||
"""
|
||||
org.xmlpull.v1.XmlPullParserFactory
|
||||
Factory for creating XmlPullParser and XmlSerializer instances.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._features = {}
|
||||
self._properties = {}
|
||||
|
||||
@staticmethod
|
||||
def newInstance(unused: Any = None, unused_cls: Any = None) -> "XmlPullParserFactory":
|
||||
return XmlPullParserFactory()
|
||||
|
||||
def setFeature(self, name: str, value: bool):
|
||||
self._features[name] = value
|
||||
|
||||
def getFeature(self, name: str) -> bool:
|
||||
return self._features.get(name, False)
|
||||
|
||||
def setProperty(self, name: str, value: Any):
|
||||
self._properties[name] = value
|
||||
|
||||
def getProperty(self, name: str):
|
||||
return self._properties.get(name)
|
||||
|
||||
def newPullParser(self) -> XmlPullParser:
|
||||
"""Creates a new XmlPullParser."""
|
||||
return XmlPullParser()
|
||||
|
||||
def newSerializer(self) -> XmlSerializer:
|
||||
"""Creates a new XmlSerializer."""
|
||||
return XmlSerializer()
|
||||
|
||||
def isNamespaceAware(self) -> bool:
|
||||
return self.getFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES)
|
||||
|
||||
def isValidating(self) -> bool:
|
||||
return self.getFeature(XmlPullParser.FEATURE_VALIDATION)
|
||||
|
||||
def toString(self) -> str:
|
||||
return f"XmlPullParserFactory@{hex(id(self))}"
|
||||
|
||||
def equals(self, other) -> bool:
|
||||
return self is other
|
||||
|
||||
def hashCode(self) -> int:
|
||||
return hash(self) & 0x7FFFFFFF
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Factory (alias)
|
||||
# ============================================================
|
||||
|
||||
class Factory(XmlPullParserFactory):
|
||||
"""
|
||||
Factory alias for XmlPullParserFactory.
|
||||
"""
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
@staticmethod
|
||||
def newInstance(unused: Any = None, unused_cls: Any = None) -> "Factory":
|
||||
return Factory()
|
||||
|
||||
@staticmethod
|
||||
def getInstance() -> "Factory":
|
||||
return Factory()
|
||||
|
||||
def toString(self) -> str:
|
||||
return f"Factory@{hex(id(self))}"
|
||||
|
||||
def equals(self, other) -> bool:
|
||||
return isinstance(other, Factory)
|
||||
|
||||
def hashCode(self) -> int:
|
||||
return hash("Factory") & 0x7FFFFFFF
|
||||
@@ -0,0 +1,890 @@
|
||||
"""
|
||||
Java org.xml.sax APIs implemented in Python.
|
||||
org.xml.sax package - XMLReader, ContentHandler, SAXException, etc.
|
||||
Wraps Python xml.sax module.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from .._core import Stub, AndroidOnlyError
|
||||
import xml.sax as _sax
|
||||
import xml.sax.handler as _handler
|
||||
import xml.sax.xmlreader as _reader
|
||||
from typing import List, Optional
|
||||
|
||||
__all__ = [
|
||||
"XMLReader", "ContentHandler", "DTDHandler", "EntityResolver",
|
||||
"ErrorHandler", "InputSource", "SAXException", "SAXParseException",
|
||||
"SAXNotRecognizedException", "SAXNotSupportedException",
|
||||
"Locator", "Attributes", "AttributeList", "HandlerBase",
|
||||
"DocumentHandler", "XMLFilter", "XMLFilterImpl", "DefaultHandler",
|
||||
"Helpers",
|
||||
]
|
||||
|
||||
|
||||
# ============================================================
|
||||
# SAXException
|
||||
# ============================================================
|
||||
|
||||
class SAXException(Exception, Stub):
|
||||
"""
|
||||
org.xml.sax.SAXException
|
||||
Encapsulate a general SAX error or warning.
|
||||
"""
|
||||
def __init__(self, message: str = "", exception: Exception = None):
|
||||
super().__init__(message)
|
||||
self._message = message
|
||||
self._exception = exception
|
||||
|
||||
def getMessage(self) -> str:
|
||||
return self._message
|
||||
|
||||
def getException(self) -> Optional[Exception]:
|
||||
return self._exception
|
||||
|
||||
def toString(self) -> str:
|
||||
return f"SAXException: {self._message}"
|
||||
|
||||
def equals(self, other) -> bool:
|
||||
if isinstance(other, SAXException):
|
||||
return self._message == other._message
|
||||
return False
|
||||
|
||||
def hashCode(self) -> int:
|
||||
return hash(self._message) & 0x7FFFFFFF
|
||||
|
||||
|
||||
class SAXParseException(SAXException):
|
||||
"""
|
||||
org.xml.sax.SAXParseException
|
||||
Encapsulate an XML parse error or warning.
|
||||
"""
|
||||
def __init__(self, message: str = "", public_id: str = "", system_id: str = "",
|
||||
line: int = -1, column: int = -1, exception: Exception = None):
|
||||
super().__init__(message, exception)
|
||||
self._public_id = public_id
|
||||
self._system_id = system_id
|
||||
self._line = line
|
||||
self._column = column
|
||||
|
||||
def getPublicId(self) -> str:
|
||||
return self._public_id
|
||||
|
||||
def getSystemId(self) -> str:
|
||||
return self._system_id
|
||||
|
||||
def getLineNumber(self) -> int:
|
||||
return self._line
|
||||
|
||||
def getColumnNumber(self) -> int:
|
||||
return self._column
|
||||
|
||||
def toString(self) -> str:
|
||||
return f"SAXParseException[line={self._line}, col={self._column}]: {self._message}"
|
||||
|
||||
def equals(self, other) -> bool:
|
||||
if isinstance(other, SAXParseException):
|
||||
return (self._line == other._line and
|
||||
self._column == other._column and
|
||||
self._message == other._message)
|
||||
return False
|
||||
|
||||
def hashCode(self) -> int:
|
||||
return hash((self._line, self._column, self._message)) & 0x7FFFFFFF
|
||||
|
||||
|
||||
class SAXNotRecognizedException(SAXException):
|
||||
"""
|
||||
org.xml.sax.SAXNotRecognizedException
|
||||
Exception for unrecognized feature or property.
|
||||
"""
|
||||
def __init__(self, message: str = ""):
|
||||
super().__init__(message or "Feature or property not recognized")
|
||||
|
||||
def toString(self) -> str:
|
||||
return f"SAXNotRecognizedException: {self._message}"
|
||||
|
||||
def equals(self, other) -> bool:
|
||||
return isinstance(other, SAXNotRecognizedException)
|
||||
|
||||
def hashCode(self) -> int:
|
||||
return hash("SAXNotRecognizedException") & 0x7FFFFFFF
|
||||
|
||||
|
||||
class SAXNotSupportedException(SAXException):
|
||||
"""
|
||||
org.xml.sax.SAXNotSupportedException
|
||||
Exception for unsupported feature or property.
|
||||
"""
|
||||
def __init__(self, message: str = ""):
|
||||
super().__init__(message or "Feature or property not supported")
|
||||
|
||||
def toString(self) -> str:
|
||||
return f"SAXNotSupportedException: {self._message}"
|
||||
|
||||
def equals(self, other) -> bool:
|
||||
return isinstance(other, SAXNotSupportedException)
|
||||
|
||||
def hashCode(self) -> int:
|
||||
return hash("SAXNotSupportedException") & 0x7FFFFFFF
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Locator
|
||||
# ============================================================
|
||||
|
||||
class Locator(Stub):
|
||||
"""
|
||||
org.xml.sax.Locator
|
||||
Interface for associating a SAX event with a document location.
|
||||
"""
|
||||
def __init__(self, public_id: str = "", system_id: str = "",
|
||||
line: int = -1, column: int = -1):
|
||||
super().__init__()
|
||||
self._public_id = public_id
|
||||
self._system_id = system_id
|
||||
self._line = line
|
||||
self._column = column
|
||||
|
||||
def getPublicId(self) -> str:
|
||||
return self._public_id
|
||||
|
||||
def getSystemId(self) -> str:
|
||||
return self._system_id
|
||||
|
||||
def getLineNumber(self) -> int:
|
||||
return self._line
|
||||
|
||||
def getColumnNumber(self) -> int:
|
||||
return self._column
|
||||
|
||||
def toString(self) -> str:
|
||||
return f"Locator[line={self._line}, col={self._column}]"
|
||||
|
||||
def equals(self, other) -> bool:
|
||||
return self is other
|
||||
|
||||
def hashCode(self) -> int:
|
||||
return hash(self) & 0x7FFFFFFF
|
||||
|
||||
|
||||
# ============================================================
|
||||
# InputSource
|
||||
# ============================================================
|
||||
|
||||
class InputSource(Stub):
|
||||
"""
|
||||
org.xml.sax.InputSource
|
||||
A single input source for a SAX parser.
|
||||
"""
|
||||
def __init__(self, system_id: str = None, byte_stream=None,
|
||||
character_stream=None, encoding: str = None):
|
||||
super().__init__()
|
||||
self._public_id = None
|
||||
self._system_id = system_id
|
||||
self._byte_stream = byte_stream
|
||||
self._character_stream = character_stream
|
||||
self._encoding = encoding
|
||||
|
||||
def getPublicId(self) -> Optional[str]:
|
||||
return self._public_id
|
||||
|
||||
def setPublicId(self, public_id: str):
|
||||
self._public_id = public_id
|
||||
|
||||
def getSystemId(self) -> Optional[str]:
|
||||
return self._system_id
|
||||
|
||||
def setSystemId(self, system_id: str):
|
||||
self._system_id = system_id
|
||||
|
||||
def getByteStream(self):
|
||||
return self._byte_stream
|
||||
|
||||
def setByteStream(self, byte_stream):
|
||||
self._byte_stream = byte_stream
|
||||
|
||||
def getEncoding(self) -> Optional[str]:
|
||||
return self._encoding
|
||||
|
||||
def setEncoding(self, encoding: str):
|
||||
self._encoding = encoding
|
||||
|
||||
def getCharacterStream(self):
|
||||
return self._character_stream
|
||||
|
||||
def setCharacterStream(self, character_stream):
|
||||
self._character_stream = character_stream
|
||||
|
||||
def toString(self) -> str:
|
||||
return f"InputSource[systemId={self._system_id}]"
|
||||
|
||||
def equals(self, other) -> bool:
|
||||
return self is other
|
||||
|
||||
def hashCode(self) -> int:
|
||||
return hash(self) & 0x7FFFFFFF
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Attributes
|
||||
# ============================================================
|
||||
|
||||
class Attributes(Stub):
|
||||
"""
|
||||
org.xml.sax.Attributes
|
||||
Interface for a list of XML attributes.
|
||||
"""
|
||||
def __init__(self, attrs: List[dict] = None):
|
||||
super().__init__()
|
||||
self._attrs = attrs or []
|
||||
|
||||
def getLength(self) -> int:
|
||||
return len(self._attrs)
|
||||
|
||||
def getURI(self, index: int) -> str:
|
||||
if 0 <= index < len(self._attrs):
|
||||
return self._attrs[index].get("uri", "")
|
||||
return ""
|
||||
|
||||
def getLocalName(self, index: int) -> str:
|
||||
if 0 <= index < len(self._attrs):
|
||||
return self._attrs[index].get("localName", "")
|
||||
return ""
|
||||
|
||||
def getQName(self, index: int) -> str:
|
||||
if 0 <= index < len(self._attrs):
|
||||
return self._attrs[index].get("qname", "")
|
||||
return ""
|
||||
|
||||
def getType(self, index_or_name: Any) -> str:
|
||||
if isinstance(index_or_name, int):
|
||||
if 0 <= index_or_name < len(self._attrs):
|
||||
return self._attrs[index_or_name].get("type", "CDATA")
|
||||
return ""
|
||||
for attr in self._attrs:
|
||||
if attr.get("qname") == index_or_name:
|
||||
return attr.get("type", "CDATA")
|
||||
return ""
|
||||
|
||||
def getValue(self, index_or_name: Any) -> str:
|
||||
if isinstance(index_or_name, int):
|
||||
if 0 <= index_or_name < len(self._attrs):
|
||||
return self._attrs[index_or_name].get("value", "")
|
||||
return ""
|
||||
for attr in self._attrs:
|
||||
if attr.get("qname") == index_or_name:
|
||||
return attr.get("value", "")
|
||||
return ""
|
||||
|
||||
def getIndex(self, qname_or_uri: str, local_name: str = None) -> int:
|
||||
if local_name is None:
|
||||
for i, attr in enumerate(self._attrs):
|
||||
if attr.get("qname") == qname_or_uri:
|
||||
return i
|
||||
else:
|
||||
for i, attr in enumerate(self._attrs):
|
||||
if attr.get("uri") == qname_or_uri and attr.get("localName") == local_name:
|
||||
return i
|
||||
return -1
|
||||
|
||||
def getIndexByQName(self, qname: str) -> int:
|
||||
return self.getIndex(qname)
|
||||
|
||||
def getIndexByURI(self, uri: str, local_name: str) -> int:
|
||||
return self.getIndex(uri, local_name)
|
||||
|
||||
def toString(self) -> str:
|
||||
return f"Attributes@{hex(id(self))}[length={len(self._attrs)}]"
|
||||
|
||||
def equals(self, other) -> bool:
|
||||
return self is other
|
||||
|
||||
def hashCode(self) -> int:
|
||||
return hash(self) & 0x7FFFFFFF
|
||||
|
||||
|
||||
# ============================================================
|
||||
# AttributeList (deprecated)
|
||||
# ============================================================
|
||||
|
||||
class AttributeList(Stub):
|
||||
"""
|
||||
org.xml.sax.AttributeList
|
||||
Deprecated SAX1 interface for attribute list.
|
||||
"""
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._attrs = []
|
||||
|
||||
def getLength(self) -> int:
|
||||
return len(self._attrs)
|
||||
|
||||
def getName(self, index: int) -> str:
|
||||
if 0 <= index < len(self._attrs):
|
||||
return self._attrs[index].get("name", "")
|
||||
return ""
|
||||
|
||||
def getType(self, index_or_name: Any) -> str:
|
||||
if isinstance(index_or_name, int):
|
||||
if 0 <= index_or_name < len(self._attrs):
|
||||
return self._attrs[index_or_name].get("type", "CDATA")
|
||||
return ""
|
||||
for attr in self._attrs:
|
||||
if attr.get("name") == index_or_name:
|
||||
return attr.get("type", "CDATA")
|
||||
return ""
|
||||
|
||||
def getValue(self, index_or_name: Any) -> str:
|
||||
if isinstance(index_or_name, int):
|
||||
if 0 <= index_or_name < len(self._attrs):
|
||||
return self._attrs[index_or_name].get("value", "")
|
||||
return ""
|
||||
for attr in self._attrs:
|
||||
if attr.get("name") == index_or_name:
|
||||
return attr.get("value", "")
|
||||
return ""
|
||||
|
||||
def toString(self) -> str:
|
||||
return f"AttributeList@{hex(id(self))}"
|
||||
|
||||
def equals(self, other) -> bool:
|
||||
return self is other
|
||||
|
||||
def hashCode(self) -> int:
|
||||
return hash(self) & 0x7FFFFFFF
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ContentHandler
|
||||
# ============================================================
|
||||
|
||||
class ContentHandler(Stub):
|
||||
"""
|
||||
org.xml.sax.ContentHandler
|
||||
Interface for receiving SAX content events.
|
||||
"""
|
||||
def setDocumentLocator(self, locator: Locator):
|
||||
pass
|
||||
|
||||
def startDocument(self):
|
||||
pass
|
||||
|
||||
def endDocument(self):
|
||||
pass
|
||||
|
||||
def startPrefixMapping(self, prefix: str, uri: str):
|
||||
pass
|
||||
|
||||
def endPrefixMapping(self, prefix: str):
|
||||
pass
|
||||
|
||||
def startElement(self, namespace_uri: str, local_name: str, qname: str, atts: Attributes):
|
||||
pass
|
||||
|
||||
def endElement(self, namespace_uri: str, local_name: str, qname: str):
|
||||
pass
|
||||
|
||||
def characters(self, ch: str, start: int, length: int):
|
||||
pass
|
||||
|
||||
def ignorableWhitespace(self, ch: str, start: int, length: int):
|
||||
pass
|
||||
|
||||
def processingInstruction(self, target: str, data: str):
|
||||
pass
|
||||
|
||||
def skippedEntity(self, name: str):
|
||||
pass
|
||||
|
||||
def toString(self) -> str:
|
||||
return f"ContentHandler@{hex(id(self))}"
|
||||
|
||||
def equals(self, other) -> bool:
|
||||
return self is other
|
||||
|
||||
def hashCode(self) -> int:
|
||||
return hash(self) & 0x7FFFFFFF
|
||||
|
||||
|
||||
# ============================================================
|
||||
# DTDHandler
|
||||
# ============================================================
|
||||
|
||||
class DTDHandler(Stub):
|
||||
"""
|
||||
org.xml.sax.DTDHandler
|
||||
Interface for receiving DTD events.
|
||||
"""
|
||||
def notationDecl(self, name: str, public_id: str, system_id: str):
|
||||
pass
|
||||
|
||||
def unparsedEntityDecl(self, name: str, public_id: str, system_id: str,
|
||||
notation_name: str):
|
||||
pass
|
||||
|
||||
def toString(self) -> str:
|
||||
return f"DTDHandler@{hex(id(self))}"
|
||||
|
||||
def equals(self, other) -> bool:
|
||||
return self is other
|
||||
|
||||
def hashCode(self) -> int:
|
||||
return hash(self) & 0x7FFFFFFF
|
||||
|
||||
|
||||
# ============================================================
|
||||
# EntityResolver
|
||||
# ============================================================
|
||||
|
||||
class EntityResolver(Stub):
|
||||
"""
|
||||
org.xml.sax.EntityResolver
|
||||
Interface for resolving entities.
|
||||
"""
|
||||
def resolveEntity(self, public_id: str, system_id: str) -> InputSource:
|
||||
return InputSource(system_id)
|
||||
|
||||
def toString(self) -> str:
|
||||
return f"EntityResolver@{hex(id(self))}"
|
||||
|
||||
def equals(self, other) -> bool:
|
||||
return self is other
|
||||
|
||||
def hashCode(self) -> int:
|
||||
return hash(self) & 0x7FFFFFFF
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ErrorHandler
|
||||
# ============================================================
|
||||
|
||||
class ErrorHandler(Stub):
|
||||
"""
|
||||
org.xml.sax.ErrorHandler
|
||||
Interface for receiving SAX error events.
|
||||
"""
|
||||
def warning(self, exception: SAXParseException):
|
||||
pass
|
||||
|
||||
def error(self, exception: SAXParseException):
|
||||
pass
|
||||
|
||||
def fatalError(self, exception: SAXParseException):
|
||||
raise exception
|
||||
|
||||
def toString(self) -> str:
|
||||
return f"ErrorHandler@{hex(id(self))}"
|
||||
|
||||
def equals(self, other) -> bool:
|
||||
return self is other
|
||||
|
||||
def hashCode(self) -> int:
|
||||
return hash(self) & 0x7FFFFFFF
|
||||
|
||||
|
||||
# ============================================================
|
||||
# HandlerBase (deprecated SAX1)
|
||||
# ============================================================
|
||||
|
||||
class HandlerBase(Stub):
|
||||
"""
|
||||
org.xml.sax.HandlerBase
|
||||
Deprecated SAX1 base class for handlers.
|
||||
"""
|
||||
def setDocumentLocator(self, locator: Locator): pass
|
||||
def startDocument(self): pass
|
||||
def endDocument(self): pass
|
||||
def startElement(self, name: str, atts: AttributeList): pass
|
||||
def endElement(self, name: str): pass
|
||||
def characters(self, ch: str, start: int, length: int): pass
|
||||
def ignorableWhitespace(self, ch: str, start: int, length: int): pass
|
||||
def processingInstruction(self, target: str, data: str): pass
|
||||
def notationDecl(self, name: str, public_id: str, system_id: str): pass
|
||||
def unparsedEntityDecl(self, name: str, public_id: str, system_id: str, notation_name: str): pass
|
||||
def resolveEntity(self, public_id: str, system_id: str) -> InputSource: return InputSource(system_id)
|
||||
def warning(self, exception: SAXParseException): pass
|
||||
def error(self, exception: SAXParseException): pass
|
||||
def fatalError(self, exception: SAXParseException): raise exception
|
||||
|
||||
def toString(self) -> str:
|
||||
return f"HandlerBase@{hex(id(self))}"
|
||||
|
||||
def equals(self, other) -> bool:
|
||||
return self is other
|
||||
|
||||
def hashCode(self) -> int:
|
||||
return hash(self) & 0x7FFFFFFF
|
||||
|
||||
|
||||
# ============================================================
|
||||
# DocumentHandler (deprecated SAX1)
|
||||
# ============================================================
|
||||
|
||||
class DocumentHandler(Stub):
|
||||
"""
|
||||
org.xml.sax.DocumentHandler
|
||||
Deprecated SAX1 interface for document handlers.
|
||||
"""
|
||||
def setDocumentLocator(self, locator: Locator): pass
|
||||
def startDocument(self): pass
|
||||
def endDocument(self): pass
|
||||
def startElement(self, name: str, atts: AttributeList): pass
|
||||
def endElement(self, name: str): pass
|
||||
def characters(self, ch: str, start: int, length: int): pass
|
||||
def ignorableWhitespace(self, ch: str, start: int, length: int): pass
|
||||
def processingInstruction(self, target: str, data: str): pass
|
||||
|
||||
def toString(self) -> str:
|
||||
return f"DocumentHandler@{hex(id(self))}"
|
||||
|
||||
def equals(self, other) -> bool:
|
||||
return self is other
|
||||
|
||||
def hashCode(self) -> int:
|
||||
return hash(self) & 0x7FFFFFFF
|
||||
|
||||
|
||||
# ============================================================
|
||||
# XMLReader
|
||||
# ============================================================
|
||||
|
||||
class XMLReader(Stub):
|
||||
"""
|
||||
org.xml.sax.XMLReader
|
||||
Interface for reading an XML document using callbacks.
|
||||
Wraps Python xml.sax.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._content_handler = None
|
||||
self._dtd_handler = None
|
||||
self._error_handler = None
|
||||
self._entity_resolver = None
|
||||
self._locale = None
|
||||
self._features = {}
|
||||
self._properties = {}
|
||||
|
||||
def parse(self, input_source: Any):
|
||||
"""
|
||||
Parse an XML document from an InputSource or system ID.
|
||||
"""
|
||||
if isinstance(input_source, InputSource):
|
||||
sys_id = input_source.getSystemId()
|
||||
elif isinstance(input_source, str):
|
||||
sys_id = input_source
|
||||
else:
|
||||
sys_id = str(input_source)
|
||||
|
||||
try:
|
||||
parser = _sax.make_parser()
|
||||
if self._content_handler:
|
||||
parser.setContentHandler(self._content_handler)
|
||||
if self._error_handler:
|
||||
parser.setErrorHandler(self._error_handler)
|
||||
if self._dtd_handler:
|
||||
parser.setDTDHandler(self._dtd_handler)
|
||||
if self._entity_resolver:
|
||||
parser.setEntityResolver(self._entity_resolver)
|
||||
parser.parse(sys_id)
|
||||
except _sax.SAXException as e:
|
||||
if self._error_handler:
|
||||
self._error_handler.fatalError(
|
||||
SAXParseException(str(e), "", sys_id, 0, 0))
|
||||
raise SAXException(str(e)) from e
|
||||
|
||||
def setContentHandler(self, handler: ContentHandler):
|
||||
self._content_handler = handler
|
||||
|
||||
def getContentHandler(self) -> Optional[ContentHandler]:
|
||||
return self._content_handler
|
||||
|
||||
def setDTDHandler(self, handler: DTDHandler):
|
||||
self._dtd_handler = handler
|
||||
|
||||
def getDTDHandler(self) -> Optional[DTDHandler]:
|
||||
return self._dtd_handler
|
||||
|
||||
def setErrorHandler(self, handler: ErrorHandler):
|
||||
self._error_handler = handler
|
||||
|
||||
def getErrorHandler(self) -> Optional[ErrorHandler]:
|
||||
return self._error_handler
|
||||
|
||||
def setEntityResolver(self, resolver: EntityResolver):
|
||||
self._entity_resolver = resolver
|
||||
|
||||
def getEntityResolver(self) -> Optional[EntityResolver]:
|
||||
return self._entity_resolver
|
||||
|
||||
def setLocale(self, locale):
|
||||
self._locale = locale
|
||||
|
||||
def getFeature(self, name: str) -> bool:
|
||||
return self._features.get(name, False)
|
||||
|
||||
def setFeature(self, name: str, value: bool):
|
||||
if name == "http://xml.org/sax/features/namespaces":
|
||||
self._features[name] = value
|
||||
elif name == "http://xml.org/sax/features/validation":
|
||||
self._features[name] = value
|
||||
elif name == "http://xml.org/sax/features/external-general-entities":
|
||||
self._features[name] = value
|
||||
elif name == "http://xml.org/sax/features/external-parameter-entities":
|
||||
self._features[name] = value
|
||||
else:
|
||||
raise SAXNotRecognizedException(f"Feature not recognized: {name}")
|
||||
|
||||
def getProperty(self, name: str) -> Any:
|
||||
return self._properties.get(name)
|
||||
|
||||
def setProperty(self, name: str, value: Any):
|
||||
if name == "http://xml.org/sax/properties/lexical-handler":
|
||||
self._properties[name] = value
|
||||
else:
|
||||
raise SAXNotRecognizedException(f"Property not recognized: {name}")
|
||||
|
||||
def toString(self) -> str:
|
||||
return f"XMLReader@{hex(id(self))}"
|
||||
|
||||
def equals(self, other) -> bool:
|
||||
return self is other
|
||||
|
||||
def hashCode(self) -> int:
|
||||
return hash(self) & 0x7FFFFFFF
|
||||
|
||||
|
||||
# ============================================================
|
||||
# XMLFilter
|
||||
# ============================================================
|
||||
|
||||
class XMLFilter(XMLReader):
|
||||
"""
|
||||
org.xml.sax.XMLFilter
|
||||
Interface for an XML filter.
|
||||
"""
|
||||
def setParent(self, parent: XMLReader):
|
||||
self._parent = parent
|
||||
|
||||
def getParent(self) -> Optional[XMLReader]:
|
||||
return getattr(self, '_parent', None)
|
||||
|
||||
def toString(self) -> str:
|
||||
return f"XMLFilter@{hex(id(self))}"
|
||||
|
||||
def equals(self, other) -> bool:
|
||||
return self is other
|
||||
|
||||
def hashCode(self) -> int:
|
||||
return hash(self) & 0x7FFFFFFF
|
||||
|
||||
|
||||
# ============================================================
|
||||
# XMLFilterImpl
|
||||
# ============================================================
|
||||
|
||||
class XMLFilterImpl(XMLFilter, ContentHandler, DTDHandler, EntityResolver, ErrorHandler):
|
||||
"""
|
||||
org.xml.sax.helpers.XMLFilterImpl
|
||||
Base class for XML filters with default implementation.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._parent = None
|
||||
|
||||
def setParent(self, parent: XMLReader):
|
||||
self._parent = parent
|
||||
|
||||
def getParent(self) -> Optional[XMLReader]:
|
||||
return self._parent
|
||||
|
||||
def parse(self, input_source: Any):
|
||||
if self._parent:
|
||||
self._parent.setContentHandler(self)
|
||||
self._parent.setDTDHandler(self)
|
||||
self._parent.setEntityResolver(self)
|
||||
self._parent.setErrorHandler(self)
|
||||
self._parent.parse(input_source)
|
||||
|
||||
# ContentHandler delegation
|
||||
def setContentHandler(self, handler: ContentHandler):
|
||||
self._content_handler = handler
|
||||
|
||||
def getContentHandler(self) -> Optional[ContentHandler]:
|
||||
return getattr(self, '_content_handler', None)
|
||||
|
||||
def setDTDHandler(self, handler: DTDHandler):
|
||||
self._dtd_handler = handler
|
||||
|
||||
def getDTDHandler(self) -> Optional[DTDHandler]:
|
||||
return getattr(self, '_dtd_handler', None)
|
||||
|
||||
def setEntityResolver(self, resolver: EntityResolver):
|
||||
self._entity_resolver = resolver
|
||||
|
||||
def getEntityResolver(self) -> Optional[EntityResolver]:
|
||||
return getattr(self, '_entity_resolver', None)
|
||||
|
||||
def setErrorHandler(self, handler: ErrorHandler):
|
||||
self._error_handler = handler
|
||||
|
||||
def getErrorHandler(self) -> Optional[ErrorHandler]:
|
||||
return getattr(self, '_error_handler', None)
|
||||
|
||||
def setLocale(self, locale): pass
|
||||
|
||||
def getFeature(self, name: str) -> bool:
|
||||
return False
|
||||
|
||||
def setFeature(self, name: str, value: bool): pass
|
||||
|
||||
def getProperty(self, name: str): return None
|
||||
|
||||
def setProperty(self, name: str, value): pass
|
||||
|
||||
# Delegated implementations
|
||||
def resolveEntity(self, public_id: str, system_id: str) -> InputSource:
|
||||
if self._entity_resolver:
|
||||
return self._entity_resolver.resolveEntity(public_id, system_id)
|
||||
return InputSource(system_id)
|
||||
|
||||
def notationDecl(self, name: str, public_id: str, system_id: str):
|
||||
if self._dtd_handler:
|
||||
self._dtd_handler.notationDecl(name, public_id, system_id)
|
||||
|
||||
def unparsedEntityDecl(self, name: str, public_id: str, system_id: str, notation_name: str):
|
||||
if self._dtd_handler:
|
||||
self._dtd_handler.unparsedEntityDecl(name, public_id, system_id, notation_name)
|
||||
|
||||
def setDocumentLocator(self, locator: Locator):
|
||||
if self._content_handler:
|
||||
self._content_handler.setDocumentLocator(locator)
|
||||
|
||||
def startDocument(self):
|
||||
if self._content_handler:
|
||||
self._content_handler.startDocument()
|
||||
|
||||
def endDocument(self):
|
||||
if self._content_handler:
|
||||
self._content_handler.endDocument()
|
||||
|
||||
def startPrefixMapping(self, prefix: str, uri: str):
|
||||
if self._content_handler:
|
||||
self._content_handler.startPrefixMapping(prefix, uri)
|
||||
|
||||
def endPrefixMapping(self, prefix: str):
|
||||
if self._content_handler:
|
||||
self._content_handler.endPrefixMapping(prefix)
|
||||
|
||||
def startElement(self, namespace_uri: str, local_name: str, qname: str, atts: Attributes):
|
||||
if self._content_handler:
|
||||
self._content_handler.startElement(namespace_uri, local_name, qname, atts)
|
||||
|
||||
def endElement(self, namespace_uri: str, local_name: str, qname: str):
|
||||
if self._content_handler:
|
||||
self._content_handler.endElement(namespace_uri, local_name, qname)
|
||||
|
||||
def characters(self, ch: str, start: int, length: int):
|
||||
if self._content_handler:
|
||||
self._content_handler.characters(ch, start, length)
|
||||
|
||||
def ignorableWhitespace(self, ch: str, start: int, length: int):
|
||||
if self._content_handler:
|
||||
self._content_handler.ignorableWhitespace(ch, start, length)
|
||||
|
||||
def processingInstruction(self, target: str, data: str):
|
||||
if self._content_handler:
|
||||
self._content_handler.processingInstruction(target, data)
|
||||
|
||||
def skippedEntity(self, name: str):
|
||||
if self._content_handler:
|
||||
self._content_handler.skippedEntity(name)
|
||||
|
||||
def warning(self, exception: SAXParseException):
|
||||
if self._error_handler:
|
||||
self._error_handler.warning(exception)
|
||||
|
||||
def error(self, exception: SAXParseException):
|
||||
if self._error_handler:
|
||||
self._error_handler.error(exception)
|
||||
|
||||
def fatalError(self, exception: SAXParseException):
|
||||
if self._error_handler:
|
||||
self._error_handler.fatalError(exception)
|
||||
raise exception
|
||||
|
||||
def toString(self) -> str:
|
||||
return f"XMLFilterImpl@{hex(id(self))}"
|
||||
|
||||
def equals(self, other) -> bool:
|
||||
return self is other
|
||||
|
||||
def hashCode(self) -> int:
|
||||
return hash(self) & 0x7FFFFFFF
|
||||
|
||||
|
||||
# ============================================================
|
||||
# DefaultHandler
|
||||
# ============================================================
|
||||
|
||||
class DefaultHandler(ContentHandler, DTDHandler, EntityResolver, ErrorHandler):
|
||||
"""
|
||||
org.xml.sax.helpers.DefaultHandler
|
||||
Default base class for SAX2 event handlers.
|
||||
"""
|
||||
def setDocumentLocator(self, locator: Locator): pass
|
||||
def startDocument(self): pass
|
||||
def endDocument(self): pass
|
||||
def startPrefixMapping(self, prefix: str, uri: str): pass
|
||||
def endPrefixMapping(self, prefix: str): pass
|
||||
def startElement(self, namespace_uri: str, local_name: str, qname: str, atts: Attributes): pass
|
||||
def endElement(self, namespace_uri: str, local_name: str, qname: str): pass
|
||||
def characters(self, ch: str, start: int, length: int): pass
|
||||
def ignorableWhitespace(self, ch: str, start: int, length: int): pass
|
||||
def processingInstruction(self, target: str, data: str): pass
|
||||
def skippedEntity(self, name: str): pass
|
||||
def notationDecl(self, name: str, public_id: str, system_id: str): pass
|
||||
def unparsedEntityDecl(self, name: str, public_id: str, system_id: str, notation_name: str): pass
|
||||
def resolveEntity(self, public_id: str, system_id: str) -> InputSource: return InputSource(system_id)
|
||||
def warning(self, exception: SAXParseException): pass
|
||||
def error(self, exception: SAXParseException): pass
|
||||
def fatalError(self, exception: SAXParseException): raise exception
|
||||
|
||||
def toString(self) -> str:
|
||||
return f"DefaultHandler@{hex(id(self))}"
|
||||
|
||||
def equals(self, other) -> bool:
|
||||
return self is other
|
||||
|
||||
def hashCode(self) -> int:
|
||||
return hash(self) & 0x7FFFFFFF
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Helpers (stub)
|
||||
# ============================================================
|
||||
|
||||
class Helpers(Stub):
|
||||
"""
|
||||
org.xml.sax.helpers (namespace placeholder)
|
||||
"""
|
||||
@staticmethod
|
||||
def makeParser(parser_class: str = None):
|
||||
return XMLReader()
|
||||
|
||||
@staticmethod
|
||||
def parseXML(source: Any, handler: ContentHandler):
|
||||
reader = XMLReader()
|
||||
reader.setContentHandler(handler)
|
||||
reader.parse(source)
|
||||
|
||||
def toString(self) -> str:
|
||||
return "Helpers"
|
||||
|
||||
def equals(self, other) -> bool:
|
||||
return isinstance(other, Helpers)
|
||||
|
||||
def hashCode(self) -> int:
|
||||
return hash("Helpers") & 0x7FFFFFFF
|
||||
Reference in new issue
Block a user