VirtualBox

source: vbox/trunk/src/libs/libxslt-1.1.22/libxslt/keys.c@ 24345

Last change on this file since 24345 was 7296, checked in by vboxsync, 17 years ago

Added libxslt-1.1.22 sources.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 21.2 KB
Line 
1/*
2 * keys.c: Implemetation of the keys support
3 *
4 * Reference:
5 * http://www.w3.org/TR/1999/REC-xslt-19991116
6 *
7 * See Copyright for the status of this software.
8 *
9 * [email protected]
10 */
11
12#define IN_LIBXSLT
13#include "libxslt.h"
14
15#include <string.h>
16
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 "xslt.h"
25#include "xsltInternals.h"
26#include "xsltutils.h"
27#include "imports.h"
28#include "templates.h"
29#include "keys.h"
30
31#ifdef WITH_XSLT_DEBUG
32#define WITH_XSLT_DEBUG_KEYS
33#endif
34
35
36/************************************************************************
37 * *
38 * Type functions *
39 * *
40 ************************************************************************/
41
42/**
43 * xsltNewKeyDef:
44 * @name: the key name or NULL
45 * @nameURI: the name URI or NULL
46 *
47 * Create a new XSLT KeyDef
48 *
49 * Returns the newly allocated xsltKeyDefPtr or NULL in case of error
50 */
51static xsltKeyDefPtr
52xsltNewKeyDef(const xmlChar *name, const xmlChar *nameURI) {
53 xsltKeyDefPtr cur;
54
55 cur = (xsltKeyDefPtr) xmlMalloc(sizeof(xsltKeyDef));
56 if (cur == NULL) {
57 xsltTransformError(NULL, NULL, NULL,
58 "xsltNewKeyDef : malloc failed\n");
59 return(NULL);
60 }
61 memset(cur, 0, sizeof(xsltKeyDef));
62 if (name != NULL)
63 cur->name = xmlStrdup(name);
64 if (nameURI != NULL)
65 cur->nameURI = xmlStrdup(nameURI);
66 cur->nsList = NULL;
67 return(cur);
68}
69
70/**
71 * xsltFreeKeyDef:
72 * @keyd: an XSLT key definition
73 *
74 * Free up the memory allocated by @keyd
75 */
76static void
77xsltFreeKeyDef(xsltKeyDefPtr keyd) {
78 if (keyd == NULL)
79 return;
80 if (keyd->comp != NULL)
81 xmlXPathFreeCompExpr(keyd->comp);
82 if (keyd->usecomp != NULL)
83 xmlXPathFreeCompExpr(keyd->usecomp);
84 if (keyd->name != NULL)
85 xmlFree(keyd->name);
86 if (keyd->nameURI != NULL)
87 xmlFree(keyd->nameURI);
88 if (keyd->match != NULL)
89 xmlFree(keyd->match);
90 if (keyd->use != NULL)
91 xmlFree(keyd->use);
92 if (keyd->nsList != NULL)
93 xmlFree(keyd->nsList);
94 memset(keyd, -1, sizeof(xsltKeyDef));
95 xmlFree(keyd);
96}
97
98/**
99 * xsltFreeKeyDefList:
100 * @keyd: an XSLT key definition list
101 *
102 * Free up the memory allocated by all the elements of @keyd
103 */
104static void
105xsltFreeKeyDefList(xsltKeyDefPtr keyd) {
106 xsltKeyDefPtr cur;
107
108 while (keyd != NULL) {
109 cur = keyd;
110 keyd = keyd->next;
111 xsltFreeKeyDef(cur);
112 }
113}
114
115/**
116 * xsltNewKeyTable:
117 * @name: the key name or NULL
118 * @nameURI: the name URI or NULL
119 *
120 * Create a new XSLT KeyTable
121 *
122 * Returns the newly allocated xsltKeyTablePtr or NULL in case of error
123 */
124static xsltKeyTablePtr
125xsltNewKeyTable(const xmlChar *name, const xmlChar *nameURI) {
126 xsltKeyTablePtr cur;
127
128 cur = (xsltKeyTablePtr) xmlMalloc(sizeof(xsltKeyTable));
129 if (cur == NULL) {
130 xsltTransformError(NULL, NULL, NULL,
131 "xsltNewKeyTable : malloc failed\n");
132 return(NULL);
133 }
134 memset(cur, 0, sizeof(xsltKeyTable));
135 if (name != NULL)
136 cur->name = xmlStrdup(name);
137 if (nameURI != NULL)
138 cur->nameURI = xmlStrdup(nameURI);
139 cur->keys = xmlHashCreate(0);
140 return(cur);
141}
142
143/**
144 * xsltFreeKeyTable:
145 * @keyt: an XSLT key table
146 *
147 * Free up the memory allocated by @keyt
148 */
149static void
150xsltFreeKeyTable(xsltKeyTablePtr keyt) {
151 if (keyt == NULL)
152 return;
153 if (keyt->name != NULL)
154 xmlFree(keyt->name);
155 if (keyt->nameURI != NULL)
156 xmlFree(keyt->nameURI);
157 if (keyt->keys != NULL)
158 xmlHashFree(keyt->keys,
159 (xmlHashDeallocator) xmlXPathFreeNodeSet);
160 memset(keyt, -1, sizeof(xsltKeyTable));
161 xmlFree(keyt);
162}
163
164/**
165 * xsltFreeKeyTableList:
166 * @keyt: an XSLT key table list
167 *
168 * Free up the memory allocated by all the elements of @keyt
169 */
170static void
171xsltFreeKeyTableList(xsltKeyTablePtr keyt) {
172 xsltKeyTablePtr cur;
173
174 while (keyt != NULL) {
175 cur = keyt;
176 keyt = keyt->next;
177 xsltFreeKeyTable(cur);
178 }
179}
180
181/************************************************************************
182 * *
183 * The interpreter for the precompiled patterns *
184 * *
185 ************************************************************************/
186
187
188/**
189 * xsltFreeKeys:
190 * @style: an XSLT stylesheet
191 *
192 * Free up the memory used by XSLT keys in a stylesheet
193 */
194void
195xsltFreeKeys(xsltStylesheetPtr style) {
196 if (style->keys)
197 xsltFreeKeyDefList((xsltKeyDefPtr) style->keys);
198}
199
200/**
201 * skipString:
202 * @cur: the current pointer
203 * @end: the current offset
204 *
205 * skip a string delimited by " or '
206 *
207 * Returns the byte after the string or -1 in case of error
208 */
209static int
210skipString(const xmlChar *cur, int end) {
211 xmlChar limit;
212
213 if ((cur == NULL) || (end < 0)) return(-1);
214 if ((cur[end] == '\'') || (cur[end] == '"')) limit = cur[end];
215 else return(end);
216 end++;
217 while (cur[end] != 0) {
218 if (cur[end] == limit)
219 return(end + 1);
220 end++;
221 }
222 return(-1);
223}
224
225/**
226 * skipPredicate:
227 * @cur: the current pointer
228 * @end: the current offset
229 *
230 * skip a predicate
231 *
232 * Returns the byte after the predicate or -1 in case of error
233 */
234static int
235skipPredicate(const xmlChar *cur, int end) {
236 if ((cur == NULL) || (end < 0)) return(-1);
237 if (cur[end] != '[') return(end);
238 end++;
239 while (cur[end] != 0) {
240 if ((cur[end] == '\'') || (cur[end] == '"')) {
241 end = skipString(cur, end);
242 if (end <= 0)
243 return(-1);
244 continue;
245 } else if (cur[end] == '[') {
246 end = skipPredicate(cur, end);
247 if (end <= 0)
248 return(-1);
249 continue;
250 } else if (cur[end] == ']')
251 return(end + 1);
252 end++;
253 }
254 return(-1);
255}
256
257/**
258 * xsltAddKey:
259 * @style: an XSLT stylesheet
260 * @name: the key name or NULL
261 * @nameURI: the name URI or NULL
262 * @match: the match value
263 * @use: the use value
264 * @inst: the key instruction
265 *
266 * add a key definition to a stylesheet
267 *
268 * Returns 0 in case of success, and -1 in case of failure.
269 */
270int
271xsltAddKey(xsltStylesheetPtr style, const xmlChar *name,
272 const xmlChar *nameURI, const xmlChar *match,
273 const xmlChar *use, xmlNodePtr inst) {
274 xsltKeyDefPtr key;
275 xmlChar *pattern = NULL;
276 int current, end, start, i = 0;
277
278 if ((style == NULL) || (name == NULL) || (match == NULL) || (use == NULL))
279 return(-1);
280
281#ifdef WITH_XSLT_DEBUG_KEYS
282 xsltGenericDebug(xsltGenericDebugContext,
283 "Add key %s, match %s, use %s\n", name, match, use);
284#endif
285
286 key = xsltNewKeyDef(name, nameURI);
287 key->match = xmlStrdup(match);
288 key->use = xmlStrdup(use);
289 key->inst = inst;
290 key->nsList = xmlGetNsList(inst->doc, inst);
291 if (key->nsList != NULL) {
292 while (key->nsList[i] != NULL)
293 i++;
294 }
295 key->nsNr = i;
296
297 /*
298 * Split the | and register it as as many keys
299 */
300 current = end = 0;
301 while (match[current] != 0) {
302 start = current;
303 while (IS_BLANK_CH(match[current]))
304 current++;
305 end = current;
306 while ((match[end] != 0) && (match[end] != '|')) {
307 if (match[end] == '[') {
308 end = skipPredicate(match, end);
309 if (end <= 0) {
310 xsltTransformError(NULL, style, inst,
311 "key pattern is malformed: %s",
312 key->match);
313 if (style != NULL) style->errors++;
314 goto error;
315 }
316 } else
317 end++;
318 }
319 if (current == end) {
320 xsltTransformError(NULL, style, inst,
321 "key pattern is empty\n");
322 if (style != NULL) style->errors++;
323 goto error;
324 }
325 if (match[start] != '/') {
326 pattern = xmlStrcat(pattern, (xmlChar *)"//");
327 if (pattern == NULL) {
328 if (style != NULL) style->errors++;
329 goto error;
330 }
331 }
332 pattern = xmlStrncat(pattern, &match[start], end - start);
333 if (pattern == NULL) {
334 if (style != NULL) style->errors++;
335 goto error;
336 }
337
338 if (match[end] == '|') {
339 pattern = xmlStrcat(pattern, (xmlChar *)"|");
340 end++;
341 }
342 current = end;
343 }
344#ifdef WITH_XSLT_DEBUG_KEYS
345 xsltGenericDebug(xsltGenericDebugContext,
346 " resulting pattern %s\n", pattern);
347#endif
348 /*
349 * XSLT-1: "It is an error for the value of either the use
350 * attribute or the match attribute to contain a
351 * VariableReference."
352 * TODO: We should report a variable-reference at compile-time.
353 * Maybe a search for "$", if it occurs outside of quotation
354 * marks, could be sufficient.
355 */
356 key->comp = xsltXPathCompile(style, pattern);
357 if (key->comp == NULL) {
358 xsltTransformError(NULL, style, inst,
359 "xsl:key : XPath pattern compilation failed '%s'\n",
360 pattern);
361 if (style != NULL) style->errors++;
362 }
363 key->usecomp = xsltXPathCompile(style, use);
364 if (key->usecomp == NULL) {
365 xsltTransformError(NULL, style, inst,
366 "xsl:key : XPath pattern compilation failed '%s'\n",
367 use);
368 if (style != NULL) style->errors++;
369 }
370 key->next = style->keys;
371 style->keys = key;
372error:
373 if (pattern != NULL)
374 xmlFree(pattern);
375 return(0);
376}
377
378/**
379 * xsltGetKey:
380 * @ctxt: an XSLT transformation context
381 * @name: the key name or NULL
382 * @nameURI: the name URI or NULL
383 * @value: the key value to look for
384 *
385 * Looks up a key of the in current source doc (the document info
386 * on @ctxt->document). Computes the key if not already done
387 * for the current source doc.
388 *
389 * Returns the nodeset resulting from the query or NULL
390 */
391xmlNodeSetPtr
392xsltGetKey(xsltTransformContextPtr ctxt, const xmlChar *name,
393 const xmlChar *nameURI, const xmlChar *value) {
394 xmlNodeSetPtr ret;
395 xsltKeyTablePtr table;
396#ifdef XSLT_REFACTORED_KEYCOMP
397 int found = 0;
398#endif
399
400 if ((ctxt == NULL) || (name == NULL) || (value == NULL) ||
401 (ctxt->document == NULL))
402 return(NULL);
403
404#ifdef WITH_XSLT_DEBUG_KEYS
405 xsltGenericDebug(xsltGenericDebugContext,
406 "Get key %s, value %s\n", name, value);
407#endif
408
409 table = (xsltKeyTablePtr) ctxt->document->keys;
410 while (table != NULL) {
411 if (((nameURI != NULL) == (table->nameURI != NULL)) &&
412 xmlStrEqual(table->name, name) &&
413 xmlStrEqual(table->nameURI, nameURI))
414 {
415#ifdef XSLT_REFACTORED_KEYCOMP
416 found = 1;
417#endif
418 ret = (xmlNodeSetPtr)xmlHashLookup(table->keys, value);
419 return(ret);
420 }
421 table = table->next;
422 }
423#ifdef XSLT_REFACTORED_KEYCOMP
424 if (! found) {
425 xsltStylesheetPtr style = ctxt->style;
426 xsltKeyDefPtr keyd;
427 /*
428 * This might be the first call to the key with the specified
429 * name and the specified document.
430 * Find all keys with a matching name and compute them for the
431 * current tree.
432 */
433 found = 0;
434 while (style != NULL) {
435 keyd = (xsltKeyDefPtr) style->keys;
436 while (keyd != NULL) {
437 if (((nameURI != NULL) == (keyd->nameURI != NULL)) &&
438 xmlStrEqual(keyd->name, name) &&
439 xmlStrEqual(keyd->nameURI, nameURI))
440 {
441 found = 1;
442 xsltInitCtxtKey(ctxt, ctxt->document, keyd);
443 }
444 keyd = keyd->next;
445 }
446 style = xsltNextImport(style);
447 }
448 if (found) {
449 /*
450 * The key was computed, so look it up.
451 */
452 table = (xsltKeyTablePtr) ctxt->document->keys;
453 while (table != NULL) {
454 if (((nameURI != NULL) == (table->nameURI != NULL)) &&
455 xmlStrEqual(table->name, name) &&
456 xmlStrEqual(table->nameURI, nameURI))
457 {
458 ret = (xmlNodeSetPtr)xmlHashLookup(table->keys, value);
459 return(ret);
460 }
461 table = table->next;
462 }
463
464 }
465 }
466#endif
467 return(NULL);
468}
469
470#if 0 /* Merged with xsltInitCtxtKey() */
471/**
472 * xsltEvalXPathKeys:
473 * @ctxt: the XSLT transformation context
474 * @comp: the compiled XPath expression
475 *
476 * Process the expression using XPath to get the list of keys
477 *
478 * Returns the array of computed string value or NULL, must be deallocated
479 * by the caller.
480 */
481static xmlChar **
482xsltEvalXPathKeys(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp,
483 xsltKeyDefPtr keyd) {
484 xmlChar **ret = NULL;
485 xmlXPathObjectPtr res;
486 xmlNodePtr oldInst;
487 xmlNodePtr oldNode;
488 int oldPos, oldSize;
489 int oldNsNr;
490 xmlNsPtr *oldNamespaces;
491
492 oldInst = ctxt->inst;
493 oldNode = ctxt->node;
494 oldPos = ctxt->xpathCtxt->proximityPosition;
495 oldSize = ctxt->xpathCtxt->contextSize;
496 oldNsNr = ctxt->xpathCtxt->nsNr;
497 oldNamespaces = ctxt->xpathCtxt->namespaces;
498
499 ctxt->xpathCtxt->node = ctxt->node;
500 ctxt->xpathCtxt->namespaces = keyd->nsList;
501 ctxt->xpathCtxt->nsNr = keyd->nsNr;
502 res = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
503 if (res != NULL) {
504 if (res->type == XPATH_NODESET) {
505 int len, i, j;
506
507 if (res->nodesetval != NULL)
508 len = res->nodesetval->nodeNr;
509 else
510 len = 0;
511 if (len != 0) {
512 ret = (xmlChar **) xmlMalloc((len + 1) * sizeof(xmlChar *));
513 if (ret != NULL) {
514 for (i = 0,j = 0;i < len;i++) {
515 ret[j] = xmlXPathCastNodeToString(
516 res->nodesetval->nodeTab[i]);
517 if (ret[j] != NULL)
518 j++;
519 }
520 ret[j] = NULL;
521 }
522 }
523 } else {
524 if (res->type != XPATH_STRING)
525 res = xmlXPathConvertString(res);
526 if (res->type == XPATH_STRING) {
527 ret = (xmlChar **) xmlMalloc(2 * sizeof(xmlChar *));
528 if (ret != NULL) {
529 ret[0] = res->stringval;
530 ret[1] = NULL;
531 res->stringval = NULL;
532 }
533 } else {
534 xsltTransformError(ctxt, NULL, NULL,
535 "xpath : string() function didn't return a String\n");
536 }
537 }
538 xmlXPathFreeObject(res);
539 } else {
540 ctxt->state = XSLT_STATE_STOPPED;
541 }
542#ifdef WITH_XSLT_DEBUG_TEMPLATES
543 xsltGenericDebug(xsltGenericDebugContext,
544 "xsltEvalXPathString: returns %s\n", ret);
545#endif
546 ctxt->inst = oldInst;
547 ctxt->node = oldNode;
548 ctxt->xpathCtxt->contextSize = oldSize;
549 ctxt->xpathCtxt->proximityPosition = oldPos;
550 ctxt->xpathCtxt->nsNr = oldNsNr;
551 ctxt->xpathCtxt->namespaces = oldNamespaces;
552 return(ret);
553}
554#endif
555
556/**
557 * xsltInitCtxtKey:
558 * @ctxt: an XSLT transformation context
559 * @idoc: the document information (holds key values)
560 * @keyDef: the key definition
561 *
562 * Computes the key tables this key and for the current input document.
563 *
564 * Returns: 0 on success, -1 on error
565 */
566int
567xsltInitCtxtKey(xsltTransformContextPtr ctxt, xsltDocumentPtr idoc,
568 xsltKeyDefPtr keyDef)
569{
570 int i, len, k;
571 xmlNodeSetPtr matchList = NULL, keylist;
572 xmlXPathObjectPtr matchRes = NULL, useRes = NULL;
573 xmlChar *str = NULL;
574 xsltKeyTablePtr table;
575 xmlNodePtr oldInst, cur;
576 xmlNodePtr oldContextNode;
577 xsltDocumentPtr oldDocInfo;
578 int oldXPPos, oldXPSize;
579 xmlDocPtr oldXPDoc;
580 int oldXPNsNr;
581 xmlNsPtr *oldXPNamespaces;
582 xmlXPathContextPtr xpctxt;
583
584 if ((keyDef->comp == NULL) || (keyDef->usecomp == NULL))
585 return(-1);
586
587 xpctxt = ctxt->xpathCtxt;
588 idoc->nbKeysComputed++;
589 /*
590 * Save context state.
591 */
592 oldInst = ctxt->inst;
593 oldDocInfo = ctxt->document;
594 oldContextNode = ctxt->node;
595
596 oldXPDoc = xpctxt->doc;
597 oldXPPos = xpctxt->proximityPosition;
598 oldXPSize = xpctxt->contextSize;
599 oldXPNsNr = xpctxt->nsNr;
600 oldXPNamespaces = xpctxt->namespaces;
601
602 /*
603 * Set up contexts.
604 */
605 ctxt->document = idoc;
606 ctxt->node = (xmlNodePtr) idoc->doc;
607 ctxt->inst = keyDef->inst;
608
609 xpctxt->doc = idoc->doc;
610 xpctxt->node = (xmlNodePtr) idoc->doc;
611 /* TODO : clarify the use of namespaces in keys evaluation */
612 xpctxt->namespaces = keyDef->nsList;
613 xpctxt->nsNr = keyDef->nsNr;
614
615 /*
616 * Evaluate the 'match' expression of the xsl:key.
617 * TODO: The 'match' is a *pattern*.
618 */
619 matchRes = xmlXPathCompiledEval(keyDef->comp, xpctxt);
620 if (matchRes == NULL) {
621
622#ifdef WITH_XSLT_DEBUG_KEYS
623 XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,
624 "xsltInitCtxtKey: %s evaluation failed\n", keyDef->match));
625#endif
626 xsltTransformError(ctxt, NULL, keyDef->inst,
627 "Failed to evaluate the 'match' expression.\n");
628 ctxt->state = XSLT_STATE_STOPPED;
629 goto error;
630 } else {
631 if (matchRes->type == XPATH_NODESET) {
632 matchList = matchRes->nodesetval;
633
634#ifdef WITH_XSLT_DEBUG_KEYS
635 if (matchList != NULL)
636 XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,
637 "xsltInitCtxtKey: %s evaluates to %d nodes\n",
638 keyDef->match, matchList->nodeNr));
639#endif
640 } else {
641 /*
642 * Is not a node set, but must be.
643 */
644#ifdef WITH_XSLT_DEBUG_KEYS
645 XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,
646 "xsltInitCtxtKey: %s is not a node set\n", keyDef->match));
647#endif
648 xsltTransformError(ctxt, NULL, keyDef->inst,
649 "The 'match' expression did not evaluate to a node set.\n");
650 ctxt->state = XSLT_STATE_STOPPED;
651 goto error;
652 }
653 }
654 if ((matchList == NULL) || (matchList->nodeNr <= 0))
655 goto exit;
656
657 /**
658 * Multiple key definitions for the same name are allowed, so
659 * we must check if the key is already present for this doc
660 */
661 table = (xsltKeyTablePtr) idoc->keys;
662 while (table != NULL) {
663 if (xmlStrEqual(table->name, keyDef->name) &&
664 (((keyDef->nameURI == NULL) && (table->nameURI == NULL)) ||
665 ((keyDef->nameURI != NULL) && (table->nameURI != NULL) &&
666 (xmlStrEqual(table->nameURI, keyDef->nameURI)))))
667 break;
668 table = table->next;
669 }
670 /**
671 * If the key was not previously defined, create it now and
672 * chain it to the list of keys for the doc
673 */
674 if (table == NULL) {
675 table = xsltNewKeyTable(keyDef->name, keyDef->nameURI);
676 if (table == NULL)
677 goto error;
678 table->next = idoc->keys;
679 idoc->keys = table;
680 }
681
682 /*
683 * SPEC XSLT 1.0 (XSLT 2.0 does not clarify the context size!)
684 * "...the use attribute of the xsl:key element is evaluated with x as
685 " the current node and with a node list containing just x as the
686 * current node list"
687 */
688 xpctxt->contextSize = 1;
689 xpctxt->proximityPosition = 1;
690
691 for (i = 0; i < matchList->nodeNr; i++) {
692 cur = matchList->nodeTab[i];
693 if (! IS_XSLT_REAL_NODE(cur))
694 continue;
695 xpctxt->node = cur;
696 /*
697 * Process the 'use' of the xsl:key.
698 * SPEC XSLT 1.0:
699 * "The use attribute is an expression specifying the values of
700 * the key; the expression is evaluated once for each node that
701 * matches the pattern."
702 */
703 if (useRes != NULL)
704 xmlXPathFreeObject(useRes);
705 useRes = xmlXPathCompiledEval(keyDef->usecomp, xpctxt);
706 if (useRes == NULL) {
707 xsltTransformError(ctxt, NULL, keyDef->inst,
708 "Failed to evaluate the 'use' expression.\n");
709 ctxt->state = XSLT_STATE_STOPPED;
710 break;
711 }
712 if (useRes->type == XPATH_NODESET) {
713 if ((useRes->nodesetval != NULL) &&
714 (useRes->nodesetval->nodeNr != 0))
715 {
716 len = useRes->nodesetval->nodeNr;
717 str = xmlXPathCastNodeToString(useRes->nodesetval->nodeTab[0]);
718 } else {
719 continue;
720 }
721 } else {
722 len = 1;
723 if (useRes->type == XPATH_STRING) {
724 /*
725 * Consume the string value.
726 */
727 str = useRes->stringval;
728 useRes->stringval = NULL;
729 } else {
730 str = xmlXPathCastToString(useRes);
731 }
732 }
733 /*
734 * Process all strings.
735 */
736 k = 0;
737 while (1) {
738 if (str == NULL)
739 goto next_string;
740
741#ifdef WITH_XSLT_DEBUG_KEYS
742 XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,
743 "xsl:key : node associated to ('%s', '%s')\n", keyDef->name, str));
744#endif
745
746 keylist = xmlHashLookup(table->keys, str);
747 if (keylist == NULL) {
748 keylist = xmlXPathNodeSetCreate(cur);
749 if (keylist == NULL)
750 goto error;
751 xmlHashAddEntry(table->keys, str, keylist);
752 } else {
753 /*
754 * TODO: How do we know if this function failed?
755 */
756 xmlXPathNodeSetAdd(keylist, cur);
757 }
758 switch (cur->type) {
759 case XML_ELEMENT_NODE:
760 case XML_TEXT_NODE:
761 case XML_CDATA_SECTION_NODE:
762 case XML_PI_NODE:
763 case XML_COMMENT_NODE:
764 cur->psvi = keyDef;
765 break;
766 case XML_ATTRIBUTE_NODE:
767 ((xmlAttrPtr) cur)->psvi = keyDef;
768 break;
769 case XML_DOCUMENT_NODE:
770 case XML_HTML_DOCUMENT_NODE:
771 ((xmlDocPtr) cur)->psvi = keyDef;
772 break;
773 default:
774 break;
775 }
776 xmlFree(str);
777 str = NULL;
778
779next_string:
780 k++;
781 if (k >= len)
782 break;
783 str = xmlXPathCastNodeToString(useRes->nodesetval->nodeTab[k]);
784 }
785 }
786
787exit:
788error:
789 /*
790 * Restore context state.
791 */
792 xpctxt->doc = oldXPDoc;
793 xpctxt->nsNr = oldXPNsNr;
794 xpctxt->namespaces = oldXPNamespaces;
795 xpctxt->proximityPosition = oldXPPos;
796 xpctxt->contextSize = oldXPSize;
797
798 ctxt->node = oldContextNode;
799 ctxt->document = oldDocInfo;
800 ctxt->inst = oldInst;
801
802 if (str)
803 xmlFree(str);
804 if (useRes != NULL)
805 xmlXPathFreeObject(useRes);
806 if (matchRes != NULL)
807 xmlXPathFreeObject(matchRes);
808 return(0);
809}
810
811/**
812 * xsltInitCtxtKeys:
813 * @ctxt: an XSLT transformation context
814 * @idoc: a document info
815 *
816 * Computes all the keys tables for the current input document.
817 * Should be done before global varibales are initialized.
818 * NOTE: Not used anymore in the refactored code.
819 */
820void
821xsltInitCtxtKeys(xsltTransformContextPtr ctxt, xsltDocumentPtr idoc) {
822 xsltStylesheetPtr style;
823 xsltKeyDefPtr keyDef;
824
825 if ((ctxt == NULL) || (idoc == NULL))
826 return;
827#ifdef WITH_XSLT_DEBUG_KEYS
828 if ((idoc->doc != NULL) && (idoc->doc->URL != NULL))
829 XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext, "Initializing keys on %s\n",
830 idoc->doc->URL));
831#endif
832 style = ctxt->style;
833 while (style != NULL) {
834 keyDef = (xsltKeyDefPtr) style->keys;
835 while (keyDef != NULL) {
836 xsltInitCtxtKey(ctxt, idoc, keyDef);
837
838 keyDef = keyDef->next;
839 }
840
841 style = xsltNextImport(style);
842 }
843}
844
845/**
846 * xsltFreeDocumentKeys:
847 * @idoc: a XSLT document
848 *
849 * Free the keys associated to a document
850 */
851void
852xsltFreeDocumentKeys(xsltDocumentPtr idoc) {
853 if (idoc != NULL)
854 xsltFreeKeyTableList(idoc->keys);
855}
856
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette