| Index: third_party/libxslt/libxslt/keys.c
|
| diff --git a/third_party/libxslt/libxslt/keys.c b/third_party/libxslt/libxslt/keys.c
|
| deleted file mode 100644
|
| index 43a343eb2c0ca4fb423e6cb1fcc775a7fd0e00b5..0000000000000000000000000000000000000000
|
| --- a/third_party/libxslt/libxslt/keys.c
|
| +++ /dev/null
|
| @@ -1,935 +0,0 @@
|
| -/*
|
| - * 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 <libxml/xpath.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,
|
| - "xsl:key : 'match' pattern is malformed: %s",
|
| - key->match);
|
| - if (style != NULL) style->errors++;
|
| - goto error;
|
| - }
|
| - } else
|
| - end++;
|
| - }
|
| - if (current == end) {
|
| - xsltTransformError(NULL, style, inst,
|
| - "xsl:key : 'match' 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;
|
| - }
|
| - if (pattern == NULL) {
|
| - xsltTransformError(NULL, style, inst,
|
| - "xsl:key : 'match' pattern is empty\n");
|
| - if (style != NULL) style->errors++;
|
| - goto error;
|
| - }
|
| -#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.
|
| - */
|
| -#ifdef XML_XPATH_NOVAR
|
| - key->comp = xsltXPathCompileFlags(style, pattern, XML_XPATH_NOVAR);
|
| -#else
|
| - key->comp = xsltXPathCompile(style, pattern);
|
| -#endif
|
| - if (key->comp == NULL) {
|
| - xsltTransformError(NULL, style, inst,
|
| - "xsl:key : 'match' pattern compilation failed '%s'\n",
|
| - pattern);
|
| - if (style != NULL) style->errors++;
|
| - }
|
| -#ifdef XML_XPATH_NOVAR
|
| - key->usecomp = xsltXPathCompileFlags(style, use, XML_XPATH_NOVAR);
|
| -#else
|
| - key->usecomp = xsltXPathCompile(style, use);
|
| -#endif
|
| - if (key->usecomp == NULL) {
|
| - xsltTransformError(NULL, style, inst,
|
| - "xsl:key : 'use' expression 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;
|
| - ctxt->node = cur;
|
| - 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);
|
| -}
|
| -
|
|
|