[xslt] patch - python bindings for extension elements



Attached is a patch of the libxslt-1.0.30 source which contains the
modifications needed to callback into python for extension element
binding. (Should patch against 1.0.31 too)

Thanks a ton for completing the function binding. I based most of the
code off of that.

Issues and oddities:

* Type wrapping

	I followed the example in libxslt.c for wrapping the
	xsltElemPreCompPtr.  Given that I am not entirely clear on the
	role of this object, I didn't touch the semantics behind it, only
	wrapped the pointer to act as a placeholder. `

	Shouldn't these type wrappers go in types.c?
	
	What is the role of xsltElemPreCompPtr?

* Returning from callbacks

	What should the behavior be when returning failure from the
	callback methods?  Right now results are ignored.

* Recommended method of packing python tuples

	PyTuple_SetItem steals object references, which bit me in the
	butt.  Use Py_BuildValue instead.
	
	http://www.python.org/doc/current/api/refcountDetails.html#l2h-13

	I haven't touched the functionality of
	libxslt_xsltRegisterExtModuleFunction but I saw somewhere you
	mentioned there was still a bug.  If you're seeing segfaults then
	refcount bugs could be coming from your argument creation.

* Super minor cleanup

	I removed some unreferenced variables and initialized some pointers.

	Fixed the bug found also in the libxml2 python wrapper regarding
	PyFile checking.

* New python api declaration + generate.py

	I get some strange behavior when running generate.py.  I haven't
	debugged the generation process, but these methods appear in my
	class list during generation which don't show up in the 1.0.30
	libxsltclass.txt distribution.  Is it related to my modification
	of libxslt-python-api.xml?

	I get around this by deleting the following lines from my
	libxsltclass.txt file before making the python module.

		# functions from module transform
		applyImports()
		applyStripSpaces()
		applyTemplates()
		attribute()
		callTemplate()
		choose()
		comment()
		copy()
		copyOf()
		documentElem()
		element()
		forEach()
		freeTransformContext()
		if()
		number()
		processingInstruction()
		registerAllElement()
		sort()
		text()
		valueOf()

	The work around I mention is not included in the diff, but thought
	I'd bring the behavior to your attention.

	I'm not depending on the naming scheme I chose.  Please edit it to
	follow your naming scheme.

	Also, I think it's a bit ugly that one has to "cast" the incoming
	PyCObjects to usable ones (ctxt to transformCtxt).  This should be
	done in the wrapper.  

Now to putting this into use!  

It's fairly straightforward.  The following python code will show the
order of extension class and element compile/transform:

####################
#!/usr/bin/env python 
import sys
import libxml2
import libxslt

BOUND_URI = 'http://example.com/bound'
UNBOUND_URI = 'http://example.com/unbound'
ELEM = 'test'

def test_compile(stylesheet, instruction, transform_method):
	print "### UNBOUND COMPILE"

def test_transform(context, node, instruction, styleCompile):
	print "### UNBOUND TRANSFORM"

class ext_class(libxslt.extensionModule):
	def styleInit(self, *args):
		print "styleInit"
		libxslt.registerExtModuleElement(ELEM, 
			BOUND_URI, self.ext_compile, self.ext_transform)

	def ctxtInit(self, *args):
		print 'ctxtInit'
		
	def ext_compile(self, style, inst, func):
		print "### BOUND COMPILE", func == self.ext_transform

	def ext_transform(self, ctx, node, instruction, comp):
		print "### BOUND TRANSFORM"
		tctx = libxslt.transformCtxt(_obj=ctx)
		tctx.insertNode().addContent('-- SUCCESS --')


styledoc = libxml2.parseDoc("""
<xsl:stylesheet version='1.0'
  xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
  xmlns:bound='http://example.com/bound'
  xmlns:unbound='http://example.com/unbound'
  xsl:extension-element-prefixes='bound unbound'>

  <xsl:template match='/'>
	<article><bound:test/></article>
	<unbound:test/>
  </xsl:template>
</xsl:stylesheet>
""")

libxslt.registerExtensionClass(BOUND_URI, ext_class())
libxslt.registerExtModuleElement(ELEM, 
	UNBOUND_URI, test_compile, test_transform)

print "parse SS"
style = libxslt.parseStylesheetDoc(styledoc)
xmldoc = libxml2.parseDoc("""<doc/>""")
print "apply SS"
res = style.applyStylesheet(xmldoc, {})
res.dump(sys.stdout)

style.freeStylesheet()
xmldoc.freeDoc()

####################

Which outputs the following:

parse SS
styleInit
### BOUND COMPILE 1
### UNBOUND COMPILE
apply SS
ctxtInit
### BOUND TRANSFORM
### UNBOUND TRANSFORM
<?xml version="1.0"?>
<article>-- SUCCESS --</article>

####################

However, I've made a little test case with nested extension elements.
Obviously, only my outer element gets transformed first because it
doesn't continue the processing of its elements.  What do I need to
call to process the contents of the extension element before actually
doing the custom processing? 


-Sean


extelem-libxslt-1.0.30.diff.gz



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