[libxslt.wiki] Create Python bindings



commit 559f0ebf995efc8ac24f52d45c81152d7b198c02
Author: Nick Wellnhofer <wellnhofer aevum de>
Date:   Sat Feb 12 17:28:00 2022 +0000

    Create Python bindings

 Python-bindings.md | 135 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 135 insertions(+)
---
diff --git a/Python-bindings.md b/Python-bindings.md
new file mode 100644
index 0000000..4d5ed34
--- /dev/null
+++ b/Python-bindings.md
@@ -0,0 +1,135 @@
+The libxslt Python module depends on the [libxml2 Python](http://xmlsoft.org/python.html) module.
+
+The distribution includes a set of Python bindings, which are guaranteed to be maintained as part of the 
library in the future, though the Python interface have not yet reached the completeness of the C API.
+
+[Stéphane Bidoul](mailto:stephane bidoul softwareag com) maintains [a Windows port of the Python 
bindings](http://users.skynet.be/sbi/libxml-python/).
+
+Note to people interested in building bindings, the API is formalized as [an XML API description 
file](http://xmlsoft.org/XSLT/libxslt-api.xml) which allows to automate a large part of the Python bindings, 
this includes function descriptions, enums, structures, typedefs, etc... The Python script used to build the 
bindings is python/generator.py in the source distribution.
+
+To install the Python bindings there are 2 options:
+
+* If you use an RPM based distribution, simply install the [libxml2-python 
RPM](http://rpmfind.net/linux/rpm2html/search.php?query=libxml2-python) and the [libxslt-python 
RPM](http://rpmfind.net/linux/rpm2html/search.php?query=libxslt-python).
+* Otherwise use the [libxml2-python module distribution](ftp://xmlsoft.org/libxml2/python/) corresponding to 
your installed version of libxml2 and libxslt. Note that to install it you will need both libxml2 and libxslt 
installed and run "python [setup.py](http://setup.py) build install" in the module tree.
+
+The distribution includes a set of examples and regression tests for the python bindings in the 
`python/tests` directory. Here are some excepts from those tests:
+
+### [basic.py](http://basic.py):
+
+This is a basic test of XSLT interfaces: loading a stylesheet and a document, transforming the document and 
saving the result.
+
+```
+import libxml2
+import libxslt
+
+styledoc = libxml2.parseFile("test.xsl")
+style = libxslt.parseStylesheetDoc(styledoc)
+doc = libxml2.parseFile("test.xml")
+result = style.applyStylesheet(doc, None)
+style.saveResultToFilename("foo", result, 0)
+style.freeStylesheet()
+doc.freeDoc()
+result.freeDoc()
+```
+
+The Python module is called libxslt, you will also need the libxml2 module for the operations on XML trees. 
Let's have a look at the objects manipulated in that example and how is the processing done:
+
+* `styledoc` : is a libxml2 document tree. It is obtained by parsing the XML file "test.xsl" containing the 
stylesheet.
+* `style` : this is a precompiled stylesheet ready to be used by the following transformations (note the 
plural form, multiple transformations can resuse the same stylesheet).
+* `doc` : this is the document to apply the transformation to. In this case it is simply generated by 
parsing it from a file but any other processing is possible as long as one get a libxml2 Doc. Note that HTML 
tree are suitable for XSLT processing in libxslt. This is actually how this page is generated !
+* `result` : this is a document generated by applying the stylesheet to the document. Note that some of the 
stylesheet information may be related to the serialization of that document and as in this example a specific 
saveResultToFilename() method of the stylesheet should be used to save it to a file (in that case to "foo").
+
+Also note the need to explicitely deallocate documents with freeDoc() except for the stylesheet document 
which is freed when its compiled form is garbage collected.
+
+### [extfunc.py](http://extfunc.py):
+
+This one is a far more complex test. It shows how to modify the behaviour of an XSLT transformation by 
passing parameters and how to extend the XSLT engine with functions defined in python:
+
+```
+import libxml2
+import libxslt
+import string
+
+nodeName = None
+def f(ctx, str):
+    global nodeName
+
+    #
+    # Small check to verify the context is correcly accessed
+    #
+    try:
+        pctxt = libxslt.xpathParserContext(_obj=ctx)
+        ctxt = pctxt.context()
+        tctxt = ctxt.transformContext()
+        nodeName = tctxt.insertNode().name
+    except:
+        pass
+
+    return string.upper(str)
+
+libxslt.registerExtModuleFunction("foo", "http://example.com/foo";, f)
+```
+
+This code defines and register an extension function. Note that the function can be bound to any name (foo) 
and how the binding is also associated to a namespace name "<http://example.com/foo>". From an XSLT point of 
view the function just returns an upper case version of the string passed as a parameter. But the first part 
of the function also read some contextual information from the current XSLT processing environement, in that 
case it looks for the current insertion node in the resulting output (either the resulting document or the 
Result Value Tree being generated), and saves it to a global variable for checking that the access actually 
worked.
+
+For more information on the xpathParserContext and transformContext objects check the [libray internals 
description](http://xmlsoft.org/XSLT/internals.html). The pctxt is actually an object from a class derived 
from the libxml2.xpathParserContext() with just a couple more properties including the possibility to look up 
the XSLT transformation context from the XPath context.
+
+```
+styledoc = libxml2.parseDoc("""
+<xsl:stylesheet version='1.0'
+  xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
+  xmlns:foo='http://example.com/foo'
+  xsl:exclude-result-prefixes='foo'>
+
+  <xsl:param name='bar'>failure</xsl:param>
+  <xsl:template match='/'>
+    <article><xsl:value-of select='foo:foo($bar)'/></article>
+  </xsl:template>
+</xsl:stylesheet>
+""")
+```
+
+Here is a simple example of how to read an XML document from a python string with libxml2. Note how this 
stylesheet:
+
+* Uses a global parameter `bar`
+* Reference the extension function f
+* how the Namespace name "<http://example.com/foo>" has to be bound to a prefix
+* how that prefix is excluded from the output
+* how the function is called from the select
+
+```
+style = libxslt.parseStylesheetDoc(styledoc)
+doc = libxml2.parseDoc("<doc/>")
+result = style.applyStylesheet(doc, { "bar": "'success'" })
+style.freeStylesheet()
+doc.freeDoc()
+```
+
+that part is identical, to the basic example except that the transformation is passed a dictionary of 
parameters. Note that the string passed "success" had to be quoted, otherwise it is interpreted as an XPath 
query for the childs of root named "success".
+
+```
+root = result.children
+if root.name != "article":
+    print "Unexpected root node name"
+    sys.exit(1)
+if root.content != "SUCCESS":
+    print "Unexpected root node content, extension function failed"
+    sys.exit(1)
+if nodeName != 'article':
+    print "The function callback failed to access its context"
+    sys.exit(1)
+
+result.freeDoc()
+```
+
+That part just verifies that the transformation worked, that the parameter got properly passed to the 
engine, that the function f() got called and that it properly accessed the context to find the name of the 
insertion node.
+
+### [pyxsltproc.py](http://pyxsltproc.py):
+
+this module is a bit too long to be described there but it is basically a rewrite of the xsltproc command 
line interface of libxslt in Python. It provides nearly all the functionalities of xsltproc and can be used 
as a base module to write Python customized XSLT processors. One of the thing to notice are:
+
+```
+libxml2.lineNumbersDefault(1)
+libxml2.substituteEntitiesDefault(1)
+```
+
+those two calls in the main() function are needed to force the libxml2 processor to generate DOM trees 
compliant with the XPath data model.
\ No newline at end of file


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]