[xslt] implementation of dyn:map



Here's an implementation of {http://exslt.org/dynamic}map for libexslt.  It
seems like a goofy extension but can be very useful, as in when working with
multiple documents where the key() limited me.

The attached samples are really silly and not a good test but shows it works at
least.
Index: dynamic.c
===================================================================
RCS file: /cvs/gnome/libxslt/libexslt/dynamic.c,v
retrieving revision 1.3
diff -c -r1.3 dynamic.c
*** dynamic.c	18 Aug 2003 22:41:05 -0000	1.3
--- dynamic.c	8 Jul 2005 17:51:03 -0000
***************
*** 84,89 ****
--- 84,229 ----
  }
  
  /**
+  * exsltDynMapFunction:
+  * @ctxt:  an XPath parser context
+  * @nargs:  the number of arguments
+  *
+  * Evaluates the string as an XPath expression and returns the result
+  * value, which may be a boolean, number, string, node set, result tree
+  * fragment or external object.
+  */
+ 
+ static void
+ exsltDynMapFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+ 	xmlChar *str = NULL;
+ 	xmlNodeSetPtr nodeset = NULL;
+ 	xmlXPathCompExprPtr comp = NULL;
+ 	xmlXPathObjectPtr ret = NULL;
+ 	xmlDocPtr oldDoc, container;
+ 	xmlNodePtr oldNode; 
+ 	int oldContextSize;
+ 	int oldProximityPosition;
+ 	int i, j;
+ 
+ 
+     if (nargs != 2) {
+ 		xmlXPathSetArityError(ctxt);
+ 		return;
+     }
+ 	str = xmlXPathPopString(ctxt);
+     if (xmlXPathCheckError(ctxt)) {
+ 		xmlXPathSetTypeError(ctxt);
+ 		return;
+     }
+ 
+     nodeset = xmlXPathPopNodeSet(ctxt);
+     if (xmlXPathCheckError(ctxt)) {
+ 		xmlXPathSetTypeError(ctxt);
+ 		return;
+     }
+ 	if (str == NULL || !xmlStrlen(str) || !(comp = xmlXPathCompile(str))) {
+ 		if (nodeset != NULL)
+ 			xmlXPathFreeNodeSet(nodeset);
+ 		if (str != NULL)
+ 			xmlFree(str);
+ 		valuePush(ctxt, xmlXPathNewNodeSet(NULL));
+ 		return;
+ 	}
+ 
+ 	ret = xmlXPathNewNodeSet(NULL);
+ 	if (ret == NULL) {
+   		xsltGenericError(xsltGenericErrorContext,
+ 			 "exsltDynMapFunctoin: ret == NULL\n");
+ 		goto cleanup;
+ 	}
+ 
+ 	oldDoc = ctxt->context->doc;
+ 	oldNode = ctxt->context->node;
+ 	oldContextSize = ctxt->context->contextSize;
+ 	oldProximityPosition = ctxt->context->proximityPosition;
+ 
+ 	/** 
+ 	 * since we really don't know we're going to be adding node(s) 
+ 	 * down the road we create the RVT regardless 
+ 	 */
+     container = xsltCreateRVT(xsltXPathGetTransformContext(ctxt));
+     if (container != NULL) 
+         xsltRegisterTmpRVT(xsltXPathGetTransformContext(ctxt), container);
+ 
+ 	if (nodeset && nodeset->nodeNr > 0 ) {
+ 		xmlXPathNodeSetSort(nodeset);
+ 		ctxt->context->contextSize = nodeset->nodeNr;
+ 		ctxt->context->proximityPosition = 0;
+ 		for (i = 0; i < nodeset->nodeNr; i++) {
+ 			xmlXPathObjectPtr subResult = NULL;
+ 			ctxt->context->proximityPosition++;
+ 			ctxt->context->node = nodeset->nodeTab[i];
+ 			ctxt->context->doc = nodeset->nodeTab[i]->doc;
+ 
+ 			subResult = xmlXPathCompiledEval(comp, ctxt->context);
+ 			if (subResult != NULL) {
+ 				switch (subResult->type) {
+ 					case XPATH_NODESET:
+ 						if (subResult->nodesetval != NULL)
+ 							for (j = 0; j < subResult->nodesetval->nodeNr; j++)
+ 								xmlXPathNodeSetAdd(ret->nodesetval, subResult->nodesetval->nodeTab[j]);
+ 						break;
+ 					case XPATH_BOOLEAN:
+ 						if (container != NULL) {
+ 							xmlNodePtr cur = xmlNewChild((xmlNodePtr) container, NULL, BAD_CAST "boolean", BAD_CAST subResult->boolval ? "true" : "");
+ 							if (cur != NULL)  {
+ 								cur->ns = xmlNewNs(cur, BAD_CAST "http://exslt.org/common";, BAD_CAST "exsl");
+ 								xmlXPathNodeSetAddUnique(ret->nodesetval, cur);
+ 							}
+ 						}
+ 						break;
+ 					case XPATH_NUMBER:
+ 						if (container != NULL) {
+ 							xmlChar *val = xmlXPathCastNumberToString(subResult->floatval);
+ 							xmlNodePtr cur = xmlNewChild((xmlNodePtr) container, NULL, BAD_CAST "number", val);
+ 							if (val != NULL)
+ 								xmlFree(val);
+ 
+ 							if (cur != NULL)  {
+ 								cur->ns = xmlNewNs(cur, BAD_CAST "http://exslt.org/common";, BAD_CAST "exsl");
+ 								xmlXPathNodeSetAddUnique(ret->nodesetval, cur);
+ 							}
+ 						}
+ 						break;
+ 					case XPATH_STRING:
+ 						if (container != NULL) {
+ 							xmlNodePtr cur = xmlNewChild((xmlNodePtr) container, NULL, BAD_CAST "string", subResult->stringval);
+ 							if (cur != NULL)  {
+ 								cur->ns = xmlNewNs(cur, BAD_CAST "http://exslt.org/common";, BAD_CAST "exsl");
+ 								xmlXPathNodeSetAddUnique(ret->nodesetval, cur);
+ 							}
+ 						}
+ 						break;
+ 				}
+ 				xmlXPathFreeObject(subResult);
+ 			}
+ 		}
+ 	}
+ 	ctxt->context->doc = oldDoc;
+ 	ctxt->context->node = oldNode;
+ 	ctxt->context->contextSize = oldContextSize;
+ 	ctxt->context->proximityPosition = oldProximityPosition;
+ 
+ 
+ cleanup:
+ 	/* restore the xpath context */
+ 	if (comp != NULL)
+ 		xmlXPathFreeCompExpr(comp);
+ 	if (nodeset != NULL)
+ 		xmlXPathFreeNodeSet(nodeset);
+ 	if (str != NULL)
+ 		xmlFree(str);
+ 	valuePush(ctxt, ret);
+ 	return;
+ }
+ 
+ 
+ /**
   * exsltDynRegister:
   *
   * Registers the EXSLT - Dynamic module
***************
*** 94,97 ****
--- 234,241 ----
      xsltRegisterExtModuleFunction ((const xmlChar *) "evaluate",
  				   EXSLT_DYNAMIC_NAMESPACE,
  				   exsltDynEvaluateFunction);
+   xsltRegisterExtModuleFunction ((const xmlChar *) "map",
+ 				   EXSLT_DYNAMIC_NAMESPACE,
+ 				   exsltDynMapFunction);
+ 
  }
<dynmap>
 <with-child>
  <childNode1>aaa</childNode1>
  <childNode2>bbbb</childNode2>
  <childNode3>ccc</childNode3>
  <childNode4>dddd</childNode4>
  <childNode5>eee</childNode5>
  <childNode6>ffff</childNode6>
  <childNode7>ggg</childNode7>
  <childNode8>hhhh</childNode8>
  <childNode9>iii</childNode9>
 </with-child>
 <without-child>some text</without-child>
 <without-child>some text</without-child>
 <without-child>some text</without-child>
 <without-child>some text</without-child>
 <without-child>some text</without-child>
 <with-child>
  <childNode1>jjjj</childNode1>
  <childNode2>kkk</childNode2>
  <childNode3>llll</childNode3>
  <childNode4>mmm</childNode4>
  <childNode5>nnnn</childNode5>
  <childNode6>ooo</childNode6>
  <childNode7>pppp</childNode7>
  <childNode8>qqq</childNode8>
  <childNode9>rrrr</childNode9>
 </with-child>
</dynmap>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="1.0"
 xmlns:dyn="http://exslt.org/dynamic";
 exclude-result-prefixes="dyn"
>
<xsl:output indent="yes"/>

<xsl:template match="/dynmap">
<result>
 <node-set>
  <xsl:copy-of select="dyn:map(*, 'child::*[string-length(.) &gt; 3]')"/>
 </node-set> 
 <boolean>
  <xsl:copy-of select="dyn:map(*, 'string-length(name()) &gt; 3')"/>
 </boolean>
 <number>
  <xsl:copy-of select="dyn:map(*, 'count(*)')"/>
 </number>
 <string>
  <xsl:copy-of select="dyn:map(*, 'name()')"/>
 </string>  
</result> 
</xsl:template>
</xsl:stylesheet>



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