- FEATURES: updated - libxslt/Makefile.am libxslt/keys.[ch] libxslt/xslt.c
authorDaniel Veillard <veillard@src.gnome.org>
Wed, 7 Feb 2001 18:51:50 +0000 (18:51 +0000)
committerDaniel Veillard <veillard@src.gnome.org>
Wed, 7 Feb 2001 18:51:50 +0000 (18:51 +0000)
- FEATURES: updated
- libxslt/Makefile.am libxslt/keys.[ch] libxslt/xslt.c
  libxslt/transform.c libxslt/xsltInternals.h: started adding key
  support
- libxslt/xsltutils.c: warning cleanup
- libxslt/pattern.h: fixed soopid cut'n paste prob
Daniel

ChangeLog
FEATURES
libxslt/Makefile.am
libxslt/keys.c [new file with mode: 0644]
libxslt/keys.h [new file with mode: 0644]
libxslt/pattern.h
libxslt/transform.c
libxslt/variables.c
libxslt/xslt.c
libxslt/xsltInternals.h
libxslt/xsltutils.c

index 8fe8599..1f511c9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+Wed Feb  7 19:46:07 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
+
+       * FEATURES: updated
+       * libxslt/Makefile.am libxslt/keys.[ch] libxslt/xslt.c
+         libxslt/transform.c libxslt/xsltInternals.h: started adding key
+         support
+       * libxslt/xsltutils.c: warning cleanup
+       * libxslt/pattern.h: fixed soopid cut'n paste prob
+
 Tue Feb  6 10:56:38 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
 
        * libxslt/transform.c libxslt/xslt.c: chased some reported
index 35551ad..e36052c 100644 (file)
--- a/FEATURES
+++ b/FEATURES
@@ -63,10 +63,10 @@ YES                         name = qname
 YES                            select = expression
 YES                            Content: template
 
-NO                         xsl:key
-NO                             name = qname 
-NO                             match = pattern 
-NO                             use = expression
+YES                        xsl:key
+YES                            name = qname 
+YES                            match = pattern 
+YES                            use = expression
 
 YES                        xsl:output
 YES                            method = "xml" | "html" | "text" | qname-but-not-ncname 
@@ -238,5 +238,6 @@ YES                     item[position() mod 2 = 1]
 YES                        div[@class="appendix"]//p
 YES                        @class
 YES                        @*
+NO                         key('a','b')
 
 Daniel.Veillard@imag.fr
index 66f5960..d52b079 100644 (file)
@@ -11,6 +11,7 @@ xsltinc_HEADERS =                     \
        pattern.h                       \
        templates.h                     \
        variables.h                     \
+       keys.h                          \
        numbersInternals.h              \
        functions.h                     \
        namespaces.h                    \
@@ -25,6 +26,7 @@ libxslt_la_SOURCES =                  \
        pattern.c                       \
        templates.c                     \
        variables.c                     \
+       keys.c                          \
        numbers.c                       \
        functions.c                     \
        namespaces.c                    \
diff --git a/libxslt/keys.c b/libxslt/keys.c
new file mode 100644 (file)
index 0000000..a25cceb
--- /dev/null
@@ -0,0 +1,433 @@
+/*
+ * 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@imag.fr
+ */
+
+#include "xsltconfig.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"
+
+#define DEBUG_KEYS
+
+typedef struct _xsltKeyDef xsltKeyDef;
+typedef xsltKeyDef *xsltKeyDefPtr;
+struct _xsltKeyDef {
+    struct _xsltKeyDef *next;
+    xmlChar *name;
+    xmlChar *nameURI;
+    xmlChar *match;
+    xmlChar *use;
+};
+
+typedef struct _xsltKeyTable xsltKeyTable;
+typedef xsltKeyTable *xsltKeyTablePtr;
+struct _xsltKeyTable {
+    struct _xsltKeyTable *next;
+    xmlChar *name;
+    xmlChar *nameURI;
+    xmlHashTablePtr keys;
+};
+
+
+/************************************************************************
+ *                                                                     *
+ *                     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
+ */
+xsltKeyDefPtr
+xsltNewKeyDef(const xmlChar *name, const xmlChar *nameURI) {
+    xsltKeyDefPtr cur;
+
+    cur = (xsltKeyDefPtr) xmlMalloc(sizeof(xsltKeyDef));
+    if (cur == NULL) {
+        xsltGenericError(xsltGenericErrorContext,
+               "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);
+    return(cur);
+}
+
+/**
+ * xsltFreeKeyDef:
+ * @keyd:  an XSLT key definition
+ *
+ * Free up the memory allocated by @keyd
+ */
+void
+xsltFreeKeyDef(xsltKeyDefPtr keyd) {
+    if (keyd == NULL)
+       return;
+    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);
+    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
+ */
+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
+ */
+xsltKeyTablePtr
+xsltNewKeyTable(const xmlChar *name, const xmlChar *nameURI) {
+    xsltKeyTablePtr cur;
+
+    cur = (xsltKeyTablePtr) xmlMalloc(sizeof(xsltKeyTable));
+    if (cur == NULL) {
+        xsltGenericError(xsltGenericErrorContext,
+               "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
+ */
+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
+ */
+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);
+}
+
+/**
+ * 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
+ *
+ * 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) {
+    xsltKeyDefPtr key;
+
+    if ((style == NULL) || (name == NULL) || (match == NULL) || (use == NULL))
+       return(-1);
+
+#ifdef 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->next = style->keys;
+    style->keys = key;
+    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
+ *
+ * Lookup a key
+ *
+ * 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;
+
+    if ((ctxt == NULL) || (name == NULL) || (value == NULL))
+       return(NULL);
+
+#ifdef DEBUG_KEYS
+    xsltGenericDebug(xsltGenericDebugContext,
+       "Get key %s, value %s\n", name, value);
+#endif
+
+    table = (xsltKeyTablePtr) ctxt->keys;
+    while (table != NULL) {
+       if (xmlStrEqual(table->name, name) &&
+           (((nameURI == NULL) && (table->nameURI == NULL)) ||
+            ((nameURI != NULL) && (table->nameURI != NULL) &&
+             (xmlStrEqual(table->nameURI, nameURI))))) {
+           ret = (xmlNodeSetPtr)xmlHashLookup(table->keys, value);
+           return(ret);
+       }
+    }
+    return(NULL);
+}
+
+/**
+ * xsltInitCtxtKey:
+ * @ctxt: an XSLT transformation context
+ * @keyd: the key definition
+ *
+ * Computes the key tables this key and for the current input document.
+ */
+void
+xsltInitCtxtKey(xsltTransformContextPtr ctxt, xsltKeyDefPtr keyd) {
+    int i;
+    xmlChar *pattern = NULL;
+    xmlNodeSetPtr nodelist = NULL, keylist;
+    xmlXPathObjectPtr res, tmp;
+    xmlChar *str;
+    xmlXPathParserContextPtr xpathParserCtxt;
+    xsltKeyTablePtr table;
+
+    /*
+     * Prepare the search
+     */
+    if (keyd->match[0] != '/') {
+       pattern = xmlStrdup((xmlChar *)"//");
+       pattern = xmlStrcat(pattern, keyd->match);
+    } else {
+       pattern = xmlStrdup(keyd->match);
+    }
+
+    /*
+     * Evaluate the nodelist
+     */
+
+    xpathParserCtxt =
+       xmlXPathNewParserContext(pattern, ctxt->xpathCtxt);
+    if (xpathParserCtxt == NULL)
+       goto error;
+    ctxt->node = (xmlNodePtr) ctxt->doc;
+    ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->doc;
+    xmlXPathEvalExpr(xpathParserCtxt);
+    res = valuePop(xpathParserCtxt);
+    do {
+        tmp = valuePop(xpathParserCtxt);
+       if (tmp != NULL) {
+           xmlXPathFreeObject(tmp);
+       }
+    } while (tmp != NULL);
+    if (res != NULL) {
+       if (res->type == XPATH_NODESET) {
+           nodelist = res->nodesetval;
+#ifdef DEBUG_KEYS
+           xsltGenericDebug(xsltGenericDebugContext,
+                "xsltInitCtxtKey: %s evaluates to %d nodes\n",
+                            pattern, nodelist->nodeNr);
+#endif
+       } else {
+#ifdef DEBUG_KEYS
+           xsltGenericDebug(xsltGenericDebugContext,
+                "xsltInitCtxtKey: %s is not a node set\n", pattern);
+#endif
+           goto error;
+       }
+    } else {
+#ifdef DEBUG_KEYS
+       xsltGenericDebug(xsltGenericDebugContext,
+            "xsltInitCtxtKey: %s evaluation failed\n", pattern);
+#endif
+       goto error;
+    }
+
+    /*
+     * for each node in the list evaluate the key and insert the node
+     */
+    if ((nodelist == NULL) || (nodelist->nodeNr <= 0))
+       goto error;
+
+    table = xsltNewKeyTable(keyd->name, keyd->nameURI);
+    if (table == NULL)
+       goto error;
+
+    for (i = 0;i < nodelist->nodeNr;i++) {
+       ctxt->node = nodelist->nodeTab[i];
+       str = xsltEvalXPathString(ctxt, keyd->use);
+       if (str != NULL) {
+#ifdef DEBUG_KEYS
+           xsltGenericDebug(xsltGenericDebugContext,
+                "xsl:key : node associated to(%s,%s)\n",
+                            keyd->name, str);
+#endif
+           keylist = xmlHashLookup(table->keys, str);
+           if (keylist == NULL) {
+               keylist = xmlXPathNodeSetCreate(nodelist->nodeTab[i]);
+               xmlHashAddEntry(table->keys, str, keylist);
+           } else {
+               xmlXPathNodeSetAdd(keylist, nodelist->nodeTab[i]);
+           }
+           xmlFree(str);
+#ifdef DEBUG_KEYS
+       } else {
+           xsltGenericDebug(xsltGenericDebugContext,
+                "xsl:key : use %s failed to return a string\n",
+                            keyd->use);
+#endif
+       }
+    }
+
+    table->next = ctxt->keys;
+    ctxt->keys = table;
+
+error:
+    if (res != NULL)
+       xmlXPathFreeObject(res);
+    if (xpathParserCtxt != NULL)
+       xmlXPathFreeParserContext(xpathParserCtxt);
+    if (pattern != NULL)
+       xmlFree(pattern);
+}
+
+/**
+ * xsltInitCtxtKeys:
+ * @ctxt: an XSLT transformation context
+ *
+ * Computes all the keys tables for the current input document.
+ * Should be done before global varibales are initialized.
+ */
+void
+xsltInitCtxtKeys(xsltTransformContextPtr ctxt) {
+    xsltStylesheetPtr style;
+    xsltKeyDefPtr keyd;
+
+    if (ctxt == NULL)
+       return;
+    style = ctxt->style;
+    while (style != NULL) {
+       keyd = (xsltKeyDefPtr) style->keys;
+       while (keyd != NULL) {
+           xsltInitCtxtKey(ctxt, keyd);
+
+           keyd = keyd->next;
+       }
+
+       style = xsltNextImport(style);
+    }
+}
+
+/**
+ * xsltFreeCtxtKeys:
+ * @ctxt: an XSLT transformation context
+ *
+ * Free up all the space used by the key tables
+ */
+void   
+xsltFreeCtxtKeys(xsltTransformContextPtr ctxt) {
+    if (ctxt->keys)
+       xsltFreeKeyTableList((xsltKeyTablePtr) ctxt->keys);
+}
+
diff --git a/libxslt/keys.h b/libxslt/keys.h
new file mode 100644 (file)
index 0000000..8f0d7e5
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * key.h: interface for the key matching used in template matches.
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@imag.fr
+ */
+
+#ifndef __XML_XSLT_KEY_H__
+#define __XML_XSLT_KEY_H__
+
+#include "libxml/xpath.h"
+#include "xsltInternals.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int            xsltAddKey              (xsltStylesheetPtr style,
+                                        const xmlChar *name,
+                                        const xmlChar *nameURI,
+                                        const xmlChar *match,
+                                        const xmlChar *use);
+xmlNodeSetPtr  xsltGetKey              (xsltTransformContextPtr ctxt,
+                                        const xmlChar *name,
+                                        const xmlChar *nameURI,
+                                        const xmlChar *value);
+void           xsltInitCtxtKeys        (xsltTransformContextPtr ctxt);
+void           xsltFreeKeys            (xsltStylesheetPtr style);
+void           xsltFreeCtxtKeys        (xsltTransformContextPtr ctxt);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_XSLT_H__ */
+
index 946ff30..423f91c 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #ifndef __XML_XSLT_PATTERN_H__
-#define __XML_XSLT_H__
+#define __XML_XSLT_PATTERN_H__
 
 #include "xsltInternals.h"
 
@@ -26,5 +26,5 @@ void          xsltFreeTemplateHashes  (xsltStylesheetPtr style);
 }
 #endif
 
-#endif /* __XML_XSLT_H__ */
+#endif /* __XML_XSLT_PATTERN_H__ */
 
index ac8b79f..27fb015 100644 (file)
@@ -35,6 +35,7 @@
 #include "attributes.h"
 #include "templates.h"
 #include "imports.h"
+#include "keys.h"
 
 #define DEBUG_PROCESS
 
@@ -110,6 +111,7 @@ xsltFreeTransformContext(xsltTransformContextPtr ctxt) {
     if (ctxt->xpathCtxt != NULL)
        xmlXPathFreeContext(ctxt->xpathCtxt);
     xsltFreeVariableHashes(ctxt);
+    xsltFreeCtxtKeys(ctxt);
     memset(ctxt, -1, sizeof(xsltTransformContext));
     xmlFree(ctxt);
 }
@@ -1985,6 +1987,7 @@ xsltApplyStylesheet(xsltStylesheetPtr style, xmlDocPtr doc) {
     if (ctxt == NULL)
        return(NULL);
     ctxt->style = style;
+    xsltInitCtxtKeys(ctxt);
     xsltEvalGlobalVariables(ctxt);
     if ((style->method != NULL) &&
        (!xmlStrEqual(style->method, (const xmlChar *) "xml"))) {
index 0b0024e..006e92d 100644 (file)
@@ -26,6 +26,7 @@
 #include "xsltutils.h"
 #include "variables.h"
 #include "transform.h"
+#include "imports.h"
 
 #define DEBUG_VARIABLE
 
@@ -504,8 +505,7 @@ xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
     xsltStackElemPtr elem = NULL;
 
     style = ctxt->style;
-    /* TODO: handle the stylesheet cascade */
-    if (style != NULL) {
+    while (style != NULL) {
        elem = style->variables;
        
        while (elem != NULL) {
@@ -523,6 +523,8 @@ xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
            }
            elem = elem->next;
        }
+
+       style = xsltNextImport(style);
     }
     if (elem == NULL)
        return(NULL);
index 3cb60ba..8cfad6f 100644 (file)
@@ -29,6 +29,7 @@
 #include "attributes.h"
 #include "xsltutils.h"
 #include "imports.h"
+#include "keys.h"
 
 #define DEBUG_PARSING
 /* #define DEBUG_BLANKS */
@@ -280,6 +281,7 @@ xsltFreeStylesheet(xsltStylesheetPtr sheet) {
     if (sheet == NULL)
        return;
 
+    xsltFreeKeys(sheet);
     xsltFreeTemplateHashes(sheet);
     xsltFreeDecimalFormatList(sheet);
     xsltFreeTemplateList(sheet->templates);
@@ -898,6 +900,98 @@ skip_children:
 }
 
 /**
+ * xsltParseStylesheetKey:
+ * @style:  the XSLT stylesheet
+ * @key:  the "key" element
+ *
+ * parse an XSLT stylesheet key definition and register it
+ */
+
+void
+xsltParseStylesheetKey(xsltStylesheetPtr style, xmlNodePtr key) {
+    xmlChar *prop;
+    xmlChar *use;
+    xmlChar *match;
+    xmlChar *name;
+    xmlChar *nameURI;
+
+    if (key == NULL)
+       return;
+
+    /*
+     * Get arguments
+     */
+    prop = xmlGetNsProp(key, (const xmlChar *)"name", XSLT_NAMESPACE);
+    if (prop != NULL) {
+       xmlChar *prefix = NULL;
+
+       name = xmlSplitQName2(prop, &prefix);
+       if (name != NULL) {
+           if (prefix != NULL) {
+               xmlNsPtr ns;
+
+               ns = xmlSearchNs(key->doc, key, prefix);
+               if (ns == NULL) {
+                   xsltGenericError(xsltGenericErrorContext,
+                       "no namespace bound to prefix %s\n", prefix);
+                   xmlFree(prefix);
+                   xmlFree(name);
+                   name = prop;
+                   nameURI = NULL;
+               } else {
+                   nameURI = xmlStrdup(ns->href);
+                   xmlFree(prefix);
+                   xmlFree(prop);
+               }
+           } else {
+               xmlFree(prop);
+               nameURI = NULL;
+           }
+       } else {
+           name = prop;
+           nameURI = NULL;
+       }
+#ifdef DEBUG_PARSING
+       xsltGenericDebug(xsltGenericDebugContext,
+            "xslt:key: name %s\n", name);
+#endif
+    } else {
+       xsltGenericError(xsltGenericErrorContext,
+           "xsl:key : error missing name\n");
+       goto error;
+    }
+
+    match = xmlGetNsProp(key, (const xmlChar *)"match", XSLT_NAMESPACE);
+    if (match == NULL) {
+       xsltGenericError(xsltGenericErrorContext,
+           "xsl:key : error missing match\n");
+       goto error;
+    }
+
+    use = xmlGetNsProp(key, (const xmlChar *)"use", XSLT_NAMESPACE);
+    if (use == NULL) {
+       xsltGenericError(xsltGenericErrorContext,
+           "xsl:key : error missing use\n");
+       goto error;
+    }
+
+    /*
+     * register the key
+     */
+    xsltAddKey(style, name, nameURI, match, use);
+
+error:
+    if (use != NULL)
+       xmlFree(use);
+    if (match != NULL)
+       xmlFree(match);
+    if (name != NULL)
+       xmlFree(name);
+    if (nameURI != NULL)
+       xmlFree(nameURI);
+}
+
+/**
  * xsltParseStylesheetTemplate:
  * @style:  the XSLT stylesheet
  * @template:  the "template" element
@@ -1096,7 +1190,7 @@ xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) {
         } else if (IS_XSLT_NAME(cur, "output")) {
            xsltParseStylesheetOutput(style, cur);
         } else if (IS_XSLT_NAME(cur, "key")) {
-           TODO /* Handle key */
+           xsltParseStylesheetKey(style, cur);
         } else if (IS_XSLT_NAME(cur, "decimal-format")) {
            xsltParseStylesheetDecimalFormat(style, cur);
         } else if (IS_XSLT_NAME(cur, "attribute-set")) {
index 1cd6ce5..360d9c3 100644 (file)
@@ -134,6 +134,11 @@ struct _xsltStylesheet {
     xmlHashTablePtr attributeSets;/* the attribute sets hash tables */
 
     /*
+     * Key definitions
+     */
+    void *keys;                                /* key definitions */
+
+    /*
      * Output related stuff.
      */
     xmlChar *method;           /* the output method */
@@ -186,6 +191,7 @@ struct _xsltTransformContext {
     xmlXPathContextPtr xpathCtxt;      /* the XPath context */
     void *variablesHash;               /* hash table or wherever variables
                                           informations are stored */
+    void *keys;                                /* key tables storage */
     xmlDocPtr extraDocs;               /* extra docs parsed by document() */
     xsltTransformState state;          /* the current state */
 };
index 0ae7caa..a117032 100644 (file)
@@ -380,7 +380,8 @@ xsltSaveResultToFilename(const char *URL, xmlDocPtr result,
 
        encoder = xmlFindCharEncodingHandler((char *)style->encoding);
        if ((encoder != NULL) &&
-           (xmlStrEqual(encoder->name, (const xmlChar *) "UTF-8")))
+           (xmlStrEqual((const xmlChar *)encoder->name,
+                        (const xmlChar *) "UTF-8")))
            encoder = NULL;
        buf = xmlOutputBufferCreateFilename(URL, encoder, compression);
     } else {
@@ -418,7 +419,8 @@ xsltSaveResultToFile(FILE *file, xmlDocPtr result, xsltStylesheetPtr style) {
 
        encoder = xmlFindCharEncodingHandler((char *)style->encoding);
        if ((encoder != NULL) &&
-           (xmlStrEqual(encoder->name, (const xmlChar *) "UTF-8")))
+           (xmlStrEqual((const xmlChar *)encoder->name,
+                        (const xmlChar *) "UTF-8")))
            encoder = NULL;
        buf = xmlOutputBufferCreateFile(file, encoder);
     } else {
@@ -457,7 +459,8 @@ xsltSaveResultToFd(int fd, xmlDocPtr result, xsltStylesheetPtr style) {
 
        encoder = xmlFindCharEncodingHandler((char *)style->encoding);
        if ((encoder != NULL) &&
-           (xmlStrEqual(encoder->name, (const xmlChar *) "UTF-8")))
+           (xmlStrEqual((const xmlChar *)encoder->name,
+                        (const xmlChar *) "UTF-8")))
            encoder = NULL;
        buf = xmlOutputBufferCreateFd(fd, encoder);
     } else {