xslt: Import upstream release 1.1.38.
[wine.git] / libs / xslt / libxslt / keys.c
blobf23cc4e9fca9d301d37b887c24d072ec642e0127
1 /*
2 * keys.c: Implemetation of the keys support
4 * Reference:
5 * http://www.w3.org/TR/1999/REC-xslt-19991116
7 * See Copyright for the status of this software.
9 * daniel@veillard.com
12 #define IN_LIBXSLT
13 #include "libxslt.h"
15 #include <string.h>
17 #include <libxml/xmlmemory.h>
18 #include <libxml/tree.h>
19 #include <libxml/valid.h>
20 #include <libxml/hash.h>
21 #include <libxml/xmlerror.h>
22 #include <libxml/parserInternals.h>
23 #include <libxml/xpathInternals.h>
24 #include <libxml/xpath.h>
25 #include "xslt.h"
26 #include "xsltInternals.h"
27 #include "xsltutils.h"
28 #include "imports.h"
29 #include "templates.h"
30 #include "keys.h"
32 #ifdef WITH_XSLT_DEBUG
33 #define WITH_XSLT_DEBUG_KEYS
34 #endif
36 static int
37 xsltInitDocKeyTable(xsltTransformContextPtr ctxt, const xmlChar *name,
38 const xmlChar *nameURI);
40 /************************************************************************
41 * *
42 * Type functions *
43 * *
44 ************************************************************************/
46 /**
47 * xsltNewKeyDef:
48 * @name: the key name or NULL
49 * @nameURI: the name URI or NULL
51 * Create a new XSLT KeyDef
53 * Returns the newly allocated xsltKeyDefPtr or NULL in case of error
55 static xsltKeyDefPtr
56 xsltNewKeyDef(const xmlChar *name, const xmlChar *nameURI) {
57 xsltKeyDefPtr cur;
59 cur = (xsltKeyDefPtr) xmlMalloc(sizeof(xsltKeyDef));
60 if (cur == NULL) {
61 xsltTransformError(NULL, NULL, NULL,
62 "xsltNewKeyDef : malloc failed\n");
63 return(NULL);
65 memset(cur, 0, sizeof(xsltKeyDef));
66 if (name != NULL)
67 cur->name = xmlStrdup(name);
68 if (nameURI != NULL)
69 cur->nameURI = xmlStrdup(nameURI);
70 cur->nsList = NULL;
71 return(cur);
74 /**
75 * xsltFreeKeyDef:
76 * @keyd: an XSLT key definition
78 * Free up the memory allocated by @keyd
80 static void
81 xsltFreeKeyDef(xsltKeyDefPtr keyd) {
82 if (keyd == NULL)
83 return;
84 if (keyd->comp != NULL)
85 xmlXPathFreeCompExpr(keyd->comp);
86 if (keyd->usecomp != NULL)
87 xmlXPathFreeCompExpr(keyd->usecomp);
88 if (keyd->name != NULL)
89 xmlFree(keyd->name);
90 if (keyd->nameURI != NULL)
91 xmlFree(keyd->nameURI);
92 if (keyd->match != NULL)
93 xmlFree(keyd->match);
94 if (keyd->use != NULL)
95 xmlFree(keyd->use);
96 if (keyd->nsList != NULL)
97 xmlFree(keyd->nsList);
98 memset(keyd, -1, sizeof(xsltKeyDef));
99 xmlFree(keyd);
103 * xsltFreeKeyDefList:
104 * @keyd: an XSLT key definition list
106 * Free up the memory allocated by all the elements of @keyd
108 static void
109 xsltFreeKeyDefList(xsltKeyDefPtr keyd) {
110 xsltKeyDefPtr cur;
112 while (keyd != NULL) {
113 cur = keyd;
114 keyd = keyd->next;
115 xsltFreeKeyDef(cur);
120 * xsltNewKeyTable:
121 * @name: the key name or NULL
122 * @nameURI: the name URI or NULL
124 * Create a new XSLT KeyTable
126 * Returns the newly allocated xsltKeyTablePtr or NULL in case of error
128 static xsltKeyTablePtr
129 xsltNewKeyTable(const xmlChar *name, const xmlChar *nameURI) {
130 xsltKeyTablePtr cur;
132 cur = (xsltKeyTablePtr) xmlMalloc(sizeof(xsltKeyTable));
133 if (cur == NULL) {
134 xsltTransformError(NULL, NULL, NULL,
135 "xsltNewKeyTable : malloc failed\n");
136 return(NULL);
138 memset(cur, 0, sizeof(xsltKeyTable));
139 if (name != NULL)
140 cur->name = xmlStrdup(name);
141 if (nameURI != NULL)
142 cur->nameURI = xmlStrdup(nameURI);
143 cur->keys = xmlHashCreate(0);
144 return(cur);
147 static void
148 xsltFreeNodeSetEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
149 xmlXPathFreeNodeSet((xmlNodeSetPtr) payload);
153 * xsltFreeKeyTable:
154 * @keyt: an XSLT key table
156 * Free up the memory allocated by @keyt
158 static void
159 xsltFreeKeyTable(xsltKeyTablePtr keyt) {
160 if (keyt == NULL)
161 return;
162 if (keyt->name != NULL)
163 xmlFree(keyt->name);
164 if (keyt->nameURI != NULL)
165 xmlFree(keyt->nameURI);
166 if (keyt->keys != NULL)
167 xmlHashFree(keyt->keys, xsltFreeNodeSetEntry);
168 memset(keyt, -1, sizeof(xsltKeyTable));
169 xmlFree(keyt);
173 * xsltFreeKeyTableList:
174 * @keyt: an XSLT key table list
176 * Free up the memory allocated by all the elements of @keyt
178 static void
179 xsltFreeKeyTableList(xsltKeyTablePtr keyt) {
180 xsltKeyTablePtr cur;
182 while (keyt != NULL) {
183 cur = keyt;
184 keyt = keyt->next;
185 xsltFreeKeyTable(cur);
189 /************************************************************************
191 * The interpreter for the precompiled patterns *
193 ************************************************************************/
197 * xsltFreeKeys:
198 * @style: an XSLT stylesheet
200 * Free up the memory used by XSLT keys in a stylesheet
202 void
203 xsltFreeKeys(xsltStylesheetPtr style) {
204 if (style->keys)
205 xsltFreeKeyDefList((xsltKeyDefPtr) style->keys);
209 * skipString:
210 * @cur: the current pointer
211 * @end: the current offset
213 * skip a string delimited by " or '
215 * Returns the byte after the string or -1 in case of error
217 static int
218 skipString(const xmlChar *cur, int end) {
219 xmlChar limit;
221 if ((cur == NULL) || (end < 0)) return(-1);
222 if ((cur[end] == '\'') || (cur[end] == '"')) limit = cur[end];
223 else return(end);
224 end++;
225 while (cur[end] != 0) {
226 if (cur[end] == limit)
227 return(end + 1);
228 end++;
230 return(-1);
234 * skipPredicate:
235 * @cur: the current pointer
236 * @end: the current offset
238 * skip a predicate
240 * Returns the byte after the predicate or -1 in case of error
242 static int
243 skipPredicate(const xmlChar *cur, int end) {
244 int level = 0;
246 if ((cur == NULL) || (end < 0)) return(-1);
247 if (cur[end] != '[') return(end);
248 end++;
249 while (cur[end] != 0) {
250 if ((cur[end] == '\'') || (cur[end] == '"')) {
251 end = skipString(cur, end);
252 if (end <= 0)
253 return(-1);
254 continue;
255 } else if (cur[end] == '[') {
256 level += 1;
257 } else if (cur[end] == ']') {
258 if (level == 0)
259 return(end + 1);
260 level -= 1;
262 end++;
264 return(-1);
268 * xsltAddKey:
269 * @style: an XSLT stylesheet
270 * @name: the key name or NULL
271 * @nameURI: the name URI or NULL
272 * @match: the match value
273 * @use: the use value
274 * @inst: the key instruction
276 * add a key definition to a stylesheet
278 * Returns 0 in case of success, and -1 in case of failure.
281 xsltAddKey(xsltStylesheetPtr style, const xmlChar *name,
282 const xmlChar *nameURI, const xmlChar *match,
283 const xmlChar *use, xmlNodePtr inst) {
284 xsltKeyDefPtr key;
285 xmlChar *pattern = NULL;
286 int current, end, start, i = 0;
288 if ((style == NULL) || (name == NULL) || (match == NULL) || (use == NULL))
289 return(-1);
291 #ifdef WITH_XSLT_DEBUG_KEYS
292 xsltGenericDebug(xsltGenericDebugContext,
293 "Add key %s, match %s, use %s\n", name, match, use);
294 #endif
296 key = xsltNewKeyDef(name, nameURI);
297 if (key == NULL)
298 return(-1);
299 key->match = xmlStrdup(match);
300 key->use = xmlStrdup(use);
301 key->inst = inst;
302 key->nsList = xmlGetNsList(inst->doc, inst);
303 if (key->nsList != NULL) {
304 while (key->nsList[i] != NULL)
305 i++;
307 key->nsNr = i;
310 * Split the | and register it as as many keys
312 current = end = 0;
313 while (match[current] != 0) {
314 start = current;
315 while (xmlIsBlank_ch(match[current]))
316 current++;
317 end = current;
318 while ((match[end] != 0) && (match[end] != '|')) {
319 if (match[end] == '[') {
320 end = skipPredicate(match, end);
321 if (end <= 0) {
322 xsltTransformError(NULL, style, inst,
323 "xsl:key : 'match' pattern is malformed: %s",
324 key->match);
325 if (style != NULL) style->errors++;
326 goto error;
328 } else
329 end++;
331 if (current == end) {
332 xsltTransformError(NULL, style, inst,
333 "xsl:key : 'match' pattern is empty\n");
334 if (style != NULL) style->errors++;
335 goto error;
337 if (match[start] != '/') {
338 pattern = xmlStrcat(pattern, (xmlChar *)"//");
339 if (pattern == NULL) {
340 if (style != NULL) style->errors++;
341 goto error;
344 pattern = xmlStrncat(pattern, &match[start], end - start);
345 if (pattern == NULL) {
346 if (style != NULL) style->errors++;
347 goto error;
350 if (match[end] == '|') {
351 pattern = xmlStrcat(pattern, (xmlChar *)"|");
352 end++;
354 current = end;
356 if (pattern == NULL) {
357 xsltTransformError(NULL, style, inst,
358 "xsl:key : 'match' pattern is empty\n");
359 if (style != NULL) style->errors++;
360 goto error;
362 #ifdef WITH_XSLT_DEBUG_KEYS
363 xsltGenericDebug(xsltGenericDebugContext,
364 " resulting pattern %s\n", pattern);
365 #endif
367 * XSLT-1: "It is an error for the value of either the use
368 * attribute or the match attribute to contain a
369 * VariableReference."
370 * TODO: We should report a variable-reference at compile-time.
371 * Maybe a search for "$", if it occurs outside of quotation
372 * marks, could be sufficient.
374 #ifdef XML_XPATH_NOVAR
375 key->comp = xsltXPathCompileFlags(style, pattern, XML_XPATH_NOVAR);
376 #else
377 key->comp = xsltXPathCompile(style, pattern);
378 #endif
379 if (key->comp == NULL) {
380 xsltTransformError(NULL, style, inst,
381 "xsl:key : 'match' pattern compilation failed '%s'\n",
382 pattern);
383 if (style != NULL) style->errors++;
385 #ifdef XML_XPATH_NOVAR
386 key->usecomp = xsltXPathCompileFlags(style, use, XML_XPATH_NOVAR);
387 #else
388 key->usecomp = xsltXPathCompile(style, use);
389 #endif
390 if (key->usecomp == NULL) {
391 xsltTransformError(NULL, style, inst,
392 "xsl:key : 'use' expression compilation failed '%s'\n",
393 use);
394 if (style != NULL) style->errors++;
398 * Sometimes the stylesheet writer use the order to ease the
399 * resolution of keys when they are dependant, keep the provided
400 * order so add the new one at the end.
402 if (style->keys == NULL) {
403 style->keys = key;
404 } else {
405 xsltKeyDefPtr prev = style->keys;
407 while (prev->next != NULL)
408 prev = prev->next;
410 prev->next = key;
412 key->next = NULL;
413 key = NULL;
415 error:
416 if (pattern != NULL)
417 xmlFree(pattern);
418 if (key != NULL)
419 xsltFreeKeyDef(key);
420 return(0);
424 * xsltGetKey:
425 * @ctxt: an XSLT transformation context
426 * @name: the key name or NULL
427 * @nameURI: the name URI or NULL
428 * @value: the key value to look for
430 * Looks up a key of the in current source doc (the document info
431 * on @ctxt->document). Computes the key if not already done
432 * for the current source doc.
434 * Returns the nodeset resulting from the query or NULL
436 xmlNodeSetPtr
437 xsltGetKey(xsltTransformContextPtr ctxt, const xmlChar *name,
438 const xmlChar *nameURI, const xmlChar *value) {
439 xmlNodeSetPtr ret;
440 xsltKeyTablePtr table;
441 int init_table = 0;
443 if ((ctxt == NULL) || (name == NULL) || (value == NULL) ||
444 (ctxt->document == NULL))
445 return(NULL);
447 #ifdef WITH_XSLT_DEBUG_KEYS
448 xsltGenericDebug(xsltGenericDebugContext,
449 "Get key %s, value %s\n", name, value);
450 #endif
453 * keys are computed only on-demand on first key access for a document
455 if ((ctxt->document->nbKeysComputed < ctxt->nbKeys) &&
456 (ctxt->keyInitLevel == 0)) {
458 * If non-recursive behaviour, just try to initialize all keys
460 if (xsltInitAllDocKeys(ctxt))
461 return(NULL);
464 retry:
465 table = (xsltKeyTablePtr) ctxt->document->keys;
466 while (table != NULL) {
467 if (((nameURI != NULL) == (table->nameURI != NULL)) &&
468 xmlStrEqual(table->name, name) &&
469 xmlStrEqual(table->nameURI, nameURI))
471 ret = (xmlNodeSetPtr)xmlHashLookup(table->keys, value);
472 return(ret);
474 table = table->next;
477 if ((ctxt->keyInitLevel != 0) && (init_table == 0)) {
479 * Apparently one key is recursive and this one is needed,
480 * initialize just it, that time and retry
482 xsltInitDocKeyTable(ctxt, name, nameURI);
483 init_table = 1;
484 goto retry;
487 return(NULL);
492 * xsltInitDocKeyTable:
494 * INTERNAL ROUTINE ONLY
496 * Check if any keys on the current document need to be computed
498 static int
499 xsltInitDocKeyTable(xsltTransformContextPtr ctxt, const xmlChar *name,
500 const xmlChar *nameURI)
502 xsltStylesheetPtr style;
503 xsltKeyDefPtr keyd = NULL;
504 int found = 0;
506 #ifdef KEY_INIT_DEBUG
507 fprintf(stderr, "xsltInitDocKeyTable %s\n", name);
508 #endif
510 style = ctxt->style;
511 while (style != NULL) {
512 keyd = (xsltKeyDefPtr) style->keys;
513 while (keyd != NULL) {
514 if (((keyd->nameURI != NULL) ==
515 (nameURI != NULL)) &&
516 xmlStrEqual(keyd->name, name) &&
517 xmlStrEqual(keyd->nameURI, nameURI))
519 xsltInitCtxtKey(ctxt, ctxt->document, keyd);
520 if (ctxt->document->nbKeysComputed == ctxt->nbKeys)
521 return(0);
522 found = 1;
524 keyd = keyd->next;
526 style = xsltNextImport(style);
528 if (found == 0) {
529 #ifdef WITH_XSLT_DEBUG_KEYS
530 XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,
531 "xsltInitDocKeyTable: did not found %s\n", name));
532 #endif
533 xsltTransformError(ctxt, NULL, keyd? keyd->inst : NULL,
534 "Failed to find key definition for %s\n", name);
535 ctxt->state = XSLT_STATE_STOPPED;
536 return(-1);
538 #ifdef KEY_INIT_DEBUG
539 fprintf(stderr, "xsltInitDocKeyTable %s done\n", name);
540 #endif
541 return(0);
545 * xsltInitAllDocKeys:
546 * @ctxt: transformation context
548 * INTERNAL ROUTINE ONLY
550 * Check if any keys on the current document need to be computed
552 * Returns 0 in case of success, -1 in case of failure
555 xsltInitAllDocKeys(xsltTransformContextPtr ctxt)
557 xsltStylesheetPtr style;
558 xsltKeyDefPtr keyd;
559 xsltKeyTablePtr table;
561 if (ctxt == NULL)
562 return(-1);
564 #ifdef KEY_INIT_DEBUG
565 fprintf(stderr, "xsltInitAllDocKeys %d %d\n",
566 ctxt->document->nbKeysComputed, ctxt->nbKeys);
567 #endif
569 if (ctxt->document->nbKeysComputed == ctxt->nbKeys)
570 return(0);
574 * TODO: This could be further optimized
576 style = ctxt->style;
577 while (style) {
578 keyd = (xsltKeyDefPtr) style->keys;
579 while (keyd != NULL) {
580 #ifdef KEY_INIT_DEBUG
581 fprintf(stderr, "Init key %s\n", keyd->name);
582 #endif
584 * Check if keys with this QName have been already
585 * computed.
587 table = (xsltKeyTablePtr) ctxt->document->keys;
588 while (table) {
589 if (((keyd->nameURI != NULL) == (table->nameURI != NULL)) &&
590 xmlStrEqual(keyd->name, table->name) &&
591 xmlStrEqual(keyd->nameURI, table->nameURI))
593 break;
595 table = table->next;
597 if (table == NULL) {
599 * Keys with this QName have not been yet computed.
601 xsltInitDocKeyTable(ctxt, keyd->name, keyd->nameURI);
603 keyd = keyd->next;
605 style = xsltNextImport(style);
607 #ifdef KEY_INIT_DEBUG
608 fprintf(stderr, "xsltInitAllDocKeys: done\n");
609 #endif
610 return(0);
614 * xsltInitCtxtKey:
615 * @ctxt: an XSLT transformation context
616 * @idoc: the document information (holds key values)
617 * @keyDef: the key definition
619 * Computes the key tables this key and for the current input document.
621 * Returns: 0 on success, -1 on error
624 xsltInitCtxtKey(xsltTransformContextPtr ctxt, xsltDocumentPtr idoc,
625 xsltKeyDefPtr keyDef)
627 int i, len, k;
628 xmlNodeSetPtr matchList = NULL, keylist;
629 xmlXPathObjectPtr matchRes = NULL, useRes = NULL;
630 xmlChar *str = NULL;
631 xsltKeyTablePtr table;
632 xmlNodePtr oldInst, cur;
633 xmlNodePtr oldContextNode;
634 xsltDocumentPtr oldDocInfo;
635 int oldXPPos, oldXPSize;
636 xmlNodePtr oldXPNode;
637 xmlDocPtr oldXPDoc;
638 int oldXPNsNr;
639 xmlNsPtr *oldXPNamespaces;
640 xmlXPathContextPtr xpctxt;
642 #ifdef KEY_INIT_DEBUG
643 fprintf(stderr, "xsltInitCtxtKey %s : %d\n", keyDef->name, ctxt->keyInitLevel);
644 #endif
646 if ((keyDef->comp == NULL) || (keyDef->usecomp == NULL))
647 return(-1);
650 * Detect recursive keys
652 if (ctxt->keyInitLevel > ctxt->nbKeys) {
653 #ifdef WITH_XSLT_DEBUG_KEYS
654 XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,
655 xsltGenericDebug(xsltGenericDebugContext,
656 "xsltInitCtxtKey: key definition of %s is recursive\n",
657 keyDef->name));
658 #endif
659 xsltTransformError(ctxt, NULL, keyDef->inst,
660 "Key definition for %s is recursive\n", keyDef->name);
661 ctxt->state = XSLT_STATE_STOPPED;
662 return(-1);
664 ctxt->keyInitLevel++;
666 xpctxt = ctxt->xpathCtxt;
667 idoc->nbKeysComputed++;
669 * Save context state.
671 oldInst = ctxt->inst;
672 oldDocInfo = ctxt->document;
673 oldContextNode = ctxt->node;
675 oldXPNode = xpctxt->node;
676 oldXPDoc = xpctxt->doc;
677 oldXPPos = xpctxt->proximityPosition;
678 oldXPSize = xpctxt->contextSize;
679 oldXPNsNr = xpctxt->nsNr;
680 oldXPNamespaces = xpctxt->namespaces;
683 * Set up contexts.
685 ctxt->document = idoc;
686 ctxt->node = (xmlNodePtr) idoc->doc;
687 ctxt->inst = keyDef->inst;
689 xpctxt->doc = idoc->doc;
690 xpctxt->node = (xmlNodePtr) idoc->doc;
691 /* TODO : clarify the use of namespaces in keys evaluation */
692 xpctxt->namespaces = keyDef->nsList;
693 xpctxt->nsNr = keyDef->nsNr;
696 * Evaluate the 'match' expression of the xsl:key.
697 * TODO: The 'match' is a *pattern*.
699 matchRes = xmlXPathCompiledEval(keyDef->comp, xpctxt);
700 if (matchRes == NULL) {
702 #ifdef WITH_XSLT_DEBUG_KEYS
703 XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,
704 "xsltInitCtxtKey: %s evaluation failed\n", keyDef->match));
705 #endif
706 xsltTransformError(ctxt, NULL, keyDef->inst,
707 "Failed to evaluate the 'match' expression.\n");
708 ctxt->state = XSLT_STATE_STOPPED;
709 goto error;
710 } else {
711 if (matchRes->type == XPATH_NODESET) {
712 matchList = matchRes->nodesetval;
714 #ifdef WITH_XSLT_DEBUG_KEYS
715 if (matchList != NULL)
716 XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,
717 "xsltInitCtxtKey: %s evaluates to %d nodes\n",
718 keyDef->match, matchList->nodeNr));
719 #endif
720 } else {
722 * Is not a node set, but must be.
724 #ifdef WITH_XSLT_DEBUG_KEYS
725 XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,
726 "xsltInitCtxtKey: %s is not a node set\n", keyDef->match));
727 #endif
728 xsltTransformError(ctxt, NULL, keyDef->inst,
729 "The 'match' expression did not evaluate to a node set.\n");
730 ctxt->state = XSLT_STATE_STOPPED;
731 goto error;
734 if ((matchList == NULL) || (matchList->nodeNr <= 0))
735 goto exit;
738 * Multiple key definitions for the same name are allowed, so
739 * we must check if the key is already present for this doc
741 table = (xsltKeyTablePtr) idoc->keys;
742 while (table != NULL) {
743 if (xmlStrEqual(table->name, keyDef->name) &&
744 (((keyDef->nameURI == NULL) && (table->nameURI == NULL)) ||
745 ((keyDef->nameURI != NULL) && (table->nameURI != NULL) &&
746 (xmlStrEqual(table->nameURI, keyDef->nameURI)))))
747 break;
748 table = table->next;
751 * If the key was not previously defined, create it now and
752 * chain it to the list of keys for the doc
754 if (table == NULL) {
755 table = xsltNewKeyTable(keyDef->name, keyDef->nameURI);
756 if (table == NULL)
757 goto error;
758 table->next = idoc->keys;
759 idoc->keys = table;
763 * SPEC XSLT 1.0 (XSLT 2.0 does not clarify the context size!)
764 * "...the use attribute of the xsl:key element is evaluated with x as
765 " the current node and with a node list containing just x as the
766 * current node list"
768 xpctxt->contextSize = 1;
769 xpctxt->proximityPosition = 1;
771 for (i = 0; i < matchList->nodeNr; i++) {
772 cur = matchList->nodeTab[i];
773 if (! IS_XSLT_REAL_NODE(cur))
774 continue;
775 ctxt->node = cur;
776 xpctxt->node = cur;
778 * Process the 'use' of the xsl:key.
779 * SPEC XSLT 1.0:
780 * "The use attribute is an expression specifying the values of
781 * the key; the expression is evaluated once for each node that
782 * matches the pattern."
784 if (useRes != NULL)
785 xmlXPathFreeObject(useRes);
786 useRes = xmlXPathCompiledEval(keyDef->usecomp, xpctxt);
787 if (useRes == NULL) {
788 xsltTransformError(ctxt, NULL, keyDef->inst,
789 "Failed to evaluate the 'use' expression.\n");
790 ctxt->state = XSLT_STATE_STOPPED;
791 break;
793 if (useRes->type == XPATH_NODESET) {
794 if ((useRes->nodesetval != NULL) &&
795 (useRes->nodesetval->nodeNr != 0))
797 len = useRes->nodesetval->nodeNr;
798 str = xmlXPathCastNodeToString(useRes->nodesetval->nodeTab[0]);
799 } else {
800 continue;
802 } else {
803 len = 1;
804 if (useRes->type == XPATH_STRING) {
806 * Consume the string value.
808 str = useRes->stringval;
809 useRes->stringval = NULL;
810 } else {
811 str = xmlXPathCastToString(useRes);
815 * Process all strings.
817 k = 0;
818 while (1) {
819 if (str == NULL)
820 goto next_string;
822 #ifdef WITH_XSLT_DEBUG_KEYS
823 XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,
824 "xsl:key : node associated to ('%s', '%s')\n", keyDef->name, str));
825 #endif
827 keylist = xmlHashLookup(table->keys, str);
828 if (keylist == NULL) {
829 keylist = xmlXPathNodeSetCreate(cur);
830 if (keylist == NULL)
831 goto error;
832 if (xmlHashAddEntry(table->keys, str, keylist) < 0) {
833 xmlXPathFreeNodeSet(keylist);
834 goto error;
836 } else {
838 * TODO: How do we know if this function failed?
840 xmlXPathNodeSetAdd(keylist, cur);
842 xsltSetSourceNodeFlags(ctxt, cur, XSLT_SOURCE_NODE_HAS_KEY);
843 xmlFree(str);
844 str = NULL;
846 next_string:
847 k++;
848 if (k >= len)
849 break;
850 str = xmlXPathCastNodeToString(useRes->nodesetval->nodeTab[k]);
854 exit:
855 error:
856 ctxt->keyInitLevel--;
858 * Restore context state.
860 xpctxt->node = oldXPNode;
861 xpctxt->doc = oldXPDoc;
862 xpctxt->nsNr = oldXPNsNr;
863 xpctxt->namespaces = oldXPNamespaces;
864 xpctxt->proximityPosition = oldXPPos;
865 xpctxt->contextSize = oldXPSize;
867 ctxt->node = oldContextNode;
868 ctxt->document = oldDocInfo;
869 ctxt->inst = oldInst;
871 if (str)
872 xmlFree(str);
873 if (useRes != NULL)
874 xmlXPathFreeObject(useRes);
875 if (matchRes != NULL)
876 xmlXPathFreeObject(matchRes);
877 return(0);
881 * xsltInitCtxtKeys:
882 * @ctxt: an XSLT transformation context
883 * @idoc: a document info
885 * Computes all the keys tables for the current input document.
886 * Should be done before global varibales are initialized.
887 * NOTE: Not used anymore in the refactored code.
889 void
890 xsltInitCtxtKeys(xsltTransformContextPtr ctxt, xsltDocumentPtr idoc) {
891 xsltStylesheetPtr style;
892 xsltKeyDefPtr keyDef;
894 if ((ctxt == NULL) || (idoc == NULL))
895 return;
897 #ifdef KEY_INIT_DEBUG
898 fprintf(stderr, "xsltInitCtxtKeys on document\n");
899 #endif
901 #ifdef WITH_XSLT_DEBUG_KEYS
902 if ((idoc->doc != NULL) && (idoc->doc->URL != NULL))
903 XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext, "Initializing keys on %s\n",
904 idoc->doc->URL));
905 #endif
906 style = ctxt->style;
907 while (style != NULL) {
908 keyDef = (xsltKeyDefPtr) style->keys;
909 while (keyDef != NULL) {
910 xsltInitCtxtKey(ctxt, idoc, keyDef);
912 keyDef = keyDef->next;
915 style = xsltNextImport(style);
918 #ifdef KEY_INIT_DEBUG
919 fprintf(stderr, "xsltInitCtxtKeys on document: done\n");
920 #endif
925 * xsltFreeDocumentKeys:
926 * @idoc: a XSLT document
928 * Free the keys associated to a document
930 void
931 xsltFreeDocumentKeys(xsltDocumentPtr idoc) {
932 if (idoc != NULL)
933 xsltFreeKeyTableList(idoc->keys);