blob: d28aea67999c5ded0237f5c40d6bb4c85d34573c [file] [log] [blame]
/*
* keys.c: Implemetation of the keys support
*
* Reference:
* http://www.w3.org/TR/1999/REC-xslt-19991116
*
* See Copyright for the status of this software.
*
* daniel@veillard.com
*/
#define IN_LIBXSLT
#include "libxslt.h"
#include <string.h>
#include <libxml/xmlmemory.h>
#include <libxml/tree.h>
#include <libxml/valid.h>
#include <libxml/hash.h>
#include <libxml/xmlerror.h>
#include <libxml/parserInternals.h>
#include <libxml/xpathInternals.h>
#include "xslt.h"
#include "xsltInternals.h"
#include "xsltutils.h"
#include "imports.h"
#include "templates.h"
#include "keys.h"
#ifdef WITH_XSLT_DEBUG
#define WITH_XSLT_DEBUG_KEYS
#endif
static int
xsltInitDocKeyTable(xsltTransformContextPtr ctxt, const xmlChar *name,
const xmlChar *nameURI);
/************************************************************************
* *
* Type functions *
* *
************************************************************************/
/**
* xsltNewKeyDef:
* @name: the key name or NULL
* @nameURI: the name URI or NULL
*
* Create a new XSLT KeyDef
*
* Returns the newly allocated xsltKeyDefPtr or NULL in case of error
*/
static xsltKeyDefPtr
xsltNewKeyDef(const xmlChar *name, const xmlChar *nameURI) {
xsltKeyDefPtr cur;
cur = (xsltKeyDefPtr) xmlMalloc(sizeof(xsltKeyDef));
if (cur == NULL) {
xsltTransformError(NULL, NULL, NULL,
"xsltNewKeyDef : malloc failed\n");
return(NULL);
}
memset(cur, 0, sizeof(xsltKeyDef));
if (name != NULL)
cur->name = xmlStrdup(name);
if (nameURI != NULL)
cur->nameURI = xmlStrdup(nameURI);
cur->nsList = NULL;
return(cur);
}
/**
* xsltFreeKeyDef:
* @keyd: an XSLT key definition
*
* Free up the memory allocated by @keyd
*/
static void
xsltFreeKeyDef(xsltKeyDefPtr keyd) {
if (keyd == NULL)
return;
if (keyd->comp != NULL)
xmlXPathFreeCompExpr(keyd->comp);
if (keyd->usecomp != NULL)
xmlXPathFreeCompExpr(keyd->usecomp);
if (keyd->name != NULL)
xmlFree(keyd->name);
if (keyd->nameURI != NULL)
xmlFree(keyd->nameURI);
if (keyd->match != NULL)
xmlFree(keyd->match);
if (keyd->use != NULL)
xmlFree(keyd->use);
if (keyd->nsList != NULL)
xmlFree(keyd->nsList);
memset(keyd, -1, sizeof(xsltKeyDef));
xmlFree(keyd);
}
/**
* xsltFreeKeyDefList:
* @keyd: an XSLT key definition list
*
* Free up the memory allocated by all the elements of @keyd
*/
static void
xsltFreeKeyDefList(xsltKeyDefPtr keyd) {
xsltKeyDefPtr cur;
while (keyd != NULL) {
cur = keyd;
keyd = keyd->next;
xsltFreeKeyDef(cur);
}
}
/**
* xsltNewKeyTable:
* @name: the key name or NULL
* @nameURI: the name URI or NULL
*
* Create a new XSLT KeyTable
*
* Returns the newly allocated xsltKeyTablePtr or NULL in case of error
*/
static xsltKeyTablePtr
xsltNewKeyTable(const xmlChar *name, const xmlChar *nameURI) {
xsltKeyTablePtr cur;
cur = (xsltKeyTablePtr) xmlMalloc(sizeof(xsltKeyTable));
if (cur == NULL) {
xsltTransformError(NULL, NULL, NULL,
"xsltNewKeyTable : malloc failed\n");
return(NULL);
}
memset(cur, 0, sizeof(xsltKeyTable));
if (name != NULL)
cur->name = xmlStrdup(name);
if (nameURI != NULL)
cur->nameURI = xmlStrdup(nameURI);
cur->keys = xmlHashCreate(0);
return(cur);
}
/**
* xsltFreeKeyTable:
* @keyt: an XSLT key table
*
* Free up the memory allocated by @keyt
*/
static void
xsltFreeKeyTable(xsltKeyTablePtr keyt) {
if (keyt == NULL)
return;
if (keyt->name != NULL)
xmlFree(keyt->name);
if (keyt->nameURI != NULL)
xmlFree(keyt->nameURI);
if (keyt->keys != NULL)
xmlHashFree(keyt->keys,
(xmlHashDeallocator) xmlXPathFreeNodeSet);
memset(keyt, -1, sizeof(xsltKeyTable));
xmlFree(keyt);
}
/**
* xsltFreeKeyTableList:
* @keyt: an XSLT key table list
*
* Free up the memory allocated by all the elements of @keyt
*/
static void
xsltFreeKeyTableList(xsltKeyTablePtr keyt) {
xsltKeyTablePtr cur;
while (keyt != NULL) {
cur = keyt;
keyt = keyt->next;
xsltFreeKeyTable(cur);
}
}
/************************************************************************
* *
* The interpreter for the precompiled patterns *
* *
************************************************************************/
/**
* xsltFreeKeys:
* @style: an XSLT stylesheet
*
* Free up the memory used by XSLT keys in a stylesheet
*/
void
xsltFreeKeys(xsltStylesheetPtr style) {
if (style->keys)
xsltFreeKeyDefList((xsltKeyDefPtr) style->keys);
}
/**
* skipString:
* @cur: the current pointer
* @end: the current offset
*
* skip a string delimited by " or '
*
* Returns the byte after the string or -1 in case of error
*/
static int
skipString(const xmlChar *cur, int end) {
xmlChar limit;
if ((cur == NULL) || (end < 0)) return(-1);
if ((cur[end] == '\'') || (cur[end] == '"')) limit = cur[end];
else return(end);
end++;
while (cur[end] != 0) {
if (cur[end] == limit)
return(end + 1);
end++;
}
return(-1);
}
/**
* skipPredicate:
* @cur: the current pointer
* @end: the current offset
*
* skip a predicate
*
* Returns the byte after the predicate or -1 in case of error
*/
static int
skipPredicate(const xmlChar *cur, int end) {
if ((cur == NULL) || (end < 0)) return(-1);
if (cur[end] != '[') return(end);
end++;
while (cur[end] != 0) {
if ((cur[end] == '\'') || (cur[end] == '"')) {
end = skipString(cur, end);
if (end <= 0)
return(-1);
continue;
} else if (cur[end] == '[') {
end = skipPredicate(cur, end);
if (end <= 0)
return(-1);
continue;
} else if (cur[end] == ']')
return(end + 1);
end++;
}
return(-1);
}
/**
* xsltAddKey:
* @style: an XSLT stylesheet
* @name: the key name or NULL
* @nameURI: the name URI or NULL
* @match: the match value
* @use: the use value
* @inst: the key instruction
*
* add a key definition to a stylesheet
*
* Returns 0 in case of success, and -1 in case of failure.
*/
int
xsltAddKey(xsltStylesheetPtr style, const xmlChar *name,
const xmlChar *nameURI, const xmlChar *match,
const xmlChar *use, xmlNodePtr inst) {
xsltKeyDefPtr key;
xmlChar *pattern = NULL;
int current, end, start, i = 0;
if ((style == NULL) || (name == NULL) || (match == NULL) || (use == NULL))
return(-1);
#ifdef WITH_XSLT_DEBUG_KEYS
xsltGenericDebug(xsltGenericDebugContext,
"Add key %s, match %s, use %s\n", name, match, use);
#endif
key = xsltNewKeyDef(name, nameURI);
key->match = xmlStrdup(match);
key->use = xmlStrdup(use);
key->inst = inst;
key->nsList = xmlGetNsList(inst->doc, inst);
if (key->nsList != NULL) {
while (key->nsList[i] != NULL)
i++;
}
key->nsNr = i;
/*
* Split the | and register it as as many keys
*/
current = end = 0;
while (match[current] != 0) {
start = current;
while (IS_BLANK_CH(match[current]))
current++;
end = current;
while ((match[end] != 0) && (match[end] != '|')) {
if (match[end] == '[') {
end = skipPredicate(match, end);
if (end <= 0) {
xsltTransformError(NULL, style, inst,
"key pattern is malformed: %s",
key->match);
if (style != NULL) style->errors++;
goto error;
}
} else
end++;
}
if (current == end) {
xsltTransformError(NULL, style, inst,
"key pattern is empty\n");
if (style != NULL) style->errors++;
goto error;
}
if (match[start] != '/') {
pattern = xmlStrcat(pattern, (xmlChar *)"//");
if (pattern == NULL) {
if (style != NULL) style->errors++;
goto error;
}
}
pattern = xmlStrncat(pattern, &match[start], end - start);
if (pattern == NULL) {
if (style != NULL) style->errors++;
goto error;
}
if (match[end] == '|') {
pattern = xmlStrcat(pattern, (xmlChar *)"|");
end++;
}
current = end;
}
#ifdef WITH_XSLT_DEBUG_KEYS
xsltGenericDebug(xsltGenericDebugContext,
" resulting pattern %s\n", pattern);
#endif
/*
* XSLT-1: "It is an error for the value of either the use
* attribute or the match attribute to contain a
* VariableReference."
* TODO: We should report a variable-reference at compile-time.
* Maybe a search for "$", if it occurs outside of quotation
* marks, could be sufficient.
*/
key->comp = xsltXPathCompile(style, pattern);
if (key->comp == NULL) {
xsltTransformError(NULL, style, inst,
"xsl:key : XPath pattern compilation failed '%s'\n",
pattern);
if (style != NULL) style->errors++;
}
key->usecomp = xsltXPathCompile(style, use);
if (key->usecomp == NULL) {
xsltTransformError(NULL, style, inst,
"xsl:key : XPath pattern compilation failed '%s'\n",
use);
if (style != NULL) style->errors++;
}
/*
* Sometimes the stylesheet writer use the order to ease the
* resolution of keys when they are dependant, keep the provided
* order so add the new one at the end.
*/
if (style->keys == NULL) {
style->keys = key;
} else {
xsltKeyDefPtr prev = style->keys;
while (prev->next != NULL)
prev = prev->next;
prev->next = key;
}
key->next = NULL;
error:
if (pattern != NULL)
xmlFree(pattern);
return(0);
}
/**
* xsltGetKey:
* @ctxt: an XSLT transformation context
* @name: the key name or NULL
* @nameURI: the name URI or NULL
* @value: the key value to look for
*
* Looks up a key of the in current source doc (the document info
* on @ctxt->document). Computes the key if not already done
* for the current source doc.
*
* Returns the nodeset resulting from the query or NULL
*/
xmlNodeSetPtr
xsltGetKey(xsltTransformContextPtr ctxt, const xmlChar *name,
const xmlChar *nameURI, const xmlChar *value) {
xmlNodeSetPtr ret;
xsltKeyTablePtr table;
int init_table = 0;
if ((ctxt == NULL) || (name == NULL) || (value == NULL) ||
(ctxt->document == NULL))
return(NULL);
#ifdef WITH_XSLT_DEBUG_KEYS
xsltGenericDebug(xsltGenericDebugContext,
"Get key %s, value %s\n", name, value);
#endif
/*
* keys are computed only on-demand on first key access for a document
*/
if ((ctxt->document->nbKeysComputed < ctxt->nbKeys) &&
(ctxt->keyInitLevel == 0)) {
/*
* If non-recursive behaviour, just try to initialize all keys
*/
if (xsltInitAllDocKeys(ctxt))
return(NULL);
}
retry:
table = (xsltKeyTablePtr) ctxt->document->keys;
while (table != NULL) {
if (((nameURI != NULL) == (table->nameURI != NULL)) &&
xmlStrEqual(table->name, name) &&
xmlStrEqual(table->nameURI, nameURI))
{
ret = (xmlNodeSetPtr)xmlHashLookup(table->keys, value);
return(ret);
}
table = table->next;
}
if ((ctxt->keyInitLevel != 0) && (init_table == 0)) {
/*
* Apparently one key is recursive and this one is needed,
* initialize just it, that time and retry
*/
xsltInitDocKeyTable(ctxt, name, nameURI);
init_table = 1;
goto retry;
}
return(NULL);
}
/**
* xsltInitDocKeyTable:
*
* INTERNAL ROUTINE ONLY
*
* Check if any keys on the current document need to be computed
*/
static int
xsltInitDocKeyTable(xsltTransformContextPtr ctxt, const xmlChar *name,
const xmlChar *nameURI)
{
xsltStylesheetPtr style;
xsltKeyDefPtr keyd = NULL;
int found = 0;
#ifdef KEY_INIT_DEBUG
fprintf(stderr, "xsltInitDocKeyTable %s\n", name);
#endif
style = ctxt->style;
while (style != NULL) {
keyd = (xsltKeyDefPtr) style->keys;
while (keyd != NULL) {
if (((keyd->nameURI != NULL) ==
(nameURI != NULL)) &&
xmlStrEqual(keyd->name, name) &&
xmlStrEqual(keyd->nameURI, nameURI))
{
xsltInitCtxtKey(ctxt, ctxt->document, keyd);
if (ctxt->document->nbKeysComputed == ctxt->nbKeys)
return(0);
found = 1;
}
keyd = keyd->next;
}
style = xsltNextImport(style);
}
if (found == 0) {
#ifdef WITH_XSLT_DEBUG_KEYS
XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,
"xsltInitDocKeyTable: did not found %s\n", name));
#endif
xsltTransformError(ctxt, NULL, keyd? keyd->inst : NULL,
"Failed to find key definition for %s\n", name);
ctxt->state = XSLT_STATE_STOPPED;
return(-1);
}
#ifdef KEY_INIT_DEBUG
fprintf(stderr, "xsltInitDocKeyTable %s done\n", name);
#endif
return(0);
}
/**
* xsltInitAllDocKeys:
* @ctxt: transformation context
*
* INTERNAL ROUTINE ONLY
*
* Check if any keys on the current document need to be computed
*
* Returns 0 in case of success, -1 in case of failure
*/
int
xsltInitAllDocKeys(xsltTransformContextPtr ctxt)
{
xsltStylesheetPtr style;
xsltKeyDefPtr keyd;
xsltKeyTablePtr table;
if (ctxt == NULL)
return(-1);
#ifdef KEY_INIT_DEBUG
fprintf(stderr, "xsltInitAllDocKeys %d %d\n",
ctxt->document->nbKeysComputed, ctxt->nbKeys);
#endif
if (ctxt->document->nbKeysComputed == ctxt->nbKeys)
return(0);
/*
* TODO: This could be further optimized
*/
style = ctxt->style;
while (style) {
keyd = (xsltKeyDefPtr) style->keys;
while (keyd != NULL) {
#ifdef KEY_INIT_DEBUG
fprintf(stderr, "Init key %s\n", keyd->name);
#endif
/*
* Check if keys with this QName have been already
* computed.
*/
table = (xsltKeyTablePtr) ctxt->document->keys;
while (table) {
if (((keyd->nameURI != NULL) == (table->nameURI != NULL)) &&
xmlStrEqual(keyd->name, table->name) &&
xmlStrEqual(keyd->nameURI, table->nameURI))
{
break;
}
table = table->next;
}
if (table == NULL) {
/*
* Keys with this QName have not been yet computed.
*/
xsltInitDocKeyTable(ctxt, keyd->name, keyd->nameURI);
}
keyd = keyd->next;
}
style = xsltNextImport(style);
}
#ifdef KEY_INIT_DEBUG
fprintf(stderr, "xsltInitAllDocKeys: done\n");
#endif
return(0);
}
/**
* xsltInitCtxtKey:
* @ctxt: an XSLT transformation context
* @idoc: the document information (holds key values)
* @keyDef: the key definition
*
* Computes the key tables this key and for the current input document.
*
* Returns: 0 on success, -1 on error
*/
int
xsltInitCtxtKey(xsltTransformContextPtr ctxt, xsltDocumentPtr idoc,
xsltKeyDefPtr keyDef)
{
int i, len, k;
xmlNodeSetPtr matchList = NULL, keylist;
xmlXPathObjectPtr matchRes = NULL, useRes = NULL;
xmlChar *str = NULL;
xsltKeyTablePtr table;
xmlNodePtr oldInst, cur;
xmlNodePtr oldContextNode;
xsltDocumentPtr oldDocInfo;
int oldXPPos, oldXPSize;
xmlDocPtr oldXPDoc;
int oldXPNsNr;
xmlNsPtr *oldXPNamespaces;
xmlXPathContextPtr xpctxt;
#ifdef KEY_INIT_DEBUG
fprintf(stderr, "xsltInitCtxtKey %s : %d\n", keyDef->name, ctxt->keyInitLevel);
#endif
if ((keyDef->comp == NULL) || (keyDef->usecomp == NULL))
return(-1);
/*
* Detect recursive keys
*/
if (ctxt->keyInitLevel > ctxt->nbKeys) {
#ifdef WITH_XSLT_DEBUG_KEYS
XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,
xsltGenericDebug(xsltGenericDebugContext,
"xsltInitCtxtKey: key definition of %s is recursive\n",
keyDef->name));
#endif
xsltTransformError(ctxt, NULL, keyDef->inst,
"Key definition for %s is recursive\n", keyDef->name);
ctxt->state = XSLT_STATE_STOPPED;
return(-1);
}
ctxt->keyInitLevel++;
xpctxt = ctxt->xpathCtxt;
idoc->nbKeysComputed++;
/*
* Save context state.
*/
oldInst = ctxt->inst;
oldDocInfo = ctxt->document;
oldContextNode = ctxt->node;
oldXPDoc = xpctxt->doc;
oldXPPos = xpctxt->proximityPosition;
oldXPSize = xpctxt->contextSize;
oldXPNsNr = xpctxt->nsNr;
oldXPNamespaces = xpctxt->namespaces;
/*
* Set up contexts.
*/
ctxt->document = idoc;
ctxt->node = (xmlNodePtr) idoc->doc;
ctxt->inst = keyDef->inst;
xpctxt->doc = idoc->doc;
xpctxt->node = (xmlNodePtr) idoc->doc;
/* TODO : clarify the use of namespaces in keys evaluation */
xpctxt->namespaces = keyDef->nsList;
xpctxt->nsNr = keyDef->nsNr;
/*
* Evaluate the 'match' expression of the xsl:key.
* TODO: The 'match' is a *pattern*.
*/
matchRes = xmlXPathCompiledEval(keyDef->comp, xpctxt);
if (matchRes == NULL) {
#ifdef WITH_XSLT_DEBUG_KEYS
XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,
"xsltInitCtxtKey: %s evaluation failed\n", keyDef->match));
#endif
xsltTransformError(ctxt, NULL, keyDef->inst,
"Failed to evaluate the 'match' expression.\n");
ctxt->state = XSLT_STATE_STOPPED;
goto error;
} else {
if (matchRes->type == XPATH_NODESET) {
matchList = matchRes->nodesetval;
#ifdef WITH_XSLT_DEBUG_KEYS
if (matchList != NULL)
XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,
"xsltInitCtxtKey: %s evaluates to %d nodes\n",
keyDef->match, matchList->nodeNr));
#endif
} else {
/*
* Is not a node set, but must be.
*/
#ifdef WITH_XSLT_DEBUG_KEYS
XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,
"xsltInitCtxtKey: %s is not a node set\n", keyDef->match));
#endif
xsltTransformError(ctxt, NULL, keyDef->inst,
"The 'match' expression did not evaluate to a node set.\n");
ctxt->state = XSLT_STATE_STOPPED;
goto error;
}
}
if ((matchList == NULL) || (matchList->nodeNr <= 0))
goto exit;
/**
* Multiple key definitions for the same name are allowed, so
* we must check if the key is already present for this doc
*/
table = (xsltKeyTablePtr) idoc->keys;
while (table != NULL) {
if (xmlStrEqual(table->name, keyDef->name) &&
(((keyDef->nameURI == NULL) && (table->nameURI == NULL)) ||
((keyDef->nameURI != NULL) && (table->nameURI != NULL) &&
(xmlStrEqual(table->nameURI, keyDef->nameURI)))))
break;
table = table->next;
}
/**
* If the key was not previously defined, create it now and
* chain it to the list of keys for the doc
*/
if (table == NULL) {
table = xsltNewKeyTable(keyDef->name, keyDef->nameURI);
if (table == NULL)
goto error;
table->next = idoc->keys;
idoc->keys = table;
}
/*
* SPEC XSLT 1.0 (XSLT 2.0 does not clarify the context size!)
* "...the use attribute of the xsl:key element is evaluated with x as
" the current node and with a node list containing just x as the
* current node list"
*/
xpctxt->contextSize = 1;
xpctxt->proximityPosition = 1;
for (i = 0; i < matchList->nodeNr; i++) {
cur = matchList->nodeTab[i];
if (! IS_XSLT_REAL_NODE(cur))
continue;
xpctxt->node = cur;
/*
* Process the 'use' of the xsl:key.
* SPEC XSLT 1.0:
* "The use attribute is an expression specifying the values of
* the key; the expression is evaluated once for each node that
* matches the pattern."
*/
if (useRes != NULL)
xmlXPathFreeObject(useRes);
useRes = xmlXPathCompiledEval(keyDef->usecomp, xpctxt);
if (useRes == NULL) {
xsltTransformError(ctxt, NULL, keyDef->inst,
"Failed to evaluate the 'use' expression.\n");
ctxt->state = XSLT_STATE_STOPPED;
break;
}
if (useRes->type == XPATH_NODESET) {
if ((useRes->nodesetval != NULL) &&
(useRes->nodesetval->nodeNr != 0))
{
len = useRes->nodesetval->nodeNr;
str = xmlXPathCastNodeToString(useRes->nodesetval->nodeTab[0]);
} else {
continue;
}
} else {
len = 1;
if (useRes->type == XPATH_STRING) {
/*
* Consume the string value.
*/
str = useRes->stringval;
useRes->stringval = NULL;
} else {
str = xmlXPathCastToString(useRes);
}
}
/*
* Process all strings.
*/
k = 0;
while (1) {
if (str == NULL)
goto next_string;
#ifdef WITH_XSLT_DEBUG_KEYS
XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,
"xsl:key : node associated to ('%s', '%s')\n", keyDef->name, str));
#endif
keylist = xmlHashLookup(table->keys, str);
if (keylist == NULL) {
keylist = xmlXPathNodeSetCreate(cur);
if (keylist == NULL)
goto error;
xmlHashAddEntry(table->keys, str, keylist);
} else {
/*
* TODO: How do we know if this function failed?
*/
xmlXPathNodeSetAdd(keylist, cur);
}
switch (cur->type) {
case XML_ELEMENT_NODE:
case XML_TEXT_NODE:
case XML_CDATA_SECTION_NODE:
case XML_PI_NODE:
case XML_COMMENT_NODE:
cur->psvi = keyDef;
break;
case XML_ATTRIBUTE_NODE:
((xmlAttrPtr) cur)->psvi = keyDef;
break;
case XML_DOCUMENT_NODE:
case XML_HTML_DOCUMENT_NODE:
((xmlDocPtr) cur)->psvi = keyDef;
break;
default:
break;
}
xmlFree(str);
str = NULL;
next_string:
k++;
if (k >= len)
break;
str = xmlXPathCastNodeToString(useRes->nodesetval->nodeTab[k]);
}
}
exit:
error:
ctxt->keyInitLevel--;
/*
* Restore context state.
*/
xpctxt->doc = oldXPDoc;
xpctxt->nsNr = oldXPNsNr;
xpctxt->namespaces = oldXPNamespaces;
xpctxt->proximityPosition = oldXPPos;
xpctxt->contextSize = oldXPSize;
ctxt->node = oldContextNode;
ctxt->document = oldDocInfo;
ctxt->inst = oldInst;
if (str)
xmlFree(str);
if (useRes != NULL)
xmlXPathFreeObject(useRes);
if (matchRes != NULL)
xmlXPathFreeObject(matchRes);
return(0);
}
/**
* xsltInitCtxtKeys:
* @ctxt: an XSLT transformation context
* @idoc: a document info
*
* Computes all the keys tables for the current input document.
* Should be done before global varibales are initialized.
* NOTE: Not used anymore in the refactored code.
*/
void
xsltInitCtxtKeys(xsltTransformContextPtr ctxt, xsltDocumentPtr idoc) {
xsltStylesheetPtr style;
xsltKeyDefPtr keyDef;
if ((ctxt == NULL) || (idoc == NULL))
return;
#ifdef KEY_INIT_DEBUG
fprintf(stderr, "xsltInitCtxtKeys on document\n");
#endif
#ifdef WITH_XSLT_DEBUG_KEYS
if ((idoc->doc != NULL) && (idoc->doc->URL != NULL))
XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext, "Initializing keys on %s\n",
idoc->doc->URL));
#endif
style = ctxt->style;
while (style != NULL) {
keyDef = (xsltKeyDefPtr) style->keys;
while (keyDef != NULL) {
xsltInitCtxtKey(ctxt, idoc, keyDef);
keyDef = keyDef->next;
}
style = xsltNextImport(style);
}
#ifdef KEY_INIT_DEBUG
fprintf(stderr, "xsltInitCtxtKeys on document: done\n");
#endif
}
/**
* xsltFreeDocumentKeys:
* @idoc: a XSLT document
*
* Free the keys associated to a document
*/
void
xsltFreeDocumentKeys(xsltDocumentPtr idoc) {
if (idoc != NULL)
xsltFreeKeyTableList(idoc->keys);
}