/** * 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); } }
/** * 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; key = NULL; error: if (pattern != NULL) xmlFree(pattern); if (key != NULL) xsltFreeKeyDef(key); return(0); }