2 * keys.c: Implemetation of the keys support
5 * http://www.w3.org/TR/1999/REC-xslt-19991116
7 * See Copyright for the status of this software.
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>
26 #include "xsltInternals.h"
27 #include "xsltutils.h"
29 #include "templates.h"
32 #ifdef WITH_XSLT_DEBUG
33 #define WITH_XSLT_DEBUG_KEYS
37 xsltInitDocKeyTable(xsltTransformContextPtr ctxt
, const xmlChar
*name
,
38 const xmlChar
*nameURI
);
40 /************************************************************************
44 ************************************************************************/
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
56 xsltNewKeyDef(const xmlChar
*name
, const xmlChar
*nameURI
) {
59 cur
= (xsltKeyDefPtr
) xmlMalloc(sizeof(xsltKeyDef
));
61 xsltTransformError(NULL
, NULL
, NULL
,
62 "xsltNewKeyDef : malloc failed\n");
65 memset(cur
, 0, sizeof(xsltKeyDef
));
67 cur
->name
= xmlStrdup(name
);
69 cur
->nameURI
= xmlStrdup(nameURI
);
76 * @keyd: an XSLT key definition
78 * Free up the memory allocated by @keyd
81 xsltFreeKeyDef(xsltKeyDefPtr keyd
) {
84 if (keyd
->comp
!= NULL
)
85 xmlXPathFreeCompExpr(keyd
->comp
);
86 if (keyd
->usecomp
!= NULL
)
87 xmlXPathFreeCompExpr(keyd
->usecomp
);
88 if (keyd
->name
!= NULL
)
90 if (keyd
->nameURI
!= NULL
)
91 xmlFree(keyd
->nameURI
);
92 if (keyd
->match
!= NULL
)
94 if (keyd
->use
!= NULL
)
96 if (keyd
->nsList
!= NULL
)
97 xmlFree(keyd
->nsList
);
98 memset(keyd
, -1, sizeof(xsltKeyDef
));
103 * xsltFreeKeyDefList:
104 * @keyd: an XSLT key definition list
106 * Free up the memory allocated by all the elements of @keyd
109 xsltFreeKeyDefList(xsltKeyDefPtr keyd
) {
112 while (keyd
!= NULL
) {
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
) {
132 cur
= (xsltKeyTablePtr
) xmlMalloc(sizeof(xsltKeyTable
));
134 xsltTransformError(NULL
, NULL
, NULL
,
135 "xsltNewKeyTable : malloc failed\n");
138 memset(cur
, 0, sizeof(xsltKeyTable
));
140 cur
->name
= xmlStrdup(name
);
142 cur
->nameURI
= xmlStrdup(nameURI
);
143 cur
->keys
= xmlHashCreate(0);
149 * @keyt: an XSLT key table
151 * Free up the memory allocated by @keyt
154 xsltFreeKeyTable(xsltKeyTablePtr keyt
) {
157 if (keyt
->name
!= NULL
)
159 if (keyt
->nameURI
!= NULL
)
160 xmlFree(keyt
->nameURI
);
161 if (keyt
->keys
!= NULL
)
162 xmlHashFree(keyt
->keys
,
163 (xmlHashDeallocator
) xmlXPathFreeNodeSet
);
164 memset(keyt
, -1, sizeof(xsltKeyTable
));
169 * xsltFreeKeyTableList:
170 * @keyt: an XSLT key table list
172 * Free up the memory allocated by all the elements of @keyt
175 xsltFreeKeyTableList(xsltKeyTablePtr keyt
) {
178 while (keyt
!= NULL
) {
181 xsltFreeKeyTable(cur
);
185 /************************************************************************
187 * The interpreter for the precompiled patterns *
189 ************************************************************************/
194 * @style: an XSLT stylesheet
196 * Free up the memory used by XSLT keys in a stylesheet
199 xsltFreeKeys(xsltStylesheetPtr style
) {
201 xsltFreeKeyDefList((xsltKeyDefPtr
) style
->keys
);
206 * @cur: the current pointer
207 * @end: the current offset
209 * skip a string delimited by " or '
211 * Returns the byte after the string or -1 in case of error
214 skipString(const xmlChar
*cur
, int end
) {
217 if ((cur
== NULL
) || (end
< 0)) return(-1);
218 if ((cur
[end
] == '\'') || (cur
[end
] == '"')) limit
= cur
[end
];
221 while (cur
[end
] != 0) {
222 if (cur
[end
] == limit
)
231 * @cur: the current pointer
232 * @end: the current offset
236 * Returns the byte after the predicate or -1 in case of error
239 skipPredicate(const xmlChar
*cur
, int end
) {
240 if ((cur
== NULL
) || (end
< 0)) return(-1);
241 if (cur
[end
] != '[') return(end
);
243 while (cur
[end
] != 0) {
244 if ((cur
[end
] == '\'') || (cur
[end
] == '"')) {
245 end
= skipString(cur
, end
);
249 } else if (cur
[end
] == '[') {
250 end
= skipPredicate(cur
, end
);
254 } else if (cur
[end
] == ']')
263 * @style: an XSLT stylesheet
264 * @name: the key name or NULL
265 * @nameURI: the name URI or NULL
266 * @match: the match value
267 * @use: the use value
268 * @inst: the key instruction
270 * add a key definition to a stylesheet
272 * Returns 0 in case of success, and -1 in case of failure.
275 xsltAddKey(xsltStylesheetPtr style
, const xmlChar
*name
,
276 const xmlChar
*nameURI
, const xmlChar
*match
,
277 const xmlChar
*use
, xmlNodePtr inst
) {
279 xmlChar
*pattern
= NULL
;
280 int current
, end
, start
, i
= 0;
282 if ((style
== NULL
) || (name
== NULL
) || (match
== NULL
) || (use
== NULL
))
285 #ifdef WITH_XSLT_DEBUG_KEYS
286 xsltGenericDebug(xsltGenericDebugContext
,
287 "Add key %s, match %s, use %s\n", name
, match
, use
);
290 key
= xsltNewKeyDef(name
, nameURI
);
291 key
->match
= xmlStrdup(match
);
292 key
->use
= xmlStrdup(use
);
294 key
->nsList
= xmlGetNsList(inst
->doc
, inst
);
295 if (key
->nsList
!= NULL
) {
296 while (key
->nsList
[i
] != NULL
)
302 * Split the | and register it as as many keys
305 while (match
[current
] != 0) {
307 while (IS_BLANK_CH(match
[current
]))
310 while ((match
[end
] != 0) && (match
[end
] != '|')) {
311 if (match
[end
] == '[') {
312 end
= skipPredicate(match
, end
);
314 xsltTransformError(NULL
, style
, inst
,
315 "xsl:key : 'match' pattern is malformed: %s",
317 if (style
!= NULL
) style
->errors
++;
323 if (current
== end
) {
324 xsltTransformError(NULL
, style
, inst
,
325 "xsl:key : 'match' pattern is empty\n");
326 if (style
!= NULL
) style
->errors
++;
329 if (match
[start
] != '/') {
330 pattern
= xmlStrcat(pattern
, (xmlChar
*)"//");
331 if (pattern
== NULL
) {
332 if (style
!= NULL
) style
->errors
++;
336 pattern
= xmlStrncat(pattern
, &match
[start
], end
- start
);
337 if (pattern
== NULL
) {
338 if (style
!= NULL
) style
->errors
++;
342 if (match
[end
] == '|') {
343 pattern
= xmlStrcat(pattern
, (xmlChar
*)"|");
348 if (pattern
== NULL
) {
349 xsltTransformError(NULL
, style
, inst
,
350 "xsl:key : 'match' pattern is empty\n");
351 if (style
!= NULL
) style
->errors
++;
354 #ifdef WITH_XSLT_DEBUG_KEYS
355 xsltGenericDebug(xsltGenericDebugContext
,
356 " resulting pattern %s\n", pattern
);
359 * XSLT-1: "It is an error for the value of either the use
360 * attribute or the match attribute to contain a
361 * VariableReference."
362 * TODO: We should report a variable-reference at compile-time.
363 * Maybe a search for "$", if it occurs outside of quotation
364 * marks, could be sufficient.
366 #ifdef XML_XPATH_NOVAR
367 key
->comp
= xsltXPathCompileFlags(style
, pattern
, XML_XPATH_NOVAR
);
369 key
->comp
= xsltXPathCompile(style
, pattern
);
371 if (key
->comp
== NULL
) {
372 xsltTransformError(NULL
, style
, inst
,
373 "xsl:key : 'match' pattern compilation failed '%s'\n",
375 if (style
!= NULL
) style
->errors
++;
377 #ifdef XML_XPATH_NOVAR
378 key
->usecomp
= xsltXPathCompileFlags(style
, use
, XML_XPATH_NOVAR
);
380 key
->usecomp
= xsltXPathCompile(style
, use
);
382 if (key
->usecomp
== NULL
) {
383 xsltTransformError(NULL
, style
, inst
,
384 "xsl:key : 'use' expression compilation failed '%s'\n",
386 if (style
!= NULL
) style
->errors
++;
390 * Sometimes the stylesheet writer use the order to ease the
391 * resolution of keys when they are dependant, keep the provided
392 * order so add the new one at the end.
394 if (style
->keys
== NULL
) {
397 xsltKeyDefPtr prev
= style
->keys
;
399 while (prev
->next
!= NULL
)
414 * @ctxt: an XSLT transformation context
415 * @name: the key name or NULL
416 * @nameURI: the name URI or NULL
417 * @value: the key value to look for
419 * Looks up a key of the in current source doc (the document info
420 * on @ctxt->document). Computes the key if not already done
421 * for the current source doc.
423 * Returns the nodeset resulting from the query or NULL
426 xsltGetKey(xsltTransformContextPtr ctxt
, const xmlChar
*name
,
427 const xmlChar
*nameURI
, const xmlChar
*value
) {
429 xsltKeyTablePtr table
;
432 if ((ctxt
== NULL
) || (name
== NULL
) || (value
== NULL
) ||
433 (ctxt
->document
== NULL
))
436 #ifdef WITH_XSLT_DEBUG_KEYS
437 xsltGenericDebug(xsltGenericDebugContext
,
438 "Get key %s, value %s\n", name
, value
);
442 * keys are computed only on-demand on first key access for a document
444 if ((ctxt
->document
->nbKeysComputed
< ctxt
->nbKeys
) &&
445 (ctxt
->keyInitLevel
== 0)) {
447 * If non-recursive behaviour, just try to initialize all keys
449 if (xsltInitAllDocKeys(ctxt
))
454 table
= (xsltKeyTablePtr
) ctxt
->document
->keys
;
455 while (table
!= NULL
) {
456 if (((nameURI
!= NULL
) == (table
->nameURI
!= NULL
)) &&
457 xmlStrEqual(table
->name
, name
) &&
458 xmlStrEqual(table
->nameURI
, nameURI
))
460 ret
= (xmlNodeSetPtr
)xmlHashLookup(table
->keys
, value
);
466 if ((ctxt
->keyInitLevel
!= 0) && (init_table
== 0)) {
468 * Apparently one key is recursive and this one is needed,
469 * initialize just it, that time and retry
471 xsltInitDocKeyTable(ctxt
, name
, nameURI
);
481 * xsltInitDocKeyTable:
483 * INTERNAL ROUTINE ONLY
485 * Check if any keys on the current document need to be computed
488 xsltInitDocKeyTable(xsltTransformContextPtr ctxt
, const xmlChar
*name
,
489 const xmlChar
*nameURI
)
491 xsltStylesheetPtr style
;
492 xsltKeyDefPtr keyd
= NULL
;
495 #ifdef KEY_INIT_DEBUG
496 fprintf(stderr
, "xsltInitDocKeyTable %s\n", name
);
500 while (style
!= NULL
) {
501 keyd
= (xsltKeyDefPtr
) style
->keys
;
502 while (keyd
!= NULL
) {
503 if (((keyd
->nameURI
!= NULL
) ==
504 (nameURI
!= NULL
)) &&
505 xmlStrEqual(keyd
->name
, name
) &&
506 xmlStrEqual(keyd
->nameURI
, nameURI
))
508 xsltInitCtxtKey(ctxt
, ctxt
->document
, keyd
);
509 if (ctxt
->document
->nbKeysComputed
== ctxt
->nbKeys
)
515 style
= xsltNextImport(style
);
518 #ifdef WITH_XSLT_DEBUG_KEYS
519 XSLT_TRACE(ctxt
,XSLT_TRACE_KEYS
,xsltGenericDebug(xsltGenericDebugContext
,
520 "xsltInitDocKeyTable: did not found %s\n", name
));
522 xsltTransformError(ctxt
, NULL
, keyd
? keyd
->inst
: NULL
,
523 "Failed to find key definition for %s\n", name
);
524 ctxt
->state
= XSLT_STATE_STOPPED
;
527 #ifdef KEY_INIT_DEBUG
528 fprintf(stderr
, "xsltInitDocKeyTable %s done\n", name
);
534 * xsltInitAllDocKeys:
535 * @ctxt: transformation context
537 * INTERNAL ROUTINE ONLY
539 * Check if any keys on the current document need to be computed
541 * Returns 0 in case of success, -1 in case of failure
544 xsltInitAllDocKeys(xsltTransformContextPtr ctxt
)
546 xsltStylesheetPtr style
;
548 xsltKeyTablePtr table
;
553 #ifdef KEY_INIT_DEBUG
554 fprintf(stderr
, "xsltInitAllDocKeys %d %d\n",
555 ctxt
->document
->nbKeysComputed
, ctxt
->nbKeys
);
558 if (ctxt
->document
->nbKeysComputed
== ctxt
->nbKeys
)
563 * TODO: This could be further optimized
567 keyd
= (xsltKeyDefPtr
) style
->keys
;
568 while (keyd
!= NULL
) {
569 #ifdef KEY_INIT_DEBUG
570 fprintf(stderr
, "Init key %s\n", keyd
->name
);
573 * Check if keys with this QName have been already
576 table
= (xsltKeyTablePtr
) ctxt
->document
->keys
;
578 if (((keyd
->nameURI
!= NULL
) == (table
->nameURI
!= NULL
)) &&
579 xmlStrEqual(keyd
->name
, table
->name
) &&
580 xmlStrEqual(keyd
->nameURI
, table
->nameURI
))
588 * Keys with this QName have not been yet computed.
590 xsltInitDocKeyTable(ctxt
, keyd
->name
, keyd
->nameURI
);
594 style
= xsltNextImport(style
);
596 #ifdef KEY_INIT_DEBUG
597 fprintf(stderr
, "xsltInitAllDocKeys: done\n");
604 * @ctxt: an XSLT transformation context
605 * @idoc: the document information (holds key values)
606 * @keyDef: the key definition
608 * Computes the key tables this key and for the current input document.
610 * Returns: 0 on success, -1 on error
613 xsltInitCtxtKey(xsltTransformContextPtr ctxt
, xsltDocumentPtr idoc
,
614 xsltKeyDefPtr keyDef
)
617 xmlNodeSetPtr matchList
= NULL
, keylist
;
618 xmlXPathObjectPtr matchRes
= NULL
, useRes
= NULL
;
620 xsltKeyTablePtr table
;
621 xmlNodePtr oldInst
, cur
;
622 xmlNodePtr oldContextNode
;
623 xsltDocumentPtr oldDocInfo
;
624 int oldXPPos
, oldXPSize
;
627 xmlNsPtr
*oldXPNamespaces
;
628 xmlXPathContextPtr xpctxt
;
630 #ifdef KEY_INIT_DEBUG
631 fprintf(stderr
, "xsltInitCtxtKey %s : %d\n", keyDef
->name
, ctxt
->keyInitLevel
);
634 if ((keyDef
->comp
== NULL
) || (keyDef
->usecomp
== NULL
))
638 * Detect recursive keys
640 if (ctxt
->keyInitLevel
> ctxt
->nbKeys
) {
641 #ifdef WITH_XSLT_DEBUG_KEYS
642 XSLT_TRACE(ctxt
,XSLT_TRACE_KEYS
,
643 xsltGenericDebug(xsltGenericDebugContext
,
644 "xsltInitCtxtKey: key definition of %s is recursive\n",
647 xsltTransformError(ctxt
, NULL
, keyDef
->inst
,
648 "Key definition for %s is recursive\n", keyDef
->name
);
649 ctxt
->state
= XSLT_STATE_STOPPED
;
652 ctxt
->keyInitLevel
++;
654 xpctxt
= ctxt
->xpathCtxt
;
655 idoc
->nbKeysComputed
++;
657 * Save context state.
659 oldInst
= ctxt
->inst
;
660 oldDocInfo
= ctxt
->document
;
661 oldContextNode
= ctxt
->node
;
663 oldXPDoc
= xpctxt
->doc
;
664 oldXPPos
= xpctxt
->proximityPosition
;
665 oldXPSize
= xpctxt
->contextSize
;
666 oldXPNsNr
= xpctxt
->nsNr
;
667 oldXPNamespaces
= xpctxt
->namespaces
;
672 ctxt
->document
= idoc
;
673 ctxt
->node
= (xmlNodePtr
) idoc
->doc
;
674 ctxt
->inst
= keyDef
->inst
;
676 xpctxt
->doc
= idoc
->doc
;
677 xpctxt
->node
= (xmlNodePtr
) idoc
->doc
;
678 /* TODO : clarify the use of namespaces in keys evaluation */
679 xpctxt
->namespaces
= keyDef
->nsList
;
680 xpctxt
->nsNr
= keyDef
->nsNr
;
683 * Evaluate the 'match' expression of the xsl:key.
684 * TODO: The 'match' is a *pattern*.
686 matchRes
= xmlXPathCompiledEval(keyDef
->comp
, xpctxt
);
687 if (matchRes
== NULL
) {
689 #ifdef WITH_XSLT_DEBUG_KEYS
690 XSLT_TRACE(ctxt
,XSLT_TRACE_KEYS
,xsltGenericDebug(xsltGenericDebugContext
,
691 "xsltInitCtxtKey: %s evaluation failed\n", keyDef
->match
));
693 xsltTransformError(ctxt
, NULL
, keyDef
->inst
,
694 "Failed to evaluate the 'match' expression.\n");
695 ctxt
->state
= XSLT_STATE_STOPPED
;
698 if (matchRes
->type
== XPATH_NODESET
) {
699 matchList
= matchRes
->nodesetval
;
701 #ifdef WITH_XSLT_DEBUG_KEYS
702 if (matchList
!= NULL
)
703 XSLT_TRACE(ctxt
,XSLT_TRACE_KEYS
,xsltGenericDebug(xsltGenericDebugContext
,
704 "xsltInitCtxtKey: %s evaluates to %d nodes\n",
705 keyDef
->match
, matchList
->nodeNr
));
709 * Is not a node set, but must be.
711 #ifdef WITH_XSLT_DEBUG_KEYS
712 XSLT_TRACE(ctxt
,XSLT_TRACE_KEYS
,xsltGenericDebug(xsltGenericDebugContext
,
713 "xsltInitCtxtKey: %s is not a node set\n", keyDef
->match
));
715 xsltTransformError(ctxt
, NULL
, keyDef
->inst
,
716 "The 'match' expression did not evaluate to a node set.\n");
717 ctxt
->state
= XSLT_STATE_STOPPED
;
721 if ((matchList
== NULL
) || (matchList
->nodeNr
<= 0))
725 * Multiple key definitions for the same name are allowed, so
726 * we must check if the key is already present for this doc
728 table
= (xsltKeyTablePtr
) idoc
->keys
;
729 while (table
!= NULL
) {
730 if (xmlStrEqual(table
->name
, keyDef
->name
) &&
731 (((keyDef
->nameURI
== NULL
) && (table
->nameURI
== NULL
)) ||
732 ((keyDef
->nameURI
!= NULL
) && (table
->nameURI
!= NULL
) &&
733 (xmlStrEqual(table
->nameURI
, keyDef
->nameURI
)))))
738 * If the key was not previously defined, create it now and
739 * chain it to the list of keys for the doc
742 table
= xsltNewKeyTable(keyDef
->name
, keyDef
->nameURI
);
745 table
->next
= idoc
->keys
;
750 * SPEC XSLT 1.0 (XSLT 2.0 does not clarify the context size!)
751 * "...the use attribute of the xsl:key element is evaluated with x as
752 " the current node and with a node list containing just x as the
755 xpctxt
->contextSize
= 1;
756 xpctxt
->proximityPosition
= 1;
758 for (i
= 0; i
< matchList
->nodeNr
; i
++) {
759 cur
= matchList
->nodeTab
[i
];
760 if (! IS_XSLT_REAL_NODE(cur
))
764 * Process the 'use' of the xsl:key.
766 * "The use attribute is an expression specifying the values of
767 * the key; the expression is evaluated once for each node that
768 * matches the pattern."
771 xmlXPathFreeObject(useRes
);
772 useRes
= xmlXPathCompiledEval(keyDef
->usecomp
, xpctxt
);
773 if (useRes
== NULL
) {
774 xsltTransformError(ctxt
, NULL
, keyDef
->inst
,
775 "Failed to evaluate the 'use' expression.\n");
776 ctxt
->state
= XSLT_STATE_STOPPED
;
779 if (useRes
->type
== XPATH_NODESET
) {
780 if ((useRes
->nodesetval
!= NULL
) &&
781 (useRes
->nodesetval
->nodeNr
!= 0))
783 len
= useRes
->nodesetval
->nodeNr
;
784 str
= xmlXPathCastNodeToString(useRes
->nodesetval
->nodeTab
[0]);
790 if (useRes
->type
== XPATH_STRING
) {
792 * Consume the string value.
794 str
= useRes
->stringval
;
795 useRes
->stringval
= NULL
;
797 str
= xmlXPathCastToString(useRes
);
801 * Process all strings.
808 #ifdef WITH_XSLT_DEBUG_KEYS
809 XSLT_TRACE(ctxt
,XSLT_TRACE_KEYS
,xsltGenericDebug(xsltGenericDebugContext
,
810 "xsl:key : node associated to ('%s', '%s')\n", keyDef
->name
, str
));
813 keylist
= xmlHashLookup(table
->keys
, str
);
814 if (keylist
== NULL
) {
815 keylist
= xmlXPathNodeSetCreate(cur
);
818 xmlHashAddEntry(table
->keys
, str
, keylist
);
821 * TODO: How do we know if this function failed?
823 xmlXPathNodeSetAdd(keylist
, cur
);
826 case XML_ELEMENT_NODE
:
828 case XML_CDATA_SECTION_NODE
:
830 case XML_COMMENT_NODE
:
833 case XML_ATTRIBUTE_NODE
:
834 ((xmlAttrPtr
) cur
)->psvi
= keyDef
;
836 case XML_DOCUMENT_NODE
:
837 case XML_HTML_DOCUMENT_NODE
:
838 ((xmlDocPtr
) cur
)->psvi
= keyDef
;
850 str
= xmlXPathCastNodeToString(useRes
->nodesetval
->nodeTab
[k
]);
856 ctxt
->keyInitLevel
--;
858 * Restore context state.
860 xpctxt
->doc
= oldXPDoc
;
861 xpctxt
->nsNr
= oldXPNsNr
;
862 xpctxt
->namespaces
= oldXPNamespaces
;
863 xpctxt
->proximityPosition
= oldXPPos
;
864 xpctxt
->contextSize
= oldXPSize
;
866 ctxt
->node
= oldContextNode
;
867 ctxt
->document
= oldDocInfo
;
868 ctxt
->inst
= oldInst
;
873 xmlXPathFreeObject(useRes
);
874 if (matchRes
!= NULL
)
875 xmlXPathFreeObject(matchRes
);
881 * @ctxt: an XSLT transformation context
882 * @idoc: a document info
884 * Computes all the keys tables for the current input document.
885 * Should be done before global varibales are initialized.
886 * NOTE: Not used anymore in the refactored code.
889 xsltInitCtxtKeys(xsltTransformContextPtr ctxt
, xsltDocumentPtr idoc
) {
890 xsltStylesheetPtr style
;
891 xsltKeyDefPtr keyDef
;
893 if ((ctxt
== NULL
) || (idoc
== NULL
))
896 #ifdef KEY_INIT_DEBUG
897 fprintf(stderr
, "xsltInitCtxtKeys on document\n");
900 #ifdef WITH_XSLT_DEBUG_KEYS
901 if ((idoc
->doc
!= NULL
) && (idoc
->doc
->URL
!= NULL
))
902 XSLT_TRACE(ctxt
,XSLT_TRACE_KEYS
,xsltGenericDebug(xsltGenericDebugContext
, "Initializing keys on %s\n",
906 while (style
!= NULL
) {
907 keyDef
= (xsltKeyDefPtr
) style
->keys
;
908 while (keyDef
!= NULL
) {
909 xsltInitCtxtKey(ctxt
, idoc
, keyDef
);
911 keyDef
= keyDef
->next
;
914 style
= xsltNextImport(style
);
917 #ifdef KEY_INIT_DEBUG
918 fprintf(stderr
, "xsltInitCtxtKeys on document: done\n");
924 * xsltFreeDocumentKeys:
925 * @idoc: a XSLT document
927 * Free the keys associated to a document
930 xsltFreeDocumentKeys(xsltDocumentPtr idoc
) {
932 xsltFreeKeyTableList(idoc
->keys
);