I've digged in. After some time of figuring out and reading libxslt code (the only way to understand what's really happening, because libxslt's documentation is ugly) I've ended up with solution.
The patch is placed below and it's rather simple. I'm almost sure that it needs a few of your fixes just because you know much-much better how to manage elements, memory and so on. But it does things I really needed.
I worked with source code of lxml 2.2.4.
diff -r c8813376f20b -r 0a195f4f7df2 xslt.pxd
--- a/xslt.pxd Tue Dec 29 19:03:23 2009 +0300
+++ b/xslt.pxd Tue Dec 29 19:25:19 2009 +0300
@@ -30,10 +30,13 @@
xmlNode* node
xmlDoc* output
xmlNode* insert
+ xmlNode* inst
xsltTransformState state
ctypedef struct xsltStackElem
+ ctypedef struct xsltTemplate
+
cdef xsltStylesheet* xsltParseStylesheetDoc(xmlDoc* doc) nogil
cdef void xsltFreeStylesheet(xsltStylesheet* sheet) nogil
@@ -84,6 +87,10 @@
cdef xsltTransformContext* xsltNewTransformContext(xsltStylesheet* style,
xmlDoc* doc) nogil
cdef void xsltFreeTransformContext(xsltTransformContext* context) nogil
+ cdef void xsltApplyOneTemplate(xsltTransformContext* ctxt,
+ xmlNode* contextNode, xmlNode* list,
+ xsltTemplate* templ,
+ xsltStackElem* params) nogil
cdef extern from "libxslt/xsltutils.h":
cdef int xsltSaveResultToString(char** doc_txt_ptr,
diff -r c8813376f20b -r 0a195f4f7df2 xsltext.pxi
--- a/xsltext.pxi Tue Dec 29 19:03:23 2009 +0300
+++ b/xsltext.pxi Tue Dec 29 19:25:19 2009 +0300
@@ -66,6 +66,30 @@
tree.xmlFreeNode(c_parent)
return results
+ def evaluate(self, _XSLTContext context not None, _Element output_parent):
+ u"""evaluate(self, context, output_parent)
+
+ Call this method to evaluate XSLT content of extension element.
+
+ Evaluation result will be placed into output_parent element.
+ """
+ cdef xslt.xsltTransformContext* ctxt
+ cdef xmlNode* c_backup
+
+ ctxt = context._xsltCtxt
+ c_backup = ctxt.insert
+
+ # I'm not sure about output_parent's type, maybe it should be some type
+ # of proxy. This needs better knowing man's opinion.
+ # And I'm using output_parent node for adding results instead of
+ # elements list used in apply_templates, that's easier and allows to
+ # use attributes added to extension element with <xsl:attribute>.
+ # And that's exactly the thing I need.
+ ctxt.insert = output_parent._c_node
+ xslt.xsltApplyOneTemplate(ctxt,
+ ctxt.node, ctxt.inst.children, NULL, NULL)
+ ctxt.insert = c_backup
+
cdef _registerXSLTExtensions(xslt.xsltTransformContext* c_ctxt,
extension_dict):
--------------- PATCH ENDS HERE ---------------
So, with this patch we can handle XSLT content of extension elements (including attributes) and we can have extension elements inside extension elements.
For example I can have xslt file looks like:
<xsl:stylesheet version="1.0"
xmlns:my="testns"
extension-element-prefixes="my">
<xsl:template match="/">
<foo>
<my:ext>
<xsl:attribute name="test">123</xsl:attribute>
<child>
<xsl:attribute name="test2">
<my:ext>blabla</my:ext>
</xsl:attribute>
</child>
</my:ext>
</foo>
</xsl:template>
</xsl:stylesheet>
And execute method for my:ext looks like:
def execute(self, context, self_node, input_node, output_parent):
tmp = etree.Element('tmp')
self.evaluate(context, tmp)
output_parent.append(tmp)
And the result is:
<?xml version="1.0"?>
<foo>
<tmp test="123">
<child test2="blabla"/>
</tmp>
</foo>
I think it's great feature. Is there any chance this thing will be included in nearest release?
Thanks.
--
Marat