# HG changeset patch # User Daniel Veillard <veillard@src.gnome.org> # Date 979759032 0 # Wed Jan 17 19:17:12 2001 +0000 # Node ID 034948f3afab893ea8d5a2017a2e87ef10f3a97b # Parent 866a0e5dc96fa6bf58332592795aa7d782b00b7d That part was complex actually: - libxslt/transform.c: modified apply-templates processing added select and sort support support. Daniel diff --git a/ChangeLog b/ChangeLog --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Wed Jan 17 20:15:40 CET 2001 + + * libxslt/transform.c: modified apply-templates processing + added select and sort support support. + Wed Jan 17 17:45:20 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr> * TODO: guess what, it's growing :-( diff --git a/libxslt/transform.c b/libxslt/transform.c --- a/libxslt/transform.c +++ b/libxslt/transform.c @@ -120,6 +120,141 @@ void xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst); /** + * xsltSort: + * @ctxt: a XSLT process context + * @node: the node in the source tree. + * @inst: the xslt sort node + * + * Process the xslt sort node on the source node + */ +void +xsltSort(xsltTransformContextPtr ctxt, xmlNodePtr node, + xmlNodePtr inst) { + xmlXPathObjectPtr *results = NULL; + xmlNodeSetPtr list = NULL; + xmlXPathParserContextPtr xpathParserCtxt = NULL; + xmlChar *prop; + xmlXPathObjectPtr res, tmp; + const xmlChar *start; + int descending = 0; + int number = 0; + int len; + int i; + + if ((ctxt == NULL) || (node == NULL) || (inst == NULL)) + return; + + list = ctxt->nodeList; + if ((list == NULL) || (list->nodeNr <= 1)) + goto error; /* nothing to do */ + + len = list->nodeNr; + + /* TODO: process attributes as attribute value templates */ + prop = xmlGetNsProp(inst, (const xmlChar *)"data-type", XSLT_NAMESPACE); + if (prop != NULL) { + if (xmlStrEqual(prop, (const xmlChar *) "text")) + number = 0; + else if (xmlStrEqual(prop, (const xmlChar *) "number")) + number = 1; + else { + xsltGenericError(xsltGenericErrorContext, + "xsltSort: no support for data-type = %s\n", prop); + goto error; + } + xmlFree(prop); + } + prop = xmlGetNsProp(inst, (const xmlChar *)"order", XSLT_NAMESPACE); + if (prop != NULL) { + if (xmlStrEqual(prop, (const xmlChar *) "ascending")) + descending = 0; + else if (xmlStrEqual(prop, (const xmlChar *) "descending")) + descending = 1; + else { + xsltGenericError(xsltGenericErrorContext, + "xsltSort: invalid value %s for order\n", prop); + goto error; + } + xmlFree(prop); + } + /* TODO: xsl:sort lang attribute */ + /* TODO: xsl:sort case-order attribute */ + + prop = xmlGetNsProp(inst, (const xmlChar *)"select", XSLT_NAMESPACE); + if (prop == NULL) { + xsltGenericError(xsltGenericErrorContext, + "xsltSort: select is not defined\n"); + return; + } + + xpathParserCtxt = xmlXPathNewParserContext(prop, ctxt->xpathCtxt); + if (xpathParserCtxt == NULL) + goto error; + results = xmlMalloc(len * sizeof(xmlXPathObjectPtr)); + if (results == NULL) { + xsltGenericError(xsltGenericErrorContext, + "xsltSort: memory allocation failure\n"); + goto error; + } + + start = xpathParserCtxt->cur; + for (i = 0;i < len;i++) { + xpathParserCtxt->cur = start; + node = ctxt->node = list->nodeTab[i]; + ctxt->xpathCtxt->proximityPosition = i + 1; + valuePush(xpathParserCtxt, xmlXPathNewNodeSet(node)); + xmlXPathEvalExpr(xpathParserCtxt); + xmlXPathStringFunction(xpathParserCtxt, 1); + if (number) + xmlXPathNumberFunction(xpathParserCtxt, 1); + res = valuePop(xpathParserCtxt); + do { + tmp = valuePop(xpathParserCtxt); + if (tmp != NULL) { + xmlXPathFreeObject(tmp); + } + } while (tmp != NULL); + + if (res != NULL) { + if (number) { + if (res->type == XPATH_NUMBER) { + results[i] = res; + } else { +#ifdef DEBUG_PROCESS + xsltGenericDebug(xsltGenericDebugContext, + "xsltSort: select didn't evaluate to a number\n"); +#endif + results[i] = NULL; + } + } else { + if (res->type == XPATH_STRING) { + results[i] = res; + } else { +#ifdef DEBUG_PROCESS + xsltGenericDebug(xsltGenericDebugContext, + "xsltSort: select didn't evaluate to a string\n"); +#endif + results[i] = NULL; + } + } + } + } + + xsltSortFunction(list, &results[0], descending, number); + +error: + if (xpathParserCtxt != NULL) + xmlXPathFreeParserContext(xpathParserCtxt); + if (prop != NULL) + xmlFree(prop); + if (results != NULL) { + for (i = 0;i < len;i++) + xmlXPathFreeObject(results[i]); + xmlFree(results); + } +} + +/** * xsltAttribute: * @ctxt: a XSLT process context * @node: the node in the source tree. @@ -403,6 +538,15 @@ case XML_HTML_DOCUMENT_NODE: case XML_ELEMENT_NODE: break; + case XML_TEXT_NODE: + copy = xmlCopyNode(node, 0); + if (copy != NULL) { + xmlAddChild(ctxt->insert, copy); + } else { + xsltGenericError(xsltGenericErrorContext, + "xsltDefaultProcessOneNode: text copy failed\n"); + } + return; default: return; } @@ -472,7 +616,13 @@ void xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst) { - xmlChar *prop; + xmlChar *prop = NULL; + xmlNodePtr cur, delete = NULL; + xmlXPathObjectPtr res = NULL, tmp; + xmlNodePtr replacement; + xmlNodeSetPtr list = NULL, oldlist; + xmlXPathParserContextPtr xpathParserCtxt = NULL; + int i, oldProximityPosition, oldContextSize; if ((ctxt == NULL) || (node == NULL) || (inst == NULL)) return; @@ -483,10 +633,133 @@ #endif prop = xmlGetNsProp(inst, (const xmlChar *)"select", XSLT_NAMESPACE); if (prop != NULL) { - TODO +#ifdef DEBUG_PROCESS + xsltGenericDebug(xsltGenericDebugContext, + "xsltApplyTemplates: select %s\n", prop); +#endif + + if (ctxt->xpathCtxt == NULL) { + xmlXPathInit(); + ctxt->xpathCtxt = xmlXPathNewContext(ctxt->doc); + if (ctxt->xpathCtxt == NULL) + goto error; + } + xpathParserCtxt = + xmlXPathNewParserContext(prop, ctxt->xpathCtxt); + if (xpathParserCtxt == NULL) + goto error; + ctxt->xpathCtxt->node = node; + valuePush(xpathParserCtxt, xmlXPathNewNodeSet(node)); + xmlXPathEvalExpr(xpathParserCtxt); + res = valuePop(xpathParserCtxt); + do { + tmp = valuePop(xpathParserCtxt); + if (tmp != NULL) { + xmlXPathFreeObject(tmp); + } + } while (tmp != NULL); + if (res != NULL) { + if (res->type == XPATH_NODESET) { + list = res->nodesetval; + res->nodesetval = NULL; + } else { +#ifdef DEBUG_PROCESS + xsltGenericDebug(xsltGenericDebugContext, + "xsltApplyTemplates: select didn't evaluate to a node list\n"); +#endif + goto error; + } + } } else { - xsltDefaultProcessOneNode(ctxt, node); + /* + * Build an XPath nodelist with the children + */ + list = xmlXPathNodeSetCreate(NULL); + cur = node->children; + while (cur != NULL) { + switch (cur->type) { + case XML_TEXT_NODE: + /* TODO: check the whitespace stripping rules ! */ + if ((IS_BLANK_NODE(cur)) && + (cur->parent != NULL) && + (ctxt->style->stripSpaces != NULL)) { + const xmlChar *val; + + val = (const xmlChar *) + xmlHashLookup(ctxt->style->stripSpaces, + cur->parent->name); + if ((val != NULL) && + (xmlStrEqual(val, (xmlChar *) "strip"))) { + delete = cur; + break; + } + } + /* no break on purpose */ + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + case XML_ELEMENT_NODE: + case XML_CDATA_SECTION_NODE: + xmlXPathNodeSetAdd(list, cur); + break; + default: +#ifdef DEBUG_PROCESS + xsltGenericDebug(xsltGenericDebugContext, + "xsltApplyTemplates: skipping cur type %d\n", + cur->type); +#endif + delete = cur; + } + cur = cur->next; + if (delete != NULL) { +#ifdef DEBUG_PROCESS + xsltGenericDebug(xsltGenericDebugContext, + "xsltApplyTemplates: removing ignorable blank cur\n"); +#endif + xmlUnlinkNode(delete); + xmlFreeNode(delete); + delete = NULL; + } + } } + +#ifdef DEBUG_PROCESS + xsltGenericDebug(xsltGenericDebugContext, + "xsltApplyTemplates: list of %d nodes\n", list->nodeNr); +#endif + + oldlist = ctxt->nodeList; + ctxt->nodeList = list; + oldContextSize = ctxt->xpathCtxt->contextSize; + oldProximityPosition = ctxt->xpathCtxt->proximityPosition; + ctxt->xpathCtxt->contextSize = list->nodeNr; + + /* + * handle and skip the xsl:sort + */ + replacement = inst->children; + while (IS_XSLT_ELEM(replacement) && (IS_XSLT_NAME(replacement, "sort"))) { + xsltSort(ctxt, node, replacement); + replacement = replacement->next; + } + + for (i = 0;i < list->nodeNr;i++) { + ctxt->node = list->nodeTab[i]; + ctxt->xpathCtxt->proximityPosition = i + 1; + xsltProcessOneNode(ctxt, list->nodeTab[i]); + } + ctxt->nodeList = oldlist; + ctxt->xpathCtxt->contextSize = oldContextSize; + ctxt->xpathCtxt->proximityPosition = oldProximityPosition; + +error: + if (xpathParserCtxt != NULL) + xmlXPathFreeParserContext(xpathParserCtxt); + if (prop != NULL) + xmlFree(prop); + if (res != NULL) + xmlXPathFreeObject(res); + if (list != NULL) + xmlXPathFreeNodeSet(list); } /** @@ -715,141 +988,6 @@ } /** - * xsltSort: - * @ctxt: a XSLT process context - * @node: the node in the source tree. - * @inst: the xslt sort node - * - * Process the xslt sort node on the source node - */ -void -xsltSort(xsltTransformContextPtr ctxt, xmlNodePtr node, - xmlNodePtr inst) { - xmlXPathObjectPtr *results = NULL; - xmlNodeSetPtr list = NULL; - xmlXPathParserContextPtr xpathParserCtxt = NULL; - xmlChar *prop; - xmlXPathObjectPtr res, tmp; - const xmlChar *start; - int descending = 0; - int number = 0; - int len; - int i; - - if ((ctxt == NULL) || (node == NULL) || (inst == NULL)) - return; - - list = ctxt->nodeList; - if ((list == NULL) || (list->nodeNr <= 1)) - goto error; /* nothing to do */ - - len = list->nodeNr; - - prop = xmlGetNsProp(inst, (const xmlChar *)"data-type", XSLT_NAMESPACE); - if (prop != NULL) { - if (xmlStrEqual(prop, (const xmlChar *) "text")) - number = 0; - else if (xmlStrEqual(prop, (const xmlChar *) "number")) - number = 1; - else { - xsltGenericError(xsltGenericErrorContext, - "xsltSort: no support for data-type = %s\n", prop); - goto error; - } - xmlFree(prop); - } - prop = xmlGetNsProp(inst, (const xmlChar *)"order", XSLT_NAMESPACE); - if (prop != NULL) { - if (xmlStrEqual(prop, (const xmlChar *) "ascending")) - descending = 0; - else if (xmlStrEqual(prop, (const xmlChar *) "descending")) - descending = 1; - else { - xsltGenericError(xsltGenericErrorContext, - "xsltSort: invalid value %s for order\n", prop); - goto error; - } - xmlFree(prop); - } - /* TODO: xsl:sort lang attribute */ - /* TODO: xsl:sort order attribute */ - /* TODO: xsl:sort case-order attribute */ - - prop = xmlGetNsProp(inst, (const xmlChar *)"select", XSLT_NAMESPACE); - if (prop == NULL) { - xsltGenericError(xsltGenericErrorContext, - "xsltSort: select is not defined\n"); - return; - } - - xpathParserCtxt = xmlXPathNewParserContext(prop, ctxt->xpathCtxt); - if (xpathParserCtxt == NULL) - goto error; - results = xmlMalloc(len * sizeof(xmlXPathObjectPtr)); - if (results == NULL) { - xsltGenericError(xsltGenericErrorContext, - "xsltSort: memory allocation failure\n"); - goto error; - } - - start = xpathParserCtxt->cur; - for (i = 0;i < len;i++) { - xpathParserCtxt->cur = start; - node = ctxt->node = list->nodeTab[i]; - ctxt->xpathCtxt->proximityPosition = i + 1; - valuePush(xpathParserCtxt, xmlXPathNewNodeSet(node)); - xmlXPathEvalExpr(xpathParserCtxt); - xmlXPathStringFunction(xpathParserCtxt, 1); - if (number) - xmlXPathNumberFunction(xpathParserCtxt, 1); - res = valuePop(xpathParserCtxt); - do { - tmp = valuePop(xpathParserCtxt); - if (tmp != NULL) { - xmlXPathFreeObject(tmp); - } - } while (tmp != NULL); - - if (res != NULL) { - if (number) { - if (res->type == XPATH_NUMBER) { - results[i] = res; - } else { -#ifdef DEBUG_PROCESS - xsltGenericDebug(xsltGenericDebugContext, - "xsltSort: select didn't evaluate to a number\n"); -#endif - results[i] = NULL; - } - } else { - if (res->type == XPATH_STRING) { - results[i] = res; - } else { -#ifdef DEBUG_PROCESS - xsltGenericDebug(xsltGenericDebugContext, - "xsltSort: select didn't evaluate to a string\n"); -#endif - results[i] = NULL; - } - } - } - } - - xsltSortFunction(list, &results[0], descending, number); - -error: - if (xpathParserCtxt != NULL) - xmlXPathFreeParserContext(xpathParserCtxt); - if (prop != NULL) - xmlFree(prop); - if (results != NULL) { - for (i = 0;i < len;i++) - xmlXPathFreeObject(results[i]); - xmlFree(results); - } -} - -/** * xsltForEach: * @ctxt: a XSLT process context * @node: the node in the source tree. @@ -961,8 +1099,8 @@ void xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) { xsltTemplatePtr template; + template = xsltGetTemplate(ctxt->style, node); - /* * If no template is found, apply the default rule. */ @@ -975,7 +1113,6 @@ xsltGenericDebug(xsltGenericDebugContext, "xsltProcessOneNode: no template found for %s\n", node->name); #endif - xsltDefaultProcessOneNode(ctxt, node); return; }