Hacking on namespaces support:
authorDaniel Veillard <veillard@src.gnome.org>
Mon, 19 Feb 2001 15:06:07 +0000 (15:06 +0000)
committerDaniel Veillard <veillard@src.gnome.org>
Mon, 19 Feb 2001 15:06:07 +0000 (15:06 +0000)
- libxslt/numbers.c libxslt/numbersInternals.h libxslt/xslt.c
  libxslt/pattern.[ch] libxslt/xsltInternals.h:  more work on
  support of namespaces, both in templates and in XPath subexpressions
Daniel

ChangeLog
libxslt/numbers.c
libxslt/numbersInternals.h
libxslt/pattern.c
libxslt/pattern.h
libxslt/transform.c
libxslt/xslt.c
libxslt/xsltInternals.h

index 85e0b43..3f42564 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+Mon Feb 19 18:05:47 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
+
+       * libxslt/numbers.c libxslt/numbersInternals.h libxslt/xslt.c
+         libxslt/pattern.[ch] libxslt/xsltInternals.h:  more work on
+         support of namespaces, both in templates and in XPath subexpressions
+
 Sun Feb 18 19:11:26 CET 2001 Bjorn Reese <breese@users.sourceforge.net>
 
        * libxslt/xsltutils.c: xsltSortFunction uses Shell's sort
index 34a89f4..bc38c5c 100644 (file)
@@ -398,7 +398,9 @@ xsltNumberFormatGetAnyLevel(xsltTransformContextPtr context,
                            xmlChar *count,
                            xmlChar *from,
                            double *array,
-                           int max)
+                           int max,
+                           xmlDocPtr doc,
+                           xmlNodePtr elem)
 {
     int amount = 0;
     int cnt = 0;
@@ -410,11 +412,11 @@ xsltNumberFormatGetAnyLevel(xsltTransformContextPtr context,
     xsltCompMatchPtr fromPat;
 
     if (count != NULL)
-       countPat = xsltCompilePattern(count);
+       countPat = xsltCompilePattern(count, doc, elem);
     else
        countPat = NULL;
     if (from != NULL)
-       fromPat = xsltCompilePattern(from);
+       fromPat = xsltCompilePattern(from, doc, elem);
     else
        fromPat = NULL;
     context->xpathCtxt->node = node;
@@ -474,7 +476,9 @@ xsltNumberFormatGetMultipleLevel(xsltTransformContextPtr context,
                                 xmlChar *count,
                                 xmlChar *from,
                                 double *array,
-                                int max)
+                                int max,
+                                xmlDocPtr doc,
+                                xmlNodePtr elem)
 {
     int amount = 0;
     int cnt;
@@ -485,11 +489,11 @@ xsltNumberFormatGetMultipleLevel(xsltTransformContextPtr context,
     xsltCompMatchPtr fromPat;
 
     if (count != NULL)
-       countPat = xsltCompilePattern(count);
+       countPat = xsltCompilePattern(count, doc, elem);
     else
        countPat = NULL;
     if (from != NULL)
-       fromPat = xsltCompilePattern(from);
+       fromPat = xsltCompilePattern(from, doc, elem);
     else
        fromPat = NULL;
     context->xpathCtxt->node = node;
@@ -608,7 +612,9 @@ xsltNumberFormat(xsltTransformContextPtr ctxt,
                                                      data->count,
                                                      data->from,
                                                      &number,
-                                                     1);
+                                                     1,
+                                                     data->doc,
+                                                     data->node);
            if (amount == 1) {
                xsltNumberFormatInsertNumbers(data,
                                              &number,
@@ -625,7 +631,9 @@ xsltNumberFormat(xsltTransformContextPtr ctxt,
                                                      data->count,
                                                      data->from,
                                                      numarray,
-                                                     max);
+                                                     max,
+                                                     data->doc,
+                                                     data->node);
            if (amount > 0) {
                xsltNumberFormatInsertNumbers(data,
                                              numarray,
@@ -640,7 +648,9 @@ xsltNumberFormat(xsltTransformContextPtr ctxt,
                                                 data->count,
                                                 data->from,
                                                 &number,
-                                                1);
+                                                1,
+                                                data->doc,
+                                                data->node);
            if (amount > 0) {
                xsltNumberFormatInsertNumbers(data,
                                              &number,
index a112d23..a20dec1 100644 (file)
@@ -28,6 +28,8 @@ typedef struct _xsltNumberData {
     xmlChar *format;
     int digitsPerGroup;
     xmlChar groupingCharacter;
+    xmlDocPtr doc;
+    xmlNodePtr node;
 } xsltNumberData, *xsltNumberDataPtr;
 
 xmlXPathError xsltFormatNumberConversion(xsltDecimalFormatPtr, xmlChar *,
index a6413b2..231fe1c 100644 (file)
@@ -27,7 +27,7 @@
 #include "keys.h"
 #include "pattern.h"
 
-/* #define DEBUG_PARSING */
+#define DEBUG_PATTERN
 
 /*
  * Types are private:
@@ -80,6 +80,8 @@ typedef xsltParserContext *xsltParserContextPtr;
 struct _xsltParserContext {
     const xmlChar *cur;                        /* the current char being parsed */
     const xmlChar *base;               /* the full expression */
+    xmlDocPtr      doc;                        /* the source document */
+    xmlNodePtr    elem;                        /* the source element */
     int error;                         /* error code */
     xsltCompMatchPtr comp;             /* the result */
 };
@@ -333,10 +335,10 @@ xsltTestCompMatch(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,
             case XSLT_OP_END:
                return(1);
             case XSLT_OP_ROOT:
-               if ((node->type != XML_DOCUMENT_NODE) &&
-                   (node->type != XML_HTML_DOCUMENT_NODE))
-                   return(0);
-               continue;
+               if ((node->type == XML_DOCUMENT_NODE) ||
+                   (node->type == XML_HTML_DOCUMENT_NODE))
+                   continue;
+               return(0);
             case XSLT_OP_ELEM:
                if (node->type != XML_ELEMENT_NODE)
                    return(0);
@@ -493,7 +495,7 @@ xsltTestCompMatch(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,
                    (node->type == XML_ELEMENT_NODE) &&
                    (node->parent != NULL)) {
 
-                   /* TODO: cache those informations ?!? */
+                   /* TODO: cache those informations !!! */
                    xmlNodePtr siblings = node->parent->children;
 
                    while (siblings != NULL) {
@@ -905,6 +907,9 @@ error:
 void
 xsltCompileStepPattern(xsltParserContextPtr ctxt, xmlChar *token) {
     xmlChar *name = NULL;
+    xmlChar *prefix = NULL;
+    xmlChar *ncname = NULL;
+    xmlChar *URL = NULL;
 
     SKIP_BLANKS;
     if ((token == NULL) && (CUR == '@')) {
@@ -938,6 +943,8 @@ xsltCompileStepPattern(xsltParserContextPtr ctxt, xmlChar *token) {
            goto error;
        }
     }
+
+
     SKIP_BLANKS;
     if (CUR == '(') {
        xsltCompileIdKeyPattern(ctxt, token, 0);
@@ -953,7 +960,6 @@ xsltCompileStepPattern(xsltParserContextPtr ctxt, xmlChar *token) {
        }
        NEXT;
        if (xmlStrEqual(token, (const xmlChar *) "child")) {
-           /* TODO: handle namespace */
            name = xsltScanName(ctxt);
            if (name == NULL) {
                xsltGenericError(xsltGenericErrorContext,
@@ -961,9 +967,26 @@ xsltCompileStepPattern(xsltParserContextPtr ctxt, xmlChar *token) {
                ctxt->error = 1;
                goto error;
            }
-           PUSH(XSLT_OP_CHILD, name, NULL);
+           ncname = xmlSplitQName2(name, &prefix);
+           if (ncname != NULL) {
+               if (prefix != NULL) {
+                   xmlNsPtr ns;
+
+                   ns = xmlSearchNs(ctxt->doc, ctxt->elem, prefix);
+                   if (ns == NULL) {
+                       xsltGenericError(xsltGenericErrorContext,
+                           "xsl: pattern, no namespace bound to prefix %s\n",
+                                        prefix);
+                   } else {
+                       URL = xmlStrdup(ns->href);
+                   }
+                   xmlFree(prefix);
+               }
+               xmlFree(name);
+               name = ncname;
+           }
+           PUSH(XSLT_OP_CHILD, name, URL);
        } else if (xmlStrEqual(token, (const xmlChar *) "attribute")) {
-           /* TODO: handle namespace */
            name = xsltScanName(ctxt);
            if (name == NULL) {
                xsltGenericError(xsltGenericErrorContext,
@@ -971,7 +994,25 @@ xsltCompileStepPattern(xsltParserContextPtr ctxt, xmlChar *token) {
                ctxt->error = 1;
                goto error;
            }
-           PUSH(XSLT_OP_ATTR, name, NULL);
+           ncname = xmlSplitQName2(name, &prefix);
+           if (ncname != NULL) {
+               if (prefix != NULL) {
+                   xmlNsPtr ns;
+
+                   ns = xmlSearchNs(ctxt->doc, ctxt->elem, prefix);
+                   if (ns == NULL) {
+                       xsltGenericError(xsltGenericErrorContext,
+                           "xsl: pattern, no namespace bound to prefix %s\n",
+                                        prefix);
+                   } else {
+                       URL = xmlStrdup(ns->href);
+                   }
+                   xmlFree(prefix);
+               }
+               xmlFree(name);
+               name = ncname;
+           }
+           PUSH(XSLT_OP_ATTR, name, URL);
        } else {
            xsltGenericError(xsltGenericErrorContext,
                "xsltCompileStepPattern : 'child' or 'attribute' expected\n");
@@ -983,8 +1024,25 @@ xsltCompileStepPattern(xsltParserContextPtr ctxt, xmlChar *token) {
        NEXT;
        PUSH(XSLT_OP_ALL, token, NULL);
     } else {
-       /* TODO: handle namespace */
-       PUSH(XSLT_OP_ELEM, token, NULL);
+       ncname = xmlSplitQName2(token, &prefix);
+       if (ncname != NULL) {
+           if (prefix != NULL) {
+               xmlNsPtr ns;
+
+               ns = xmlSearchNs(ctxt->doc, ctxt->elem, prefix);
+               if (ns == NULL) {
+                   xsltGenericError(xsltGenericErrorContext,
+                       "xsl: pattern, no namespace bound to prefix %s\n",
+                                    prefix);
+               } else {
+                   URL = xmlStrdup(ns->href);
+               }
+               xmlFree(prefix);
+           }
+           xmlFree(token);
+           token = ncname;
+       }
+       PUSH(XSLT_OP_ELEM, token, URL);
     }
 parse_predicate:
     SKIP_BLANKS;
@@ -1132,6 +1190,8 @@ error:
 /**
  * xsltCompilePattern:
  * @pattern an XSLT pattern
+ * @doc:  the containing document
+ * @node:  the containing element
  *
  * Compile the XSLT pattern and generates a list of precompiled form suitable
  * for fast matching.
@@ -1142,7 +1202,7 @@ error:
  */
 
 xsltCompMatchPtr
-xsltCompilePattern(const xmlChar *pattern) {
+xsltCompilePattern(const xmlChar *pattern, xmlDocPtr doc, xmlNodePtr node) {
     xsltParserContextPtr ctxt = NULL;
     xsltCompMatchPtr element, first = NULL, previous = NULL;
     int current, start, end;
@@ -1153,7 +1213,7 @@ xsltCompilePattern(const xmlChar *pattern) {
        return(NULL);
     }
 
-#ifdef DEBUG_PARSING
+#ifdef DEBUG_PATTERN
     xsltGenericDebug(xsltGenericDebugContext,
                     "xsltCompilePattern : parsing '%s'\n", pattern);
 #endif
@@ -1161,6 +1221,8 @@ xsltCompilePattern(const xmlChar *pattern) {
     ctxt = xsltNewParserContext();
     if (ctxt == NULL)
        return(NULL);
+    ctxt->doc = doc;
+    ctxt->elem = node;
     current = end = 0;
     while (pattern[current] != 0) {
        start = current;
@@ -1206,6 +1268,9 @@ xsltCompilePattern(const xmlChar *pattern) {
            (element->steps[0].value != NULL) &&
            (element->steps[1].op == XSLT_OP_END)) {
            element->priority = 0;
+       } else if ((element->steps[0].op == XSLT_OP_ROOT) &&
+                  (element->steps[1].op == XSLT_OP_END)) {
+           element->priority = 0;
        } else if ((element->steps[0].op == XSLT_OP_PI) &&
                   (element->steps[0].value != NULL) &&
                   (element->steps[1].op == XSLT_OP_END)) {
@@ -1271,7 +1336,7 @@ xsltAddTemplate(xsltStylesheetPtr style, xsltTemplatePtr cur,
     if ((style == NULL) || (cur == NULL) || (cur->match == NULL))
        return(-1);
 
-    pat = xsltCompilePattern(cur->match);
+    pat = xsltCompilePattern(cur->match, style->doc, cur->elem);
     while (pat) {
        next = pat->next;
        pat->next = NULL;
@@ -1281,7 +1346,7 @@ xsltAddTemplate(xsltStylesheetPtr style, xsltTemplatePtr cur,
            pat->mode = xmlStrdup(mode);
        if (modeURI != NULL)
            pat->modeURI = xmlStrdup(modeURI);
-       if (pat->priority != XSLT_PAT_NO_PRIORITY)
+       if (cur->priority == XSLT_PAT_NO_PRIORITY)
            cur->priority = pat->priority;
        else
            pat->priority = cur->priority;
@@ -1351,25 +1416,13 @@ xsltAddTemplate(xsltStylesheetPtr style, xsltTemplatePtr cur,
                    xsltFreeCompMatch(pat);
                    return(-1);
                }
-#ifdef DEBUG_PARSING
-               xsltGenericDebug(xsltGenericDebugContext,
-                                "xsltAddTemplate: created template hash\n");
-#endif
                xmlHashAddEntry3(style->templatesHash, name, mode, modeURI, pat);
-#ifdef DEBUG_PARSING
-               xsltGenericDebug(xsltGenericDebugContext,
-                                "xsltAddTemplate: added new hash %s\n", name);
-#endif
            } else {
                list = (xsltCompMatchPtr) xmlHashLookup3(style->templatesHash,
                                                         name, mode, modeURI);
                if (list == NULL) {
                    xmlHashAddEntry3(style->templatesHash, name,
                                     mode, modeURI, pat);
-#ifdef DEBUG_PARSING
-                   xsltGenericDebug(xsltGenericDebugContext,
-                                    "xsltAddTemplate: added new hash %s\n", name);
-#endif
                } else {
                    /*
                     * Note '<=' since one must choose among the matching
@@ -1380,10 +1433,6 @@ xsltAddTemplate(xsltStylesheetPtr style, xsltTemplatePtr cur,
                        pat->next = list;
                        xmlHashUpdateEntry3(style->templatesHash, name,
                                            mode, modeURI, pat, NULL);
-#ifdef DEBUG_PARSING
-                       xsltGenericDebug(xsltGenericDebugContext,
-                                        "xsltAddTemplate: added head hash for %s\n", name);
-#endif
                    } else {
                        while (list->next != NULL) {
                            if (list->next->priority <= pat->priority)
@@ -1418,6 +1467,12 @@ xsltAddTemplate(xsltStylesheetPtr style, xsltTemplatePtr cur,
            xsltFreeCompMatch(pat);
            return(-1);
        }
+#ifdef DEBUG_PATTERN
+       xsltGenericDebug(xsltGenericDebugContext,
+                    "added pattern : '%s' priority %f\n",
+                        pat->template->match, pat->priority);
+#endif
+
        pat = next;
     }
     return(0);
@@ -1565,7 +1620,6 @@ xsltGetTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
                list = list->next;
            }
        }
-
        if (ret != NULL)
            return(ret);
 
@@ -1607,6 +1661,7 @@ xsltFreeTemplateHashes(xsltStylesheetPtr style) {
         xsltFreeCompMatchList(style->commentMatch);
 }
 
+#if 0
 /**
  * xsltMatchPattern
  * @node: a node in the source tree
@@ -1634,4 +1689,4 @@ xsltMatchPattern(xsltTransformContextPtr context,
     }
     return match;
 }
-
+#endif
index 105c143..00b944b 100644 (file)
@@ -25,7 +25,9 @@ typedef xsltCompMatch *xsltCompMatchPtr;
  * Pattern related interfaces
  */
 
-xsltCompMatchPtr xsltCompilePattern    (const xmlChar *pattern);
+xsltCompMatchPtr xsltCompilePattern    (const xmlChar *pattern,
+                                        xmlDocPtr doc,
+                                        xmlNodePtr node);
 void            xsltFreeCompMatchList  (xsltCompMatchPtr comp);
 int             xsltTestCompMatchList  (xsltTransformContextPtr ctxt,
                                         xmlNodePtr node,
@@ -42,10 +44,11 @@ xsltTemplatePtr     xsltGetTemplate         (xsltTransformContextPtr ctxt,
                                         xmlNodePtr node,
                                         xsltStylesheetPtr style);
 void           xsltFreeTemplateHashes  (xsltStylesheetPtr style);
+#if 0
 int            xsltMatchPattern        (xsltTransformContextPtr ctxt,
                                         xmlNodePtr node,
                                         const xmlChar *pattern);
-
+#endif
 #ifdef __cplusplus
 }
 #endif
index 6956cda..fc31b95 100644 (file)
@@ -165,6 +165,7 @@ xsltNewTransformContext(xsltStylesheetPtr style, xmlDocPtr doc) {
        return(NULL);
     }
     XSLT_REGISTER_VARIABLE_LOOKUP(cur);
+    cur->xpathCtxt->nsHash = style->nsHash;
     docu = xsltNewDocument(cur, doc);
     if (docu == NULL) {
         xsltGenericError(xsltGenericErrorContext,
@@ -189,8 +190,10 @@ void
 xsltFreeTransformContext(xsltTransformContextPtr ctxt) {
     if (ctxt == NULL)
        return;
-    if (ctxt->xpathCtxt != NULL)
+    if (ctxt->xpathCtxt != NULL) {
+       ctxt->xpathCtxt->nsHash = NULL;
        xmlXPathFreeContext(ctxt->xpathCtxt);
+    }
     if (ctxt->templTab != NULL)
        xmlFree(ctxt->templTab);
     if (ctxt->varsTab != NULL)
@@ -977,6 +980,8 @@ xsltNumber(xsltTransformContextPtr ctxt,
 
     memset(&numdata, 0, sizeof(numdata));
     
+    numdata.doc = cur->doc;
+    numdata.node = cur;
     numdata.value = xmlGetNsProp(cur, (const xmlChar *)"value", XSLT_NAMESPACE);
     
     prop = xmlGetNsProp(cur, (const xmlChar *)"format", XSLT_NAMESPACE);
@@ -2337,9 +2342,9 @@ xsltApplyStylesheet(xsltStylesheetPtr style, xmlDocPtr doc) {
      */
     ctxt->output = res;
     ctxt->insert = (xmlNodePtr) res;
+    xsltEvalGlobalVariables(ctxt);
     ctxt->node = (xmlNodePtr) doc;
     varsPush(ctxt, NULL);
-    xsltEvalGlobalVariables(ctxt);
     xsltProcessOneNode(ctxt, ctxt->node);
     xsltFreeStackElemList(varsPop(ctxt));
 
index 3565b7c..d09ac0e 100644 (file)
@@ -295,6 +295,8 @@ xsltFreeStylesheet(xsltStylesheetPtr sheet) {
        xsltFreeStackElemList(sheet->variables);
     if (sheet->stripSpaces != NULL)
        xmlHashFree(sheet->stripSpaces, NULL);
+    if (sheet->nsHash != NULL) 
+       xmlHashFree(sheet->nsHash, NULL);
 
     if (sheet->method != NULL) xmlFree(sheet->method);
     if (sheet->methodURI != NULL) xmlFree(sheet->methodURI);
@@ -762,6 +764,86 @@ skip_children:
 }
 
 /**
+ * xsltGatherNamespaces:
+ * @style:  the XSLT stylesheet
+ *
+ * Browse the stylesheet and buit the namspace hash table which
+ * will be used for XPath interpretation. If needed do a bit of normalization
+ */
+
+void
+xsltGatherNamespaces(xsltStylesheetPtr style) {
+    xmlNodePtr cur;
+    const xmlChar *URI;
+
+    /* 
+     * TODO: basically if the stylesheet uses the same prefix for different
+     *       patterns, well they may be in problem, hopefully they will get
+     *       a warning first.
+     */
+    cur = xmlDocGetRootElement(style->doc);
+    while (cur != NULL) {
+       if (cur->type == XML_ELEMENT_NODE) {
+           xmlNsPtr ns = cur->nsDef;
+           while (ns != NULL) {
+               if (ns->prefix != NULL) {
+                   if (style->nsHash == NULL) {
+                       style->nsHash = xmlHashCreate(10);
+                       if (style->nsHash == NULL) {
+                           xsltGenericError(xsltGenericErrorContext,
+                "xsltGatherNamespaces: failed to create hash table\n");
+                           return;
+                       }
+                   }
+                   URI = xmlHashLookup(style->nsHash, ns->prefix);
+                   if ((URI != NULL) && (!xmlStrEqual(URI, ns->href))) {
+                       xsltGenericError(xsltGenericErrorContext,
+            "Namespaces prefix %s used for multiple namespaces\n");
+                   } else if (URI == NULL) {
+                       xmlHashUpdateEntry(style->nsHash, ns->prefix,
+                           (void *) ns->href, (xmlHashDeallocator)xmlFree);
+
+#ifdef DEBUG_PARSING
+                       xsltGenericDebug(xsltGenericDebugContext,
+                "Added namespace: %s mapped to %s\n", ns->prefix, ns->href);
+#endif
+                   }
+               }
+               ns = ns->next;
+           }
+       }
+
+       /*
+        * Skip to next node
+        */
+       if (cur->children != NULL) {
+           if (cur->children->type != XML_ENTITY_DECL) {
+               cur = cur->children;
+               continue;
+           }
+       }
+       if (cur->next != NULL) {
+           cur = cur->next;
+           continue;
+       }
+       
+       do {
+           cur = cur->parent;
+           if (cur == NULL)
+               break;
+           if (cur == (xmlNodePtr) style->doc) {
+               cur = NULL;
+               break;
+           }
+           if (cur->next != NULL) {
+               cur = cur->next;
+               break;
+           }
+       } while (cur != NULL);
+    }
+}
+
+/**
  * xsltParseTemplateContent:
  * @style:  the XSLT stylesheet
  * @ret:  the "template" structure
@@ -781,6 +863,7 @@ xsltParseTemplateContent(xsltStylesheetPtr style, xsltTemplatePtr ret,
      * For stylesheets, the set of whitespace-preserving
      * element names consists of just xsl:text.
      */
+    ret->elem = template;
     cur = template->children;
     delete = NULL;
     while (cur != NULL) {
@@ -1334,6 +1417,7 @@ xsltParseStylesheetDoc(xmlDocPtr doc) {
        return(NULL);
     
     ret->doc = doc;
+    xsltGatherNamespaces(ret);
     xsltParseStylesheetProcess(ret, doc);
 
     return(ret);
index 3cdbdf2..908e6a9 100644 (file)
@@ -53,12 +53,13 @@ struct _xsltTemplate {
     struct _xsltTemplate *next;/* chained list sorted by priority */
     struct _xsltStylesheet *style;/* the containing stylesheet */
     xmlChar *match;    /* the matching string */
-    int priority;      /* as given from the stylesheet, not computed */
+    float priority;    /* as given from the stylesheet, not computed */
     xmlChar *name;     /* the local part of the name QName */
     xmlChar *nameURI;  /* the URI part of the name QName */
     xmlChar *mode;     /* the local part of the mode QName */
     xmlChar *modeURI;  /* the URI part of the mode QName */
     xmlNodePtr content;        /* the template replacement value */
+    xmlNodePtr elem;   /* the source element */
 };
 
 /*
@@ -150,6 +151,11 @@ struct _xsltStylesheet {
     xmlHashTablePtr attributeSets;/* the attribute sets hash tables */
 
     /*
+     * Attribute sets
+     */
+    xmlHashTablePtr nsHash;     /* the set of namespaces in use */
+
+    /*
      * Key definitions
      */
     void *keys;                                /* key definitions */