[xslt] implementation of dyn:map
- From: Mark Vakoc <thevakoc-xml yahoo com>
- To: xslt gnome org
- Subject: [xslt] implementation of dyn:map
- Date: Fri, 8 Jul 2005 10:54:54 -0700 (PDT)
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(.) > 3]')"/>
</node-set>
<boolean>
<xsl:copy-of select="dyn:map(*, 'string-length(name()) > 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]