Added more support for keys, nearly complete:
authorDaniel Veillard <veillard@src.gnome.org>
Thu, 8 Feb 2001 11:16:41 +0000 (11:16 +0000)
committerDaniel Veillard <veillard@src.gnome.org>
Thu, 8 Feb 2001 11:16:41 +0000 (11:16 +0000)
- FEATURES libxslt/xsltInternals.h libxslt/pattern.c libxslt/keys.c:
  added support for keys in patterns
- tests/REC/test-12.2-2.*: added a specific testcase
Daniel

ChangeLog
FEATURES
libxslt/keys.c
libxslt/pattern.c
libxslt/xsltInternals.h
tests/REC/test-12.2-2.out [new file with mode: 0644]
tests/REC/test-12.2-2.xml [new file with mode: 0644]
tests/REC/test-12.2-2.xsl [new file with mode: 0644]

index 683dcb4..f61b089 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+Thu Feb  8 12:09:58 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
+
+       * FEATURES libxslt/xsltInternals.h libxslt/pattern.c libxslt/keys.c:
+         added support for keys in patterns
+       * tests/REC/test-12.2-2.*: added a specific testcase
+
 Wed Feb  7 21:16:47 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
 
        * libxslt/functions.c FEATURES: started adding support for key()
index c7556d0..d094e8e 100644 (file)
--- a/FEATURES
+++ b/FEATURES
@@ -194,7 +194,7 @@ YES                         match="*|/"
 YES                            match="text()|@*"
 YES                            match="processing-instruction()|comment()"
 YES                            Namespace
-NO                             Mode
+YES                            Mode
 
 NO                         Extension Elements
 
@@ -238,6 +238,6 @@ YES                     item[position() mod 2 = 1]
 YES                        div[@class="appendix"]//p
 YES                        @class
 YES                        @*
-NO                         key('a','b')
+YES   except ns for key            key('a','b')
 
 Daniel.Veillard@imag.fr
index a25cceb..056204f 100644 (file)
@@ -272,6 +272,7 @@ xsltGetKey(xsltTransformContextPtr ctxt, const xmlChar *name,
            ret = (xmlNodeSetPtr)xmlHashLookup(table->keys, value);
            return(ret);
        }
+       table = table->next;
     }
     return(NULL);
 }
@@ -370,6 +371,7 @@ xsltInitCtxtKey(xsltTransformContextPtr ctxt, xsltKeyDefPtr keyd) {
            } else {
                xmlXPathNodeSetAdd(keylist, nodelist->nodeTab[i]);
            }
+           nodelist->nodeTab[i]->_private = keyd;
            xmlFree(str);
 #ifdef DEBUG_KEYS
        } else {
@@ -431,3 +433,24 @@ xsltFreeCtxtKeys(xsltTransformContextPtr ctxt) {
        xsltFreeKeyTableList((xsltKeyTablePtr) ctxt->keys);
 }
 
+/*
+ * xsltIsKey:
+ * @ctxt: an XSLT transformation context
+ * @node: a node
+ *
+ * Returns 1 if the node is a Key, 0 otherwise
+ */
+int
+xsltIsKey(xsltTransformContextPtr ctxt, xmlNodePtr node) {
+    if (node == NULL)
+       return(0);
+
+    /*
+     * TODO:
+     * Something a bit more complex may be needed if we want
+     * to be able to do similar things with IDs
+     */
+    if (node->_private != NULL)
+       return(1);
+    return(0);
+}
index 0bf79be..51e4c11 100644 (file)
@@ -24,6 +24,7 @@
 #include "xsltutils.h"
 #include "imports.h"
 #include "templates.h"
+#include "keys.h"
 #include "pattern.h"
 
 /* #define DEBUG_PARSING */
@@ -58,6 +59,7 @@ struct _xsltStepOp {
     xsltOp op;
     xmlChar *value;
     xmlChar *value2;
+    xmlChar *value3;
 };
 
 typedef struct _xsltCompMatch xsltCompMatch;
@@ -139,6 +141,8 @@ xsltFreeCompMatch(xsltCompMatchPtr comp) {
            xmlFree(op->value);
        if (op->value2 != NULL)
            xmlFree(op->value2);
+       if (op->value3 != NULL)
+           xmlFree(op->value3);
     }
     memset(comp, -1, sizeof(xsltCompMatch));
     xmlFree(comp);
@@ -442,9 +446,21 @@ xsltTestCompMatch(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,
                    return(0);
                break;
            }
-            case XSLT_OP_KEY:
-               TODO /* Handle Keys, might be done differently */
+            case XSLT_OP_KEY: {
+               xmlNodeSetPtr list;
+               int i;
+
+               list = xsltGetKey(ctxt, step->value,
+                                 step->value3, step->value2);
+               if (list == NULL)
+                   return(0);
+               for (i = 0;i < list->nodeNr;i++)
+                   if (list->nodeTab[i] == node)
+                       break;
+               if (i >= list->nodeNr)
+                   return(0);
                break;
+           }
             case XSLT_OP_NS:
                /* Namespace test */
                if (node->ns == NULL) {
@@ -761,6 +777,7 @@ xsltCompileIdKeyPattern(xsltParserContextPtr ctxt, xmlChar *name, int aid) {
            return;
        }
        NEXT;
+       /* TODO: support namespace in keys */
        PUSH(XSLT_OP_KEY, lit, lit2);
     } else if (xmlStrEqual(name, (const xmlChar *)"processing-instruction")) {
        NEXT;
@@ -1250,9 +1267,11 @@ next_pattern:
         case XSLT_OP_ROOT:
              top = (xsltCompMatchPtr *) &(style->rootMatch);
             break;
-        case XSLT_OP_ID:
         case XSLT_OP_KEY:
-            /* TODO optimize ID/KEY !!! */
+             top = (xsltCompMatchPtr *) &(style->keyMatch);
+            break;
+        case XSLT_OP_ID:
+            /* TODO optimize ID !!! */
         case XSLT_OP_ALL:
              top = (xsltCompMatchPtr *) &(style->elemMatch);
             break;
@@ -1487,6 +1506,19 @@ xsltGetTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node) {
            }
            list = list->next;
        }
+       if (node->_private != NULL) {
+           list = style->keyMatch;
+           while ((list != NULL) &&
+                  ((ret == NULL)  || (list->priority > ret->priority))) {
+               if (xsltTestCompMatch(ctxt, list, node,
+                                     ctxt->mode, ctxt->modeURI)) {
+                   ret = list->template;
+                   break;
+               }
+               list = list->next;
+           }
+       }
+
        if (ret != NULL)
            return(ret);
 
@@ -1512,6 +1544,8 @@ xsltFreeTemplateHashes(xsltStylesheetPtr style) {
                    (xmlHashDeallocator) xsltFreeCompMatchList);
     if (style->rootMatch != NULL)
         xsltFreeCompMatchList(style->rootMatch);
+    if (style->keyMatch != NULL)
+        xsltFreeCompMatchList(style->keyMatch);
     if (style->elemMatch != NULL)
         xsltFreeCompMatchList(style->elemMatch);
     if (style->attrMatch != NULL)
index 360d9c3..0989f4c 100644 (file)
@@ -116,6 +116,7 @@ struct _xsltStylesheet {
     void *templatesHash;       /* hash table or wherever compiled templates
                                   informations are stored */
     void *rootMatch;           /* template based on / */
+    void *keyMatch;            /* template based on key() */
     void *elemMatch;           /* template based on * */
     void *attrMatch;           /* template based on @* */
     void *parentMatch;         /* template based on .. */
diff --git a/tests/REC/test-12.2-2.out b/tests/REC/test-12.2-2.out
new file mode 100644 (file)
index 0000000..62ec6a4
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+
+  
+Success
+
+  
+
diff --git a/tests/REC/test-12.2-2.xml b/tests/REC/test-12.2-2.xml
new file mode 100644 (file)
index 0000000..b833b61
--- /dev/null
@@ -0,0 +1,4 @@
+<doc>
+  <div id="lookup"/>
+  <div id="unwanted"/>
+</doc>
diff --git a/tests/REC/test-12.2-2.xsl b/tests/REC/test-12.2-2.xsl
new file mode 100644 (file)
index 0000000..68d1299
--- /dev/null
@@ -0,0 +1,11 @@
+<xsl:stylesheet version="1.0"
+      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+      xmlns:fo="http://www.w3.org/1999/XSL/Format">
+
+<xsl:key name="idkey" match="div" use="@id"/>
+
+<xsl:template match="key('idkey','lookup')">
+Success
+</xsl:template>
+
+</xsl:stylesheet>