Skip to content
Snippets Groups Projects
Commit 034948f3afab authored by Daniel Veillard's avatar Daniel Veillard
Browse files

That part was complex actually:

- libxslt/transform.c: modified apply-templates processing
  added select and sort support support.
Daniel
parent 866a0e5dc96f
No related branches found
No related tags found
No related merge requests found
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 :-(
......
......@@ -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,5 +633,41 @@
#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 {
......@@ -487,3 +673,39 @@
} 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;
}
......@@ -489,4 +711,55 @@
}
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,4 +1099,5 @@
void
xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) {
xsltTemplatePtr template;
template = xsltGetTemplate(ctxt->style, node);
......@@ -964,5 +1103,4 @@
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;
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment