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);
148 xsltFreeNodeSetEntry(void *payload
, const xmlChar
*name ATTRIBUTE_UNUSED
) {
149 xmlXPathFreeNodeSet((xmlNodeSetPtr
) payload
);
154 * @keyt: an XSLT key table
156 * Free up the memory allocated by @keyt
159 xsltFreeKeyTable(xsltKeyTablePtr keyt
) {
162 if (keyt
->name
!= NULL
)
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
));
173 * xsltFreeKeyTableList:
174 * @keyt: an XSLT key table list
176 * Free up the memory allocated by all the elements of @keyt
179 xsltFreeKeyTableList(xsltKeyTablePtr keyt
) {
182 while (keyt
!= NULL
) {
185 xsltFreeKeyTable(cur
);
189 /************************************************************************
191 * The interpreter for the precompiled patterns *
193 ************************************************************************/
198 * @style: an XSLT stylesheet
200 * Free up the memory used by XSLT keys in a stylesheet
203 xsltFreeKeys(xsltStylesheetPtr style
) {
205 xsltFreeKeyDefList((xsltKeyDefPtr
) style
->keys
);
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
218 skipString(const xmlChar
*cur
, int end
) {
221 if ((cur
== NULL
) || (end
< 0)) return(-1);
222 if ((cur
[end
] == '\'') || (cur
[end
] == '"')) limit
= cur
[end
];
225 while (cur
[end
] != 0) {
226 if (cur
[end
] == limit
)
235 * @cur: the current pointer
236 * @end: the current offset
240 * Returns the byte after the predicate or -1 in case of error
243 skipPredicate(const xmlChar
*cur
, int end
) {
246 if ((cur
== NULL
) || (end
< 0)) return(-1);
247 if (cur
[end
] != '[') return(end
);
249 while (cur
[end
] != 0) {
250 if ((cur
[end
] == '\'') || (cur
[end
] == '"')) {
251 end
= skipString(cur
, end
);
255 } else if (cur
[end
] == '[') {
257 } else if (cur
[end
] == ']') {
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
) {
285 xmlChar
*pattern
= NULL
;
286 int current
, end
, start
, i
= 0;
288 if ((style
== NULL
) || (name
== NULL
) || (match
== NULL
) || (use
== NULL
))
291 #ifdef WITH_XSLT_DEBUG_KEYS
292 xsltGenericDebug(xsltGenericDebugContext
,
293 "Add key %s, match %s, use %s\n", name
, match
, use
);
296 key
= xsltNewKeyDef(name
, nameURI
);
299 key
->match
= xmlStrdup(match
);
300 key
->use
= xmlStrdup(use
);
302 key
->nsList
= xmlGetNsList(inst
->doc
, inst
);
303 if (key
->nsList
!= NULL
) {
304 while (key
->nsList
[i
] != NULL
)
310 * Split the | and register it as as many keys
313 while (match
[current
] != 0) {
315 while (xmlIsBlank_ch(match
[current
]))
318 while ((match
[end
] != 0) && (match
[end
] != '|')) {
319 if (match
[end
] == '[') {
320 end
= skipPredicate(match
, end
);
322 xsltTransformError(NULL
, style
, inst
,
323 "xsl:key : 'match' pattern is malformed: %s",
325 if (style
!= NULL
) style
->errors
++;
331 if (current
== end
) {
332 xsltTransformError(NULL
, style
, inst
,
333 "xsl:key : 'match' pattern is empty\n");
334 if (style
!= NULL
) style
->errors
++;
337 if (match
[start
] != '/') {
338 pattern
= xmlStrcat(pattern
, (xmlChar
*)"//");
339 if (pattern
== NULL
) {
340 if (style
!= NULL
) style
->errors
++;
344 pattern
= xmlStrncat(pattern
, &match
[start
], end
- start
);
345 if (pattern
== NULL
) {
346 if (style
!= NULL
) style
->errors
++;
350 if (match
[end
] == '|') {
351 pattern
= xmlStrcat(pattern
, (xmlChar
*)"|");
356 if (pattern
== NULL
) {
357 xsltTransformError(NULL
, style
, inst
,
358 "xsl:key : 'match' pattern is empty\n");
359 if (style
!= NULL
) style
->errors
++;
362 #ifdef WITH_XSLT_DEBUG_KEYS
363 xsltGenericDebug(xsltGenericDebugContext
,
364 " resulting pattern %s\n", pattern
);
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
);
377 key
->comp
= xsltXPathCompile(style
, pattern
);
379 if (key
->comp
== NULL
) {
380 xsltTransformError(NULL
, style
, inst
,
381 "xsl:key : 'match' pattern compilation failed '%s'\n",
383 if (style
!= NULL
) style
->errors
++;
385 #ifdef XML_XPATH_NOVAR
386 key
->usecomp
= xsltXPathCompileFlags(style
, use
, XML_XPATH_NOVAR
);
388 key
->usecomp
= xsltXPathCompile(style
, use
);
390 if (key
->usecomp
== NULL
) {
391 xsltTransformError(NULL
, style
, inst
,
392 "xsl:key : 'use' expression compilation failed '%s'\n",
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
) {
405 xsltKeyDefPtr prev
= style
->keys
;
407 while (prev
->next
!= NULL
)
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
437 xsltGetKey(xsltTransformContextPtr ctxt
, const xmlChar
*name
,
438 const xmlChar
*nameURI
, const xmlChar
*value
) {
440 xsltKeyTablePtr table
;
443 if ((ctxt
== NULL
) || (name
== NULL
) || (value
== NULL
) ||
444 (ctxt
->document
== NULL
))
447 #ifdef WITH_XSLT_DEBUG_KEYS
448 xsltGenericDebug(xsltGenericDebugContext
,
449 "Get key %s, value %s\n", name
, value
);
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
))
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
);
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
);
492 * xsltInitDocKeyTable:
494 * INTERNAL ROUTINE ONLY
496 * Check if any keys on the current document need to be computed
499 xsltInitDocKeyTable(xsltTransformContextPtr ctxt
, const xmlChar
*name
,
500 const xmlChar
*nameURI
)
502 xsltStylesheetPtr style
;
503 xsltKeyDefPtr keyd
= NULL
;
506 #ifdef KEY_INIT_DEBUG
507 fprintf(stderr
, "xsltInitDocKeyTable %s\n", name
);
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
)
526 style
= xsltNextImport(style
);
529 #ifdef WITH_XSLT_DEBUG_KEYS
530 XSLT_TRACE(ctxt
,XSLT_TRACE_KEYS
,xsltGenericDebug(xsltGenericDebugContext
,
531 "xsltInitDocKeyTable: did not found %s\n", name
));
533 xsltTransformError(ctxt
, NULL
, keyd
? keyd
->inst
: NULL
,
534 "Failed to find key definition for %s\n", name
);
535 ctxt
->state
= XSLT_STATE_STOPPED
;
538 #ifdef KEY_INIT_DEBUG
539 fprintf(stderr
, "xsltInitDocKeyTable %s done\n", name
);
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
;
559 xsltKeyTablePtr table
;
564 #ifdef KEY_INIT_DEBUG
565 fprintf(stderr
, "xsltInitAllDocKeys %d %d\n",
566 ctxt
->document
->nbKeysComputed
, ctxt
->nbKeys
);
569 if (ctxt
->document
->nbKeysComputed
== ctxt
->nbKeys
)
574 * TODO: This could be further optimized
578 keyd
= (xsltKeyDefPtr
) style
->keys
;
579 while (keyd
!= NULL
) {
580 #ifdef KEY_INIT_DEBUG
581 fprintf(stderr
, "Init key %s\n", keyd
->name
);
584 * Check if keys with this QName have been already
587 table
= (xsltKeyTablePtr
) ctxt
->document
->keys
;
589 if (((keyd
->nameURI
!= NULL
) == (table
->nameURI
!= NULL
)) &&
590 xmlStrEqual(keyd
->name
, table
->name
) &&
591 xmlStrEqual(keyd
->nameURI
, table
->nameURI
))
599 * Keys with this QName have not been yet computed.
601 xsltInitDocKeyTable(ctxt
, keyd
->name
, keyd
->nameURI
);
605 style
= xsltNextImport(style
);
607 #ifdef KEY_INIT_DEBUG
608 fprintf(stderr
, "xsltInitAllDocKeys: done\n");
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
)
628 xmlNodeSetPtr matchList
= NULL
, keylist
;
629 xmlXPathObjectPtr matchRes
= NULL
, useRes
= NULL
;
631 xsltKeyTablePtr table
;
632 xmlNodePtr oldInst
, cur
;
633 xmlNodePtr oldContextNode
;
634 xsltDocumentPtr oldDocInfo
;
635 int oldXPPos
, oldXPSize
;
636 xmlNodePtr oldXPNode
;
639 xmlNsPtr
*oldXPNamespaces
;
640 xmlXPathContextPtr xpctxt
;
642 #ifdef KEY_INIT_DEBUG
643 fprintf(stderr
, "xsltInitCtxtKey %s : %d\n", keyDef
->name
, ctxt
->keyInitLevel
);
646 if ((keyDef
->comp
== NULL
) || (keyDef
->usecomp
== NULL
))
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",
659 xsltTransformError(ctxt
, NULL
, keyDef
->inst
,
660 "Key definition for %s is recursive\n", keyDef
->name
);
661 ctxt
->state
= XSLT_STATE_STOPPED
;
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
;
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
));
706 xsltTransformError(ctxt
, NULL
, keyDef
->inst
,
707 "Failed to evaluate the 'match' expression.\n");
708 ctxt
->state
= XSLT_STATE_STOPPED
;
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
));
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
));
728 xsltTransformError(ctxt
, NULL
, keyDef
->inst
,
729 "The 'match' expression did not evaluate to a node set.\n");
730 ctxt
->state
= XSLT_STATE_STOPPED
;
734 if ((matchList
== NULL
) || (matchList
->nodeNr
<= 0))
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
)))))
751 * If the key was not previously defined, create it now and
752 * chain it to the list of keys for the doc
755 table
= xsltNewKeyTable(keyDef
->name
, keyDef
->nameURI
);
758 table
->next
= idoc
->keys
;
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
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
))
778 * Process the 'use' of the xsl:key.
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."
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
;
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]);
804 if (useRes
->type
== XPATH_STRING
) {
806 * Consume the string value.
808 str
= useRes
->stringval
;
809 useRes
->stringval
= NULL
;
811 str
= xmlXPathCastToString(useRes
);
815 * Process all strings.
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
));
827 keylist
= xmlHashLookup(table
->keys
, str
);
828 if (keylist
== NULL
) {
829 keylist
= xmlXPathNodeSetCreate(cur
);
832 if (xmlHashAddEntry(table
->keys
, str
, keylist
) < 0) {
833 xmlXPathFreeNodeSet(keylist
);
838 * TODO: How do we know if this function failed?
840 xmlXPathNodeSetAdd(keylist
, cur
);
842 xsltSetSourceNodeFlags(ctxt
, cur
, XSLT_SOURCE_NODE_HAS_KEY
);
850 str
= xmlXPathCastNodeToString(useRes
->nodesetval
->nodeTab
[k
]);
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
;
874 xmlXPathFreeObject(useRes
);
875 if (matchRes
!= NULL
)
876 xmlXPathFreeObject(matchRes
);
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.
890 xsltInitCtxtKeys(xsltTransformContextPtr ctxt
, xsltDocumentPtr idoc
) {
891 xsltStylesheetPtr style
;
892 xsltKeyDefPtr keyDef
;
894 if ((ctxt
== NULL
) || (idoc
== NULL
))
897 #ifdef KEY_INIT_DEBUG
898 fprintf(stderr
, "xsltInitCtxtKeys on document\n");
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",
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");
925 * xsltFreeDocumentKeys:
926 * @idoc: a XSLT document
928 * Free the keys associated to a document
931 xsltFreeDocumentKeys(xsltDocumentPtr idoc
) {
933 xsltFreeKeyTableList(idoc
->keys
);