[Lxml-checkins] r52034 - in lxml/trunk: . doc

scoder at codespeak.net scoder at codespeak.net
Sun Mar 2 09:32:00 CET 2008


Author: scoder
Date: Sun Mar  2 09:31:59 2008
New Revision: 52034

Modified:
   lxml/trunk/   (props changed)
   lxml/trunk/doc/xpathxslt.txt
Log:
 r3673 at delle:  sbehnel | 2008-03-02 08:56:22 +0100
  r3663 at delle:  sbehnel | 2008-03-02 08:56:13 +0100
  doc section on XSLT extension elements
 


Modified: lxml/trunk/doc/xpathxslt.txt
==============================================================================
--- lxml/trunk/doc/xpathxslt.txt	(original)
+++ lxml/trunk/doc/xpathxslt.txt	Sun Mar  2 09:31:59 2008
@@ -458,8 +458,127 @@
 ------------------
 
 Just like `custom extension functions`_, lxml supports custom
-extension *elements*.
+extension *elements* in XSLT.  This means, you can write XSLT code
+like this::
 
+  <xsl:template match="*">
+      <my:python-extension>
+          <some-content />
+      </my:python-extension>
+  </xsl:template>
+
+And then you can implement the element in Python like this::
+
+  >>> class MyExtElement(etree.XSLTExtension):
+  ...     def execute(self, context, self_node, input_node, output_parent):
+  ...         print "Hello from XSLT!"
+  ...         output_parent.text = "I did it!"
+  ...         # just copy own content input to output
+  ...         output_parent.extend( list(self_node) )
+
+The arguments passed to this function are
+
+context
+    The opaque evaluation context.  You need this when calling back
+    into the XSLT processor.
+
+self_node
+    A read-only Element object that represents the extension element
+    in the stylesheet.
+
+input_node
+    The current context Element in the input document (also read-only).
+
+output_parent
+    The current insertion point in the output document.  You can
+    append elements or set the text value (not the tail).  Apart from
+    that, the Element is read-only.
+
+In XSLT, extension elements can be used like any other XSLT element,
+except that they must be declared as extensions using the standard
+XSLT ``extension-element-prefixes`` option::
+
+  >>> xslt_ext_tree = etree.XML('''
+  ... <xsl:stylesheet version="1.0"
+  ...     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  ...     xmlns:my="testns"
+  ...     extension-element-prefixes="my">
+  ...     <xsl:template match="/">
+  ...         <foo><my:ext><child>XYZ</child></my:ext></foo>
+  ...     </xsl:template>
+  ...     <xsl:template match="child">
+  ...         <CHILD>--xyz--</CHILD>
+  ...     </xsl:template>
+  ... </xsl:stylesheet>''')
+
+To register the extension, add its name and namespace to the extension
+mapping of the XSLT object::
+
+  >>> my_extension = MyExtElement()
+  >>> extensions = { ('testns', 'ext') : my_extension }
+  >>> transform = etree.XSLT(xslt_ext_tree, extensions = extensions)
+
+Note how we pass an instance here, not the class of the extension.
+Now we can run the transformation and see how our extension is
+called::
+
+  >>> root = etree.XML('<dummy/>')
+  >>> result = transform(root)
+  Hello from XSLT!
+  >>> str(result)
+  '<?xml version="1.0"?>\n<foo>I did it!<child>XYZ</child></foo>\n'
+
+XSLT extensions are a very powerful feature that allows you to
+interact directly with the XSLT processor.  You have full access to
+the input document and the stylesheet, and you can even call back into
+the XSLT processor to process templates.  Here is an example that
+passes an Element into the ``.apply_templates()`` method of the
+``XSLTExtension`` instance::
+
+  >>> class MyExtElement(etree.XSLTExtension):
+  ...     def execute(self, context, self_node, input_node, output_parent):
+  ...         child = self_node[0]
+  ...         results = self.apply_templates(context, child)
+  ...         output_parent.append(results[0])
+
+  >>> my_extension = MyExtElement()
+  >>> extensions = { ('testns', 'ext') : my_extension }
+  >>> transform = etree.XSLT(xslt_ext_tree, extensions = extensions)
+
+  >>> root = etree.XML('<dummy/>')
+  >>> result = transform(root)
+  >>> str(result)
+  '<?xml version="1.0"?>\n<foo><CHILD>--xyz--</CHILD></foo>\n'
+
+Note how we applied the templates to a child of the extension element
+itself, i.e. to an element inside the stylesheet instead of an element
+of the input document.
+
+There is one important thing to keep in mind: all Elements that the
+``execute()`` method gets to deal with are read-only Elements, so you
+cannot modify them.  They also will not easily work in the API.  For
+example, you cannot pass them to the ``tostring()`` function or wrap
+them in an ``ElementTree``.
+
+What you can do, however, is to deepcopy them to make them normal
+Elements, and then modify them using the normal etree API.  So this
+will work::
+
+  >>> from copy import deepcopy
+  >>> class MyExtElement(etree.XSLTExtension):
+  ...     def execute(self, context, self_node, input_node, output_parent):
+  ...         child = deepcopy(self_node[0])
+  ...         child.text = "NEW TEXT"
+  ...         output_parent.append(child)
+
+  >>> my_extension = MyExtElement()
+  >>> extensions = { ('testns', 'ext') : my_extension }
+  >>> transform = etree.XSLT(xslt_ext_tree, extensions = extensions)
+
+  >>> root = etree.XML('<dummy/>')
+  >>> result = transform(root)
+  >>> str(result)
+  '<?xml version="1.0"?>\n<foo><child>NEW TEXT</child></foo>\n'
 
 
 The ``xslt()`` tree method


More information about the lxml-checkins mailing list