| """
|
| On-device verification for the cross-compiled lxml wheel (norelro).
|
|
|
| Run after installing:
|
| pip install lxml-6.1.1-cp312-cp312-android_24_x86_64.whl
|
|
|
| Usage:
|
| python Test_lxml.py
|
|
|
| Exit code 0 = everything required PASSed.
|
|
|
| Generated by RIMI
|
| """
|
| import sys
|
|
|
| RESULTS = []
|
|
|
|
|
| def test(name, fn):
|
| try:
|
| fn()
|
| RESULTS.append((name, "PASS", None))
|
| except Exception as exc:
|
| RESULTS.append((name, "FAIL", "%s: %s" % (type(exc).__name__, exc)))
|
| print(" ! %s -> %s: %s" % (name, type(exc).__name__, exc))
|
|
|
|
|
| def section(title):
|
| print("=" * 60)
|
| print(title)
|
| print("=" * 60)
|
|
|
|
|
|
|
|
|
|
|
| def import_lxml():
|
| import lxml.etree as etree
|
| print(" lxml.etree version", etree.LXML_VERSION)
|
| print(" libxml2", etree.LIBXML_VERSION)
|
| print(" libxslt", etree.LIBXSLT_VERSION)
|
|
|
|
|
| def import_objectify():
|
| from lxml import objectify
|
| print(" lxml.objectify OK")
|
|
|
|
|
| def import_html():
|
| from lxml import html
|
| print(" lxml.html OK")
|
|
|
|
|
| def import_html_clean():
|
| from lxml_html_clean import clean
|
| print(" lxml_html_clean OK")
|
|
|
|
|
|
|
|
|
|
|
| def parse_string():
|
| from lxml import etree
|
| xml = b"<root><item id='1'>hello</item><item id='2'>world</item></root>"
|
| root = etree.fromstring(xml)
|
| assert root.tag == "root"
|
| items = root.findall("item")
|
| assert len(items) == 2
|
| assert items[0].get("id") == "1"
|
| assert items[0].text == "hello"
|
|
|
|
|
| def parse_file():
|
| from lxml import etree
|
| xml = b"<data><row><a>1</a><b>2</b></row></data>"
|
| root = etree.fromstring(xml)
|
| row = root.find("row")
|
| assert int(row.find("a").text) == 1
|
| assert int(row.find("b").text) == 2
|
|
|
|
|
| def tostring():
|
| from lxml import etree
|
| root = etree.Element("parent")
|
| child = etree.SubElement(root, "child")
|
| child.text = "text"
|
| s = etree.tostring(root, encoding="unicode")
|
| assert "<child>text</child>" in s
|
|
|
|
|
| def xpath():
|
| from lxml import etree
|
| xml = b"<root><a x='1'/><a x='2'/><b/></root>"
|
| root = etree.fromstring(xml)
|
| a_list = root.xpath("//a")
|
| assert len(a_list) == 2
|
| vals = root.xpath("//a/@x")
|
| assert vals == ["1", "2"]
|
| first = root.xpath("//a[@x='2']")
|
| assert len(first) == 1
|
|
|
|
|
| def namespaces():
|
| from lxml import etree
|
| ns = {"s": "http://example.com/ns"}
|
| xml = b'<root xmlns:s="http://example.com/ns"><s:item>ok</s:item></root>'
|
| root = etree.fromstring(xml)
|
| items = root.xpath("//s:item", namespaces=ns)
|
| assert len(items) == 1
|
| assert items[0].text == "ok"
|
|
|
|
|
|
|
|
|
|
|
| def build_tree():
|
| from lxml import etree
|
| root = etree.Element("root")
|
| for i in range(5):
|
| child = etree.SubElement(root, "item")
|
| child.set("index", str(i))
|
| child.text = "val_%d" % i
|
| assert len(root) == 5
|
| assert root[2].get("index") == "2"
|
| assert root[4].text == "val_4"
|
|
|
|
|
| def modify_tree():
|
| from lxml import etree
|
| root = etree.Element("root")
|
| a = etree.SubElement(root, "a")
|
| b = etree.SubElement(root, "b")
|
| root.remove(b)
|
| assert len(root) == 1
|
| a.text = "modified"
|
| assert root[0].text == "modified"
|
|
|
|
|
|
|
|
|
|
|
| def html_parse():
|
| from lxml import html
|
| doc = html.fromstring("<html><body><p>Hello</p><p>World</p></body></html>")
|
| ps = doc.xpath("//p")
|
| assert len(ps) == 2
|
| assert ps[0].text == "Hello"
|
|
|
|
|
| def html_tostring():
|
| from lxml import html
|
| doc = html.fromstring("<html><body><div id='main'>content</div></body></html>")
|
| s = html.tostring(doc, encoding="unicode")
|
| assert "content" in s
|
| assert 'id="main"' in s
|
|
|
|
|
|
|
|
|
|
|
| def html_clean():
|
| from lxml_html_clean import Cleaner
|
| from lxml import html
|
| dirty = '<html><body><p>safe</p></body></html>'
|
| doc = html.fromstring(dirty)
|
| c = Cleaner()
|
| c.clean_html(doc)
|
| s = html.tostring(doc, encoding="unicode")
|
| assert "safe" in s
|
|
|
|
|
|
|
|
|
|
|
| def xslt_transform():
|
| from lxml import etree
|
| xml = b"<root><item>1</item><item>2</item></root>"
|
| xslt_str = b"""<xsl:stylesheet version="1.0"
|
| xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
| <xsl:template match="/">
|
| <out><xsl:for-each select="root/item">
|
| <val><xsl:value-of select="."/></val>
|
| </xsl:for-each></out>
|
| </xsl:template>
|
| </xsl:stylesheet>"""
|
| xml_doc = etree.fromstring(xml)
|
| xslt_doc = etree.fromstring(xslt_str)
|
| transform = etree.XSLT(xslt_doc)
|
| result = transform(xml_doc)
|
| s = etree.tostring(result, encoding="unicode")
|
| assert "<val>1</val>" in s
|
| assert "<val>2</val>" in s
|
|
|
|
|
|
|
|
|
|
|
| def schema_validate():
|
| from lxml import etree
|
| schema_xml = b"""<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
| <xs:element name="root">
|
| <xs:complexType>
|
| <xs:sequence>
|
| <xs:element name="name" type="xs:string"/>
|
| <xs:element name="age" type="xs:decimal"/>
|
| </xs:sequence>
|
| </xs:complexType>
|
| </xs:element>
|
| </xs:schema>"""
|
| schema_doc = etree.fromstring(schema_xml)
|
| schema = etree.XMLSchema(schema_doc)
|
|
|
| valid = etree.fromstring(b"<root><name>Alice</name><age>30</age></root>")
|
| assert schema.validate(valid)
|
|
|
| invalid = etree.fromstring(b"<root><name>Alice</name></root>")
|
| assert not schema.validate(invalid)
|
|
|
|
|
|
|
|
|
|
|
| def c14n():
|
| from lxml import etree
|
| xml = b'<root attr="1" ><child>text</child></root>'
|
| root = etree.fromstring(xml)
|
| c = etree.tostring(root, method="c14n")
|
| assert b'attr="1"' in c
|
| assert b"<child>" in c
|
|
|
|
|
|
|
| def main():
|
| section("1. import / version")
|
| test("import lxml.etree", import_lxml)
|
| test("import lxml.objectify", import_objectify)
|
| test("import lxml.html", import_html)
|
| test("import lxml_html_clean", import_html_clean)
|
|
|
| section("2. etree basics")
|
| test("parse fromstring", parse_string)
|
| test("parse file-like", parse_file)
|
| test("tostring", tostring)
|
| test("xpath", xpath)
|
| test("namespaces", namespaces)
|
|
|
| section("3. build / modify trees")
|
| test("build tree", build_tree)
|
| test("modify tree", modify_tree)
|
|
|
| section("4. HTML parsing")
|
| test("html parse", html_parse)
|
| test("html tostring", html_tostring)
|
|
|
| section("5. html_clean (bundled dep)")
|
| test("clean HTML", html_clean)
|
|
|
| section("6. XSLT")
|
| test("xslt transform", xslt_transform)
|
|
|
| section("7. XML schema validation")
|
| test("schema validate", schema_validate)
|
|
|
| section("8. c14n")
|
| test("canonicalization", c14n)
|
|
|
| print()
|
| print("=" * 60)
|
| print("SUMMARY")
|
| print("=" * 60)
|
| fails = 0
|
| for name, status, why in RESULTS:
|
| mark = " OK" if status == "PASS" else "FAIL"
|
| print("%s %s" % (mark, name))
|
| if why:
|
| print(" -> %s" % why)
|
| if status == "FAIL":
|
| fails += 1
|
| print()
|
| passed = len(RESULTS) - fails
|
| print("passed=%d failed=%d" % (passed, fails))
|
| if fails:
|
| print("RESULT: FAILED")
|
| else:
|
| print("RESULT: PASSED")
|
| sys.exit(1 if fails else 0)
|
|
|
|
|
| if __name__ == "__main__":
|
| main()
|
|
|