1 #!/usr/bin/env python 2 3 """ 4 XSL-based form templating. 5 """ 6 7 import Constants 8 import libxslt 9 10 """ 11 import libxml2 12 13 def quiet(context, s): 14 pass 15 16 libxml2.registerErrorHandler(quiet, None) 17 """ 18 19 def path_to_node(node, attribute_ref, name): 20 21 """ 22 Generate an XSLForms path to the given 'node', producing an attribute 23 reference if 'attribute_ref' is true; for example: 24 25 /package#1/discriminators#5/discriminator#1/category 26 27 Otherwise an element reference is produced; for example: 28 29 /package#1/discriminators#5/discriminator#1 30 31 Use the given 'name' to complete the path if an attribute reference is 32 required (and if a genuine attribute is found at the context node - 33 otherwise 'name' will be None and the context node will be treated like an 34 attribute). 35 """ 36 37 l = [] 38 # Skip attribute reference. 39 if node.type == "attribute": 40 node = node.parent 41 # Manually insert the attribute name if defined. 42 if attribute_ref: 43 if name is not None: 44 l.insert(0, name) 45 l.insert(0, Constants.path_separator) 46 else: 47 l.insert(0, node.name) 48 l.insert(0, Constants.path_separator) 49 node = node.parent 50 # Element references. 51 while node is not None and node.type != "document_xml": 52 l.insert(0, str(int(node.xpathEval("count(preceding-sibling::*) + 1")))) 53 l.insert(0, Constants.pair_separator) 54 l.insert(0, node.name) 55 l.insert(0, Constants.path_separator) 56 node = node.parent 57 return "".join(l) 58 59 def path_to_context(context, attribute_ref): 60 61 """ 62 As a libxslt extension function, return a string containing the XSLForms 63 path to the 'context' node, using the special "this-name" variable to 64 complete the path if an attribute reference is required (as indicated by 65 'attribute_ref' being set to true). 66 """ 67 68 pctxt = libxslt.xpathParserContext(_obj=context) 69 context = pctxt.context() 70 node = context.contextNode() 71 transform_context = context.transformContext() 72 name_var = transform_context.variableLookup("this-name", None) 73 if name_var is not None: 74 name = name_var[0].content 75 else: 76 name = None 77 return path_to_node(node, attribute_ref, name) 78 79 def this_position(context): 80 return path_to_context(context, 0) 81 82 def field_name(context): 83 return path_to_context(context, 1) 84 85 libxslt.registerExtModuleFunction("this-position", "http://www.boddie.org.uk/ns/xmltools/template", this_position) 86 libxslt.registerExtModuleFunction("field-name", "http://www.boddie.org.uk/ns/xmltools/template", field_name) 87 88 # vim: tabstop=4 expandtab shiftwidth=4