anyxml 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
anyxml-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,28 @@
1
+ Metadata-Version: 2.3
2
+ Name: anyxml
3
+ Version: 0.1.0
4
+ Summary: A minimal reimplementation of `ET.tostring` that supports unescaped 'raw' text content.
5
+ Author: BHznJNs
6
+ Author-email: BHznJNs <bhznjns@outlook.com>
7
+ Requires-Python: >=3.11
8
+ Description-Content-Type: text/markdown
9
+
10
+ # AnyXml
11
+
12
+ A minimal reimplementation of `ET.tostring` that supports unescaped "raw" text content.
13
+
14
+ The standard library's `ET.tostring` always XML-escapes the `text`/`tail` content of elements (e.g. `<`, `&`), which makes it impossible to inject pre-built, already-valid XML fragments (or other raw strings) during serialization.
15
+ This class provides :meth:`tostring`, which behaves similarly to `ET.tostring` but additionally supports:
16
+
17
+ - Strings wrapped in :class:`RawText` are emitted verbatim during serialization, without any escaping; regular `str` text is still escaped according to XML rules.
18
+ - Comment nodes (`ET.Comment`) and processing instruction nodes (`ET.ProcessingInstruction`) are rendered as `<!--...-->` and `<?...?>` respectively.
19
+ - Elements with no text and no children are rendered as self-closing tags (`<tag/>`).
20
+
21
+ ## Example
22
+
23
+ ```
24
+ >>> el = ET.Element("p")
25
+ >>> el.text = AnyXml.RawText("<b>bold</b>")
26
+ >>> AnyXml.tostring(el)
27
+ '<p><b>bold</b></p>'
28
+ ```
anyxml-0.1.0/README.md ADDED
@@ -0,0 +1,19 @@
1
+ # AnyXml
2
+
3
+ A minimal reimplementation of `ET.tostring` that supports unescaped "raw" text content.
4
+
5
+ The standard library's `ET.tostring` always XML-escapes the `text`/`tail` content of elements (e.g. `<`, `&`), which makes it impossible to inject pre-built, already-valid XML fragments (or other raw strings) during serialization.
6
+ This class provides :meth:`tostring`, which behaves similarly to `ET.tostring` but additionally supports:
7
+
8
+ - Strings wrapped in :class:`RawText` are emitted verbatim during serialization, without any escaping; regular `str` text is still escaped according to XML rules.
9
+ - Comment nodes (`ET.Comment`) and processing instruction nodes (`ET.ProcessingInstruction`) are rendered as `<!--...-->` and `<?...?>` respectively.
10
+ - Elements with no text and no children are rendered as self-closing tags (`<tag/>`).
11
+
12
+ ## Example
13
+
14
+ ```
15
+ >>> el = ET.Element("p")
16
+ >>> el.text = AnyXml.RawText("<b>bold</b>")
17
+ >>> AnyXml.tostring(el)
18
+ '<p><b>bold</b></p>'
19
+ ```
@@ -0,0 +1,14 @@
1
+ [project]
2
+ name = "anyxml"
3
+ version = "0.1.0"
4
+ description = "A minimal reimplementation of `ET.tostring` that supports unescaped 'raw' text content."
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "BHznJNs", email = "bhznjns@outlook.com" }
8
+ ]
9
+ requires-python = ">=3.11"
10
+ dependencies = []
11
+
12
+ [build-system]
13
+ requires = ["uv_build>=0.9.28,<0.10.0"]
14
+ build-backend = "uv_build"
@@ -0,0 +1,57 @@
1
+ import xml.etree.ElementTree as ET
2
+ from xml.sax.saxutils import escape, quoteattr
3
+
4
+
5
+ class AnyXml:
6
+ """A minimal reimplementation of `ET.tostring` that supports unescaped "raw" text content.
7
+
8
+ The standard library's `ET.tostring` always XML-escapes the `text`/`tail` content of elements (e.g. `<`, `&`), which makes it impossible to inject pre-built, already-valid XML fragments (or other raw strings) during serialization.
9
+ This class provides :meth:`tostring`, which behaves similarly to `ET.tostring` but additionally supports:
10
+
11
+ - Strings wrapped in :class:`RawText` are emitted verbatim during serialization, without any escaping; regular `str` text is still escaped according to XML rules.
12
+ - Comment nodes (`ET.Comment`) and processing instruction nodes (`ET.ProcessingInstruction`) are rendered as `<!--...-->` and `<?...?>` respectively.
13
+ - Elements with no text and no children are rendered as self-closing tags (`<tag/>`).
14
+
15
+ Examples:
16
+ >>> el = ET.Element("p")
17
+ >>> el.text = AnyXml.RawText("<b>bold</b>")
18
+ >>> AnyXml.tostring(el)
19
+ '<p><b>bold</b></p>'
20
+ """
21
+
22
+ class RawText(str): pass
23
+
24
+ @staticmethod
25
+ def _text(s: str) -> str:
26
+ if isinstance(s, AnyXml.RawText): return s
27
+ return escape(s)
28
+
29
+ @staticmethod
30
+ def _comment(el: ET.Element) -> str:
31
+ assert el.tag is ET.Comment
32
+ return f"<!--{el.text or ''}-->"
33
+
34
+ @staticmethod
35
+ def _processing_instruction(el: ET.Element) -> str:
36
+ assert el.tag is ET.ProcessingInstruction
37
+ return f"<?{el.text or ''}?>"
38
+
39
+ @staticmethod
40
+ def tostring(el: ET.Element) -> str:
41
+ if el.tag is ET.Comment: return AnyXml._comment(el)
42
+ if el.tag is ET.ProcessingInstruction: return AnyXml._processing_instruction(el)
43
+
44
+ attrs = "".join(f" {k}={quoteattr(str(v))}" for k, v in el.attrib.items())
45
+
46
+ children_xml = []
47
+ for child in el:
48
+ children_xml.append(AnyXml.tostring(child))
49
+ if child.tail:
50
+ children_xml.append(AnyXml._text(child.tail))
51
+
52
+ if el.text is None and len(children_xml) == 0:
53
+ return f"<{el.tag}{attrs}/>"
54
+
55
+ inner_text = AnyXml._text(el.text) if el.text is not None else ""
56
+ body = inner_text + "".join(children_xml)
57
+ return f"<{el.tag}{attrs}>{body}</{el.tag}>"
File without changes