The XML Rec formatting test starts looking okay, also added
authorDaniel Veillard <veillard@src.gnome.org>
Wed, 14 Feb 2001 14:45:10 +0000 (14:45 +0000)
committerDaniel Veillard <veillard@src.gnome.org>
Wed, 14 Feb 2001 14:45:10 +0000 (14:45 +0000)
apply-imports support:
- FEATURES libxslt/imports.h libxslt/pattern.[ch]
  libxslt/xsltInternals.h libxslt/transform.[ch]
  libxslt/templates.c libxslt/xslt.c:
  Added apply-imports, keep a stack of running templates
- libxslt/xsltutils.c: bugfixes, gather the output informations
  down the cascade
- tests/xmlspec/Makefile.am tests/xmlspec/REC-xml-2e.xsl
  tests/xmlspec/diffspec.xsl tests/xmlspec/xmlspec.xsl: running
  the real set of transformation on XML-1.0 2e generages a near
  perfect HTML. Needs just more number fixes and implementation
  and an obscure problem in 3.3.3
Daniel

15 files changed:
ChangeLog
FEATURES
libxslt/imports.h
libxslt/pattern.c
libxslt/pattern.h
libxslt/templates.c
libxslt/transform.c
libxslt/transform.h
libxslt/variables.c
libxslt/xslt.c
libxslt/xsltInternals.h
libxslt/xsltutils.c
tests/xmlspec/Makefile.am
tests/xmlspec/REC-xml-2e.xsl [new file with mode: 0644]
tests/xmlspec/diffspec.xsl [new file with mode: 0644]

index 0d6bd2f..321594d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+Wed Feb 14 15:39:06 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
+
+       * FEATURES libxslt/imports.h libxslt/pattern.[ch]
+         libxslt/xsltInternals.h libxslt/transform.[ch]
+         libxslt/templates.c libxslt/xslt.c:
+         Added apply-imports, keep a stack of running templates
+       * libxslt/xsltutils.c: bugfixes, gather the output informations
+         down the cascade
+       * tests/xmlspec/Makefile.am tests/xmlspec/REC-xml-2e.xsl
+         tests/xmlspec/diffspec.xsl tests/xmlspec/xmlspec.xsl: running
+         the real set of transformation on XML-1.0 2e generages a near
+         perfect HTML. Needs just more number fixes and implementation
+         and an obscure problem in 3.3.3
+
 Tue Feb 13 20:31:03 CET 2001 Bjorn Reese <breese@users.sourceforge.net>
 
        * libxslt/pattern.c: added xsltMatchPattern()
index 4f7653b..50cab8e 100644 (file)
--- a/FEATURES
+++ b/FEATURES
@@ -87,7 +87,7 @@ YES                       xsl:apply-templates
 YES                            select = node-set-expression 
 YES                            mode = qname
 
-NO                         xsl:apply-imports
+YES                        xsl:apply-imports
 
 YES                        xsl:call-template
 YES                            name = qname
index 9aa280a..63bbdd1 100644 (file)
 extern "C" {
 #endif
 
+/*
+ * A couple of macros to apply the cascade
+ */
+#define XSLT_GET_IMPORT_PTR(res, style, name) {                        \
+    xsltStylesheetPtr st = style;                              \
+    res = NULL;                                                        \
+    while (st != NULL) {                                       \
+       if (st->name != NULL) { res = st->name; break; }        \
+       st = xsltNextImport(st);                                \
+    }}
+
+#define XSLT_GET_IMPORT_INT(res, style, name) {                        \
+    xsltStylesheetPtr st = style;                              \
+    res = -1;                                                  \
+    while (st != NULL) {                                       \
+       if (st->name != -1) { res = st->name; break; }  \
+       st = xsltNextImport(st);                                \
+    }}
+
+/*
+ * Module interfaces
+ */
 void                   xsltParseStylesheetImport(xsltStylesheetPtr style,
                                                  xmlNodePtr cur);
 void                   xsltParseStylesheetInclude(xsltStylesheetPtr style,
index 9b767ab..53c663f 100644 (file)
@@ -1389,15 +1389,18 @@ xsltAddTemplate(xsltStylesheetPtr style, xsltTemplatePtr cur,
 /**
  * xsltGetTemplate:
  * @ctxt:  a XSLT process context
- * @mode:  the mode name or NULL
+ * @mode:  the mode 
+ * @style:  the current style
  *
- * Finds the template applying to this node
+ * Finds the template applying to this node, if @style is non-NULL
+ * it means one need to look for the next imported template in scope.
  *
  * Returns the xsltTemplatePtr or NULL if not found
  */
 xsltTemplatePtr
-xsltGetTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node) {
-    xsltStylesheetPtr style;
+xsltGetTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
+               xsltStylesheetPtr style) {
+    xsltStylesheetPtr curstyle;
     xsltTemplatePtr ret = NULL;
     const xmlChar *name = NULL;
     xsltCompMatchPtr list = NULL;
@@ -1405,10 +1408,15 @@ xsltGetTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node) {
     if ((ctxt == NULL) || (node == NULL))
        return(NULL);
 
-    style = ctxt->style;
-    while (style != NULL) {
+    if (style == NULL) {
+       curstyle = ctxt->style;
+    } else {
+       curstyle = xsltNextImport(style);
+    }
+
+    while ((curstyle != NULL) && (curstyle != style)) {
        /* TODO : handle IDs/keys here ! */
-       if (style->templatesHash != NULL) {
+       if (curstyle->templatesHash != NULL) {
            /*
             * Use the top name as selector
             */
@@ -1445,7 +1453,7 @@ xsltGetTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node) {
            /*
             * find the list of appliable expressions based on the name
             */
-           list = (xsltCompMatchPtr) xmlHashLookup3(style->templatesHash,
+           list = (xsltCompMatchPtr) xmlHashLookup3(curstyle->templatesHash,
                                             name, ctxt->mode, ctxt->modeURI);
        }
        while (list != NULL) {
@@ -1463,24 +1471,24 @@ xsltGetTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node) {
         */
        switch (node->type) {
            case XML_ELEMENT_NODE:
-               list = style->elemMatch;
+               list = curstyle->elemMatch;
                break;
            case XML_ATTRIBUTE_NODE:
-               list = style->attrMatch;
+               list = curstyle->attrMatch;
                break;
            case XML_PI_NODE:
-               list = style->piMatch;
+               list = curstyle->piMatch;
                break;
            case XML_DOCUMENT_NODE:
            case XML_HTML_DOCUMENT_NODE:
-               list = style->rootMatch;
+               list = curstyle->rootMatch;
                break;
            case XML_TEXT_NODE:
            case XML_CDATA_SECTION_NODE:
-               list = style->textMatch;
+               list = curstyle->textMatch;
                break;
            case XML_COMMENT_NODE:
-               list = style->commentMatch;
+               list = curstyle->commentMatch;
                break;
            case XML_ENTITY_REF_NODE:
            case XML_ENTITY_NODE:
@@ -1509,7 +1517,7 @@ xsltGetTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node) {
            list = list->next;
        }
        if (node->_private != NULL) {
-           list = style->keyMatch;
+           list = curstyle->keyMatch;
            while ((list != NULL) &&
                   ((ret == NULL)  || (list->priority > ret->priority))) {
                if (xsltTestCompMatch(ctxt, list, node,
@@ -1525,9 +1533,9 @@ xsltGetTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node) {
            return(ret);
 
        /*
-        * Cycle on next stylesheet import.
+        * Cycle on next curstylesheet import.
         */
-       style = xsltNextImport(style);
+       curstyle = xsltNextImport(curstyle);
     }
     return(NULL);
 }
index 67b7073..4320ec9 100644 (file)
@@ -20,7 +20,8 @@ int           xsltAddTemplate         (xsltStylesheetPtr style,
                                         const xmlChar *mode,
                                         const xmlChar *modeURI);
 xsltTemplatePtr        xsltGetTemplate         (xsltTransformContextPtr ctxt,
-                                        xmlNodePtr node);
+                                        xmlNodePtr node,
+                                        xsltStylesheetPtr style);
 void           xsltFreeTemplateHashes  (xsltStylesheetPtr style);
 int            xsltMatchPattern        (xsltTransformContextPtr ctxt,
                                         xmlNodePtr node,
index 6e2fe6f..5274056 100644 (file)
@@ -30,6 +30,7 @@
 
 #define DEBUG_TEMPLATES
 
+
 /************************************************************************
  *                                                                     *
  *                     Module interfaces                               *
@@ -163,7 +164,7 @@ xsltEvalTemplateString(xsltTransformContextPtr ctxt, xmlNodePtr node,
     oldInsert = ctxt->insert;
     ctxt->insert = insert;
 
-    xsltApplyOneTemplate(ctxt, node, parent->children);
+    xsltApplyOneTemplate(ctxt, node, NULL, parent->children);
 
     ctxt->insert = oldInsert;
 
index c52efc1..61f40cc 100644 (file)
 #define IS_BLANK_NODE(n)                                               \
     (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
 
+/*
+ * Generic function for accessing stacks in the transform Context
+ */
+
+#define PUSH_AND_POP(scope, type, name)                                        \
+scope int name##Push(xsltTransformContextPtr ctxt, type value) {       \
+    if (ctxt->name##Nr >= ctxt->name##Max) {                           \
+       ctxt->name##Max *= 2;                                           \
+        ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab,         \
+                    ctxt->name##Max * sizeof(ctxt->name##Tab[0]));     \
+        if (ctxt->name##Tab == NULL) {                                 \
+           xmlGenericError(xmlGenericErrorContext,                     \
+                   "realloc failed !\n");                              \
+           return(0);                                                  \
+       }                                                               \
+    }                                                                  \
+    ctxt->name##Tab[ctxt->name##Nr] = value;                           \
+    ctxt->name = value;                                                        \
+    return(ctxt->name##Nr++);                                          \
+}                                                                      \
+scope type name##Pop(xsltTransformContextPtr ctxt) {                   \
+    type ret;                                                          \
+    if (ctxt->name##Nr <= 0) return(0);                                        \
+    ctxt->name##Nr--;                                                  \
+    if (ctxt->name##Nr > 0)                                            \
+       ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1];               \
+    else                                                               \
+        ctxt->name = NULL;                                             \
+    ret = ctxt->name##Tab[ctxt->name##Nr];                             \
+    ctxt->name##Tab[ctxt->name##Nr] = 0;                               \
+    return(ret);                                                       \
+}                                                                      \
+
+/*
+ * Those macros actually generate the functions
+ */
+PUSH_AND_POP(extern, xsltTemplatePtr, templ)
 
 /************************************************************************
  *                                                                     *
@@ -81,12 +118,24 @@ xsltNewTransformContext(xsltStylesheetPtr style, xmlDocPtr doc) {
        return(NULL);
     }
     memset(cur, 0, sizeof(xsltTransformContext));
+    cur->templTab = (xsltTemplatePtr *)
+               xmlMalloc(10 * sizeof(xsltTemplatePtr));
+    if (cur->templTab == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+               "xsltNewTransformContext: out of memory\n");
+       xmlFree(cur);
+       return(NULL);
+    }
+    cur->templNr = 0;
+    cur->templMax = 5;
+    cur->templ = NULL;
     cur->style = style;
     xmlXPathInit();
     cur->xpathCtxt = xmlXPathNewContext(doc);
     if (cur->xpathCtxt == NULL) {
         xsltGenericError(xsltGenericErrorContext,
                "xsltNewTransformContext : xmlXPathNewContext failed\n");
+       xmlFree(cur->templTab);
        xmlFree(cur);
        return(NULL);
     }
@@ -95,6 +144,7 @@ xsltNewTransformContext(xsltStylesheetPtr style, xmlDocPtr doc) {
     if (docu == NULL) {
         xsltGenericError(xsltGenericErrorContext,
                "xsltNewTransformContext : xsltNewDocument failed\n");
+       xmlFree(cur->templTab);
        xmlFree(cur);
        return(NULL);
     }
@@ -115,6 +165,8 @@ xsltFreeTransformContext(xsltTransformContextPtr ctxt) {
        return;
     if (ctxt->xpathCtxt != NULL)
        xmlXPathFreeContext(ctxt->xpathCtxt);
+    if (ctxt->templTab != NULL)
+       xmlFree(ctxt->templTab);
     xsltFreeVariableHashes(ctxt);
     xsltFreeDocuments(ctxt);
     memset(ctxt, -1, sizeof(xsltTransformContext));
@@ -450,7 +502,15 @@ xsltCopy(xsltTransformContextPtr ctxt, xmlNodePtr node,
        }
     }
 
-    xsltApplyOneTemplate(ctxt, ctxt->node, inst->children);
+    switch (node->type) {
+       case XML_DOCUMENT_NODE:
+       case XML_HTML_DOCUMENT_NODE:
+       case XML_ELEMENT_NODE:
+           xsltApplyOneTemplate(ctxt, ctxt->node, NULL, inst->children);
+           break;
+       default:
+           break;
+    }
     ctxt->insert = oldInsert;
 }
 
@@ -529,7 +589,7 @@ xsltElement(xsltTransformContextPtr ctxt, xmlNodePtr node,
         xmlFree(attributes);
     }
     
-    xsltApplyOneTemplate(ctxt, ctxt->node, inst->children);
+    xsltApplyOneTemplate(ctxt, ctxt->node, NULL, inst->children);
 
 error:
     if (prop != NULL)
@@ -949,7 +1009,7 @@ xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) {
        case XML_ELEMENT_NODE:
            break;
        case XML_CDATA_SECTION_NODE:
-           template = xsltGetTemplate(ctxt, node);
+           template = xsltGetTemplate(ctxt, node, NULL);
            if (template) {
                xmlNodePtr oldNode;
 
@@ -960,7 +1020,7 @@ xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) {
 #endif
                oldNode = ctxt->node;
                ctxt->node = node;
-               xsltApplyOneTemplate(ctxt, node, template->content);
+               xsltApplyOneTemplate(ctxt, node, template, NULL);
                ctxt->node = oldNode;
            } else /* if (ctxt->mode == NULL) */ {
 #ifdef DEBUG_PROCESS
@@ -978,7 +1038,7 @@ xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) {
            }
            return;
        case XML_TEXT_NODE:
-           template = xsltGetTemplate(ctxt, node);
+           template = xsltGetTemplate(ctxt, node, NULL);
            if (template) {
                xmlNodePtr oldNode;
 
@@ -989,7 +1049,7 @@ xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) {
 #endif
                oldNode = ctxt->node;
                ctxt->node = node;
-               xsltApplyOneTemplate(ctxt, node, template->content);
+               xsltApplyOneTemplate(ctxt, node, template, NULL);
                ctxt->node = oldNode;
            } else /* if (ctxt->mode == NULL) */ {
 #ifdef DEBUG_PROCESS
@@ -1013,13 +1073,13 @@ xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) {
        case XML_ATTRIBUTE_NODE:
            if (ctxt->insert->type == XML_ELEMENT_NODE) {
                    xmlAttrPtr attr = (xmlAttrPtr) node, ret = NULL, cur;
-               template = xsltGetTemplate(ctxt, node);
+               template = xsltGetTemplate(ctxt, node, NULL);
                if (template) {
                    xmlNodePtr oldNode;
 
                    oldNode = ctxt->node;
                    ctxt->node = node;
-                   xsltApplyOneTemplate(ctxt, node, template->content);
+                   xsltApplyOneTemplate(ctxt, node, template, NULL);
                    ctxt->node = oldNode;
                } else if (ctxt->mode == NULL) {
                    if (attr->ns != NULL) {
@@ -1100,13 +1160,13 @@ xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) {
      */
     attrs = node->properties;
     while (attrs != NULL) {
-       template = xsltGetTemplate(ctxt, (xmlNodePtr) attrs);
+       template = xsltGetTemplate(ctxt, (xmlNodePtr) attrs, NULL);
        if (template) {
            xmlNodePtr oldNode;
 
            oldNode = ctxt->node;
            ctxt->node = node;
-           xsltApplyOneTemplate(ctxt, node, template->content);
+           xsltApplyOneTemplate(ctxt, node, template, NULL);
            ctxt->node = oldNode;
        }
        attrs = attrs->next;
@@ -1125,7 +1185,7 @@ xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) {
                xsltProcessOneNode(ctxt, cur);
                break;
            case XML_CDATA_SECTION_NODE:
-               template = xsltGetTemplate(ctxt, node);
+               template = xsltGetTemplate(ctxt, node, NULL);
                if (template) {
                    xmlNodePtr oldNode;
 
@@ -1136,7 +1196,7 @@ xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) {
 #endif
                    oldNode = ctxt->node;
                    ctxt->node = node;
-                   xsltApplyOneTemplate(ctxt, node, template->content);
+                   xsltApplyOneTemplate(ctxt, node, template, NULL);
                    ctxt->node = oldNode;
                } else /* if (ctxt->mode == NULL) */ {
 #ifdef DEBUG_PROCESS
@@ -1154,7 +1214,7 @@ xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) {
                }
                break;
            case XML_TEXT_NODE:
-               template = xsltGetTemplate(ctxt, cur);
+               template = xsltGetTemplate(ctxt, cur, NULL);
                if (template) {
                    xmlNodePtr oldNode;
 
@@ -1167,7 +1227,7 @@ xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) {
                    ctxt->node = cur;
                    ctxt->xpathCtxt->contextSize = nbchild;
                    ctxt->xpathCtxt->proximityPosition = childno;
-                   xsltApplyOneTemplate(ctxt, cur, template->content);
+                   xsltApplyOneTemplate(ctxt, cur, template, NULL);
                    ctxt->node = oldNode;
                } else /* if (ctxt->mode == NULL) */ {
 #ifdef DEBUG_PROCESS
@@ -1190,7 +1250,7 @@ xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) {
                break;
            case XML_PI_NODE:
            case XML_COMMENT_NODE:
-               template = xsltGetTemplate(ctxt, cur);
+               template = xsltGetTemplate(ctxt, cur, NULL);
                if (template) {
                    xmlNodePtr oldNode;
 
@@ -1198,7 +1258,7 @@ xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) {
                    ctxt->node = cur;
                    ctxt->xpathCtxt->contextSize = nbchild;
                    ctxt->xpathCtxt->proximityPosition = childno;
-                   xsltApplyOneTemplate(ctxt, cur, template->content);
+                   xsltApplyOneTemplate(ctxt, cur, template, NULL);
                    ctxt->node = oldNode;
                }
                break;
@@ -1212,6 +1272,30 @@ xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) {
 }
 
 /**
+ * xsltApplyImports:
+ * @ctxt:  a XSLT process context
+ * @node:  the node in the source tree.
+ * @inst:  the xslt apply-imports node
+ *
+ * Process the xslt apply-imports node on the source node
+ */
+void
+xsltApplyImports(xsltTransformContextPtr ctxt, xmlNodePtr node,
+                xmlNodePtr inst) {
+    xsltTemplatePtr template;
+
+    if ((ctxt->templ == NULL) || (ctxt->templ->style == NULL)) {
+       xsltGenericError(xsltGenericErrorContext,
+            "xslt:apply-imports : internal error no current template\n");
+       return;
+    }
+    template = xsltGetTemplate(ctxt, node, ctxt->templ->style);
+    if (template != NULL) {
+       xsltApplyOneTemplate(ctxt, node, template, NULL);
+    }
+}
+
+/**
  * xsltCallTemplate:
  * @ctxt:  a XSLT process context
  * @node:  the node in the source tree.
@@ -1282,7 +1366,7 @@ xsltCallTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
        }
        cur = cur->next;
     }
-    xsltApplyOneTemplate(ctxt, node, template->content);
+    xsltApplyOneTemplate(ctxt, node, template, NULL);
 
 error:
     if (has_param == 1)
@@ -1511,23 +1595,35 @@ error:
  * xsltApplyOneTemplate:
  * @ctxt:  a XSLT process context
  * @node:  the node in the source tree.
+ * @templ:  the template
  * @list:  the template replacement nodelist
  *
  * Process the apply-templates node on the source node
  */
 void
 xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
-                    xmlNodePtr list) {
+                    xsltTemplatePtr templ, xmlNodePtr list) {
     xmlNodePtr cur = NULL, insert, copy = NULL;
     xmlNodePtr oldInsert;
     xmlAttrPtr attrs;
     int has_variables = 0;
 
+    if ((templ == NULL) && (list == NULL))
+       return;
     CHECK_STOPPED;
+
+    /*
+     * stack and saves
+     */
+    if (templ != NULL)
+       templPush(ctxt, templ);
     oldInsert = insert = ctxt->insert;
+
     /*
      * Insert all non-XSLT nodes found in the template
      */
+    if ((list == NULL) && (templ != NULL))
+       list = templ->content;
     cur = list;
     while (cur != NULL) {
        /*
@@ -1538,6 +1634,11 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
            xsltGenericDebug(xsltGenericDebugContext,
                 "xsltApplyOneTemplate: insert == NULL !\n");
 #endif
+           if (has_variables != 0) {
+               xsltPopStack(ctxt);
+           }
+           if (templ != NULL)
+               templPop(ctxt);
            return;
        }
 
@@ -1570,6 +1671,10 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
                ctxt->insert = insert;
                xsltForEach(ctxt, node, cur);
                ctxt->insert = oldInsert;
+           } else if (IS_XSLT_NAME(cur, "apply-imports")) {
+               ctxt->insert = insert;
+               xsltApplyImports(ctxt, node, cur);
+               ctxt->insert = oldInsert;
            } else if (IS_XSLT_NAME(cur, "attribute")) {
                ctxt->insert = insert;
                xsltAttribute(ctxt, node, cur);
@@ -1644,7 +1749,7 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
                        "xsltApplyOneTemplate: text copy failed\n");
            }
        } else if ((cur->type == XML_ELEMENT_NODE) &&
-                  (xmlStrEqual(cur->name, "xsltdebug"))) {
+                  (xmlStrEqual(cur->name, (const xmlChar *)"xsltdebug"))) {
            xsltDebug(ctxt, cur);
        } else if (cur->type == XML_ELEMENT_NODE) {
 #ifdef DEBUG_PROCESS
@@ -1703,6 +1808,8 @@ skip_children:
     if (has_variables != 0) {
        xsltPopStack(ctxt);
     }
+    if (templ != NULL)
+       templPop(ctxt);
 }
 
 /**
@@ -1785,7 +1892,7 @@ xsltChoose(xsltTransformContextPtr ctxt, xmlNodePtr node,
            "xsl:when: test evaluate to %d\n", doit);
 #endif
        if (doit) {
-           xsltApplyOneTemplate(ctxt, ctxt->node, when->children);
+           xsltApplyOneTemplate(ctxt, ctxt->node, NULL, when->children);
            goto done;
        }
        if (xpathParserCtxt != NULL)
@@ -1800,7 +1907,7 @@ xsltChoose(xsltTransformContextPtr ctxt, xmlNodePtr node,
        replacement = replacement->next;
     }
     if (IS_XSLT_ELEM(replacement) && (IS_XSLT_NAME(replacement, "otherwise"))) {
-       xsltApplyOneTemplate(ctxt, ctxt->node, replacement->children);
+       xsltApplyOneTemplate(ctxt, ctxt->node, NULL, replacement->children);
        replacement = replacement->next;
     }
     if (replacement != NULL) {
@@ -1884,7 +1991,7 @@ xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr node,
        "xsltIf: test evaluate to %d\n", doit);
 #endif
     if (doit) {
-       xsltApplyOneTemplate(ctxt, node, inst->children);
+       xsltApplyOneTemplate(ctxt, node, NULL, inst->children);
     }
 
 error:
@@ -1976,7 +2083,7 @@ xsltForEach(xsltTransformContextPtr ctxt, xmlNodePtr node,
     for (i = 0;i < list->nodeNr;i++) {
        ctxt->node = list->nodeTab[i];
        ctxt->xpathCtxt->proximityPosition = i + 1;
-       xsltApplyOneTemplate(ctxt, list->nodeTab[i], replacement);
+       xsltApplyOneTemplate(ctxt, list->nodeTab[i], NULL, replacement);
     }
     ctxt->nodeList = oldlist;
     ctxt->xpathCtxt->contextSize = oldContextSize;
@@ -2003,7 +2110,7 @@ xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) {
     xsltTemplatePtr template;
     xmlNodePtr oldNode;
 
-    template = xsltGetTemplate(ctxt, node);
+    template = xsltGetTemplate(ctxt, node, NULL);
     /*
      * If no template is found, apply the default rule.
      */
@@ -2032,7 +2139,7 @@ xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) {
             "xsltProcessOneNode: applying template for attribute %s\n",
                         node->name);
 #endif
-       xsltApplyOneTemplate(ctxt, node, template->content);
+       xsltApplyOneTemplate(ctxt, node, template, NULL);
     } else {
 #ifdef DEBUG_PROCESS
        if (node->type == XML_DOCUMENT_NODE)
@@ -2044,7 +2151,7 @@ xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) {
 #endif
        oldNode = ctxt->node;
        ctxt->node = node;
-       xsltApplyOneTemplate(ctxt, node, template->content);
+       xsltApplyOneTemplate(ctxt, node, template, NULL);
        ctxt->node = oldNode;
     }
 }
index de953fb..cd2a3d8 100644 (file)
@@ -23,6 +23,7 @@ xmlDocPtr     xsltApplyStylesheet     (xsltStylesheetPtr style,
                                         xmlDocPtr doc);
 void           xsltApplyOneTemplate    (xsltTransformContextPtr ctxt,
                                         xmlNodePtr node,
+                                        xsltTemplatePtr templ,
                                         xmlNodePtr list);
 #ifdef __cplusplus
 }
index 4ea0175..9ac4095 100644 (file)
@@ -354,7 +354,7 @@ xsltEvalVariables(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) {
            oldNode = ctxt->node;
            ctxt->insert = container;
 
-           xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree);
+           xsltApplyOneTemplate(ctxt, ctxt->node, NULL, elem->tree);
 
            ctxt->insert = oldInsert;
            ctxt->node = oldNode;
index 37f9e57..3565b7c 100644 (file)
@@ -1019,6 +1019,7 @@ xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) {
        return;
     ret->next = style->templates;
     style->templates = ret;
+    ret->style = style;
 
     /*
      * Get arguments
index caca594..3a89fe7 100644 (file)
@@ -52,6 +52,7 @@ typedef struct _xsltTemplate xsltTemplate;
 typedef xsltTemplate *xsltTemplatePtr;
 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 */
     xmlChar *name;     /* the local part of the name QName */
@@ -194,6 +195,11 @@ struct _xsltTransformContext {
     xsltStylesheetPtr style;           /* the stylesheet used */
     xsltOutputType type;               /* the type of output */
 
+    xsltTemplatePtr  templ;            /* the current template */
+    int              templNr;          /* Nb of templates in the stack */
+    int              templMax;         /* Size of the templtes stack */
+    xsltTemplatePtr *templTab;         /* the template stack */
+
     const xmlChar *mode;               /* the current mode */
     const xmlChar *modeURI;            /* the current mode URI */
 
index 3f9ec1d..e7d6048 100644 (file)
@@ -22,6 +22,7 @@
 #include "xsltutils.h"
 #include "templates.h"
 #include "xsltInternals.h"
+#include "imports.h"
 
 
 /************************************************************************
@@ -293,6 +294,7 @@ xsltSaveResultTo(xmlOutputBufferPtr buf, xmlDocPtr result,
     const xmlChar *encoding;
     xmlNodePtr root;
     int base;
+    const xmlChar *method;
 
     if ((buf == NULL) || (result == NULL) || (style == NULL))
        return(-1);
@@ -307,19 +309,23 @@ xsltSaveResultTo(xmlOutputBufferPtr buf, xmlDocPtr result,
 
     /* TODO: when outputing and having imported stylesheets, apply cascade */
     base = buf->written;
-    encoding = style->encoding;
-    if (style->method == NULL)
+
+    XSLT_GET_IMPORT_PTR(method, style, method)
+    XSLT_GET_IMPORT_PTR(encoding, style, encoding)
+
+    if (method == NULL)
        root = xmlDocGetRootElement(result);
     else
        root = NULL;
-    if ((style->method != NULL) &&
-       (xmlStrEqual(style->method, (const xmlChar *) "html"))) {
+
+    if ((method != NULL) &&
+       (xmlStrEqual(method, (const xmlChar *) "html"))) {
        htmlDocContentDumpOutput(buf, result, (const char *) encoding);
-    } else if ((style->method != NULL) &&
-       (xmlStrEqual(style->method, (const xmlChar *) "xhtml"))) {
+    } else if ((method != NULL) &&
+       (xmlStrEqual(method, (const xmlChar *) "xhtml"))) {
        htmlDocContentDumpOutput(buf, result, (const char *) encoding);
-    } else if ((style->method != NULL) &&
-              (xmlStrEqual(style->method, (const xmlChar *) "text"))) {
+    } else if ((method != NULL) &&
+              (xmlStrEqual(method, (const xmlChar *) "text"))) {
        xmlNodePtr cur;
 
        cur = result->children;
@@ -329,7 +335,21 @@ xsltSaveResultTo(xmlOutputBufferPtr buf, xmlDocPtr result,
            cur = cur->next;
        }
     } else {
-       if (style->omitXmlDeclaration != 1) {
+       int omitXmlDecl;
+       int standalone;
+       int indent;
+       const xmlChar *version;
+       const xmlChar *doctypePublic;
+       const xmlChar *doctypeSystem;
+
+       XSLT_GET_IMPORT_INT(omitXmlDecl, style, omitXmlDeclaration);
+       XSLT_GET_IMPORT_INT(standalone, style, standalone);
+       XSLT_GET_IMPORT_INT(indent, style, indent);
+       XSLT_GET_IMPORT_PTR(version, style, version)
+       XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
+       XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
+
+       if (omitXmlDecl != 1) {
            xmlOutputBufferWriteString(buf, "<?xml version=");
            if (result->version != NULL) 
                xmlBufferWriteQuotedString(buf->buffer, result->version);
@@ -347,7 +367,7 @@ xsltSaveResultTo(xmlOutputBufferPtr buf, xmlDocPtr result,
                xmlOutputBufferWriteString(buf, " encoding=");
                xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
            }
-           switch (style->standalone) {
+           switch (standalone) {
                case 0:
                    xmlOutputBufferWriteString(buf, " standalone=\"no\"");
                    break;
@@ -359,7 +379,7 @@ xsltSaveResultTo(xmlOutputBufferPtr buf, xmlDocPtr result,
            }
            xmlOutputBufferWriteString(buf, "?>\n");
        }
-       if ((style->doctypePublic != NULL) || (style->doctypeSystem != NULL)) {
+       if ((doctypePublic != NULL) || (doctypeSystem != NULL)) {
            xmlNodePtr cur = result->children;
 
            while (cur != NULL) {
@@ -370,24 +390,24 @@ xsltSaveResultTo(xmlOutputBufferPtr buf, xmlDocPtr result,
            if ((cur != NULL) && (cur->name != NULL)) {
                xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
                xmlOutputBufferWriteString(buf, cur->name);
-               if (style->doctypePublic != NULL) {
-                   if (style->doctypeSystem != NULL) {
+               if (doctypePublic != NULL) {
+                   if (doctypeSystem != NULL) {
                        xmlOutputBufferWriteString(buf, " PUBLIC ");
                        xmlBufferWriteQuotedString(buf->buffer,
-                                        style->doctypePublic);
+                                        doctypePublic);
                        xmlOutputBufferWriteString(buf, " ");
                        xmlBufferWriteQuotedString(buf->buffer,
-                                        style->doctypeSystem);
+                                        doctypeSystem);
                    } else {
                        xmlOutputBufferWriteString(buf, " PUBLIC \"-\" ");
                        xmlBufferWriteQuotedString(buf->buffer,
-                                        style->doctypeSystem);
+                                        doctypeSystem);
                    }
 
                } else {
                    xmlOutputBufferWriteString(buf, " SYSTEM ");
                    xmlBufferWriteQuotedString(buf->buffer,
-                                    style->doctypeSystem);
+                                    doctypeSystem);
                }
                xmlOutputBufferWriteString(buf, ">\n");
            }
@@ -396,7 +416,7 @@ xsltSaveResultTo(xmlOutputBufferPtr buf, xmlDocPtr result,
            xmlNodePtr child = result->children;
 
            while (child != NULL) {
-               xmlNodeDumpOutput(buf, result, child, 0, (style->indent == 1),
+               xmlNodeDumpOutput(buf, result, child, 0, (indent == 1),
                                  (const char *) encoding);
                xmlOutputBufferWriteString(buf, "\n");
                child = child->next;
@@ -423,15 +443,17 @@ int
 xsltSaveResultToFilename(const char *URL, xmlDocPtr result,
                         xsltStylesheetPtr style, int compression) {
     xmlOutputBufferPtr buf;
+    const xmlChar *encoding;
     int ret;
 
     if ((URL == NULL) || (result == NULL) || (style == NULL))
        return(-1);
 
-    if (style->encoding != NULL) {
+    XSLT_GET_IMPORT_PTR(encoding, style, encoding)
+    if (encoding != NULL) {
        xmlCharEncodingHandlerPtr encoder;
 
-       encoder = xmlFindCharEncodingHandler((char *)style->encoding);
+       encoder = xmlFindCharEncodingHandler((char *)encoding);
        if ((encoder != NULL) &&
            (xmlStrEqual((const xmlChar *)encoder->name,
                         (const xmlChar *) "UTF-8")))
@@ -462,15 +484,17 @@ xsltSaveResultToFilename(const char *URL, xmlDocPtr result,
 int
 xsltSaveResultToFile(FILE *file, xmlDocPtr result, xsltStylesheetPtr style) {
     xmlOutputBufferPtr buf;
+    const xmlChar *encoding;
     int ret;
 
     if ((file == NULL) || (result == NULL) || (style == NULL))
        return(-1);
 
-    if (style->encoding != NULL) {
+    XSLT_GET_IMPORT_PTR(encoding, style, encoding)
+    if (encoding != NULL) {
        xmlCharEncodingHandlerPtr encoder;
 
-       encoder = xmlFindCharEncodingHandler((char *)style->encoding);
+       encoder = xmlFindCharEncodingHandler((char *)encoding);
        if ((encoder != NULL) &&
            (xmlStrEqual((const xmlChar *)encoder->name,
                         (const xmlChar *) "UTF-8")))
@@ -502,15 +526,17 @@ xsltSaveResultToFile(FILE *file, xmlDocPtr result, xsltStylesheetPtr style) {
 int
 xsltSaveResultToFd(int fd, xmlDocPtr result, xsltStylesheetPtr style) {
     xmlOutputBufferPtr buf;
+    const xmlChar *encoding;
     int ret;
 
     if ((fd < 0) || (result == NULL) || (style == NULL))
        return(-1);
 
-    if (style->encoding != NULL) {
+    XSLT_GET_IMPORT_PTR(encoding, style, encoding)
+    if (encoding != NULL) {
        xmlCharEncodingHandlerPtr encoder;
 
-       encoder = xmlFindCharEncodingHandler((char *)style->encoding);
+       encoder = xmlFindCharEncodingHandler((char *)encoding);
        if ((encoder != NULL) &&
            (xmlStrEqual((const xmlChar *)encoder->name,
                         (const xmlChar *) "UTF-8")))
index f1cf513..b6bf213 100644 (file)
@@ -4,13 +4,13 @@ $(top_builddir)/libxslt/xsltproc:
        @(cd ../../libxslt ; make xsltproc)
 
 EXTRA_DIST = REC-xml-20001006.xml xmlspec-v21.dtd W3C-REC.css \
-             logo-REC xmlspec.xsl
+             logo-REC xmlspec.xsl REC-xml-2e.xsl diffspec.xsl
 
 all: test
 
 test tests: $(top_builddir)/libxslt/xsltproc
        @(rm -f .memdump ; touch .memdump)
-       @($(top_builddir)/libxslt/xsltproc -timing -v xmlspec.xsl REC-xml-20001006.xml > REC-xml-20001006.html 2> debug ; \
+       @($(top_builddir)/libxslt/xsltproc -timing -v REC-xml-2e.xsl REC-xml-20001006.xml > REC-xml-20001006.html 2> debug ; \
        grep implemented debug | sort | uniq -c ; \
        grep " ms$$" debug ; \
        grep "MORY ALLO" .memdump  | grep -v "MEMORY ALLOCATED : 0";\
diff --git a/tests/xmlspec/REC-xml-2e.xsl b/tests/xmlspec/REC-xml-2e.xsl
new file mode 100644 (file)
index 0000000..afe3fc1
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="1.0">
+
+<xsl:import href="diffspec.xsl"/>
+
+<xsl:template match="loc[@role='erratumref']">
+  <xsl:choose>
+    <xsl:when test="$show.diff.markup='0'">
+      <!-- nop -->
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:apply-imports/>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+<xsl:template match="loc[@role='erratumref']" mode="text">
+  <xsl:choose>
+    <xsl:when test="$show.diff.markup='0'">
+      <!-- nop -->
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:apply-imports/>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+
+</xsl:stylesheet>
+
diff --git a/tests/xmlspec/diffspec.xsl b/tests/xmlspec/diffspec.xsl
new file mode 100644 (file)
index 0000000..50e5887
--- /dev/null
@@ -0,0 +1,329 @@
+<?xml version="1.0"?>
+
+<!-- Version: $Id$ -->
+
+<!-- Stylesheet for @diff markup in XMLspec -->
+<!-- Author: Norman Walsh (Norman.Walsh@East.Sun.COM) -->
+<!-- Date Created: 2000.07.21 -->
+
+<!-- This stylesheet is copyright (c) 2000 by its authors.  Free
+     distribution and modification is permitted, including adding to
+     the list of authors and copyright holders, as long as this
+     copyright notice is maintained. -->
+
+<!-- This stylesheet attempts to implement the XML Specification V2.1
+     DTD.  Documents conforming to earlier DTDs may not be correctly
+     transformed.
+
+     This stylesheet supports the use of change-markup with the @diff
+     attribute. If you use @diff, you should always use this stylesheet.
+     If you want to turn off the highlighting of differences, use this
+     stylesheet, but set show.diff.markup to 0.
+
+     Using the original xmlspec stylesheet with @diff markup will cause
+     @diff=del text to be presented.
+-->
+
+<!-- ChangeLog:
+     25 Sep 2000: (Norman.Walsh@East.Sun.COM)
+       - Use inline diff markup (as opposed to block) for name and
+         affiliation
+       - Handle @diff='del' correctly in bibl and other list-contexts.
+     14 Aug 2000: (Norman.Walsh@East.Sun.COM)
+       - Support additional.title param
+     27 Jul 2000: (Norman.Walsh@East.Sun.COM)
+       - Fix HTML markup problem with diff'd authors in authlist
+     26 Jul 2000: (Norman.Walsh@East.Sun.COM)
+       - Update pointer to latest xmlspec-stylesheet.
+     21 Jul 2000: (Norman.Walsh@East.Sun.COM)
+       - Initial version
+-->
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+               version="1.0">
+
+<xsl:import href="xmlspec.xsl"/>
+
+<xsl:param name="show.diff.markup">1</xsl:param>
+
+<xsl:param name="additional.css">
+<xsl:if test="$show.diff.markup = '1'">
+<xsl:text>
+div.diff-add  { background-color: yellow }
+div.diff-del  { text-decoration: line-through }
+div.diff-chg  { background-color: lime }
+div.diff-off  {  }
+
+span.diff-add { background-color: yellow }
+span.diff-del { text-decoration: line-through }
+span.diff-chg { background-color: lime }
+span.diff-off {  }
+
+td.diff-add   { background-color: yellow }
+td.diff-del   { text-decoration: line-through }
+td.diff-chg   { background-color: lime }
+td.diff-off   {  }
+</xsl:text>
+</xsl:if>
+</xsl:param>
+
+<xsl:param name="additional.title">
+  <xsl:if test="$show.diff.markup != '0'">
+    <xsl:text>Review Version</xsl:text>
+  </xsl:if>
+</xsl:param>
+
+<xsl:param name="called.by.diffspec">1</xsl:param>
+
+<!-- ==================================================================== -->
+
+<xsl:template name="diff-markup">
+  <xsl:param name="diff">off</xsl:param>
+  <xsl:choose>
+    <xsl:when test="ancestor::scrap">
+      <!-- forget it, we can't add stuff inside tables -->
+      <!-- handled in base stylesheet -->
+      <xsl:apply-imports/>
+    </xsl:when>
+    <xsl:when test="self::gitem or self::bibl">
+      <!-- forget it, we can't add stuff inside dls; handled below -->
+      <xsl:apply-imports/>
+    </xsl:when>
+    <xsl:when test="ancestor-or-self::phrase">
+      <span class="diff-{$diff}">
+       <xsl:apply-imports/>
+      </span>
+    </xsl:when>
+    <xsl:when test="ancestor::p and not(self::p)">
+      <span class="diff-{$diff}">
+       <xsl:apply-imports/>
+      </span>
+    </xsl:when>
+    <xsl:when test="ancestor-or-self::affiliation">
+      <span class="diff-{$diff}">
+       <xsl:apply-imports/>
+      </span>
+    </xsl:when>
+    <xsl:when test="ancestor-or-self::name">
+      <span class="diff-{$diff}">
+       <xsl:apply-imports/>
+      </span>
+    </xsl:when>
+    <xsl:otherwise>
+      <div class="diff-{$diff}">
+       <xsl:apply-imports/>
+      </div>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+<xsl:template match="*[@diff='chg']">
+  <xsl:choose>
+    <xsl:when test="$show.diff.markup='1'">
+      <xsl:call-template name="diff-markup">
+       <xsl:with-param name="diff">chg</xsl:with-param>
+      </xsl:call-template>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:apply-imports/>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+<xsl:template match="*[@diff='add']">
+  <xsl:choose>
+    <xsl:when test="$show.diff.markup='1'">
+      <xsl:call-template name="diff-markup">
+       <xsl:with-param name="diff">add</xsl:with-param>
+      </xsl:call-template>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:apply-imports/>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+<xsl:template match="*[@diff='del']">
+  <xsl:choose>
+    <xsl:when test="$show.diff.markup='1'">
+      <xsl:call-template name="diff-markup">
+       <xsl:with-param name="diff">del</xsl:with-param>
+      </xsl:call-template>
+    </xsl:when>
+    <xsl:otherwise>
+      <!-- suppress deleted markup -->
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+<xsl:template match="*[@diff='off']">
+  <xsl:choose>
+    <xsl:when test="$show.diff.markup='1'">
+      <xsl:call-template name="diff-markup">
+       <xsl:with-param name="diff">off</xsl:with-param>
+      </xsl:call-template>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:apply-imports/>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+<!-- ================================================================= -->
+
+  <xsl:template match="bibl[@diff]" priority="1">
+    <xsl:variable name="dt">
+      <xsl:if test="@id">
+       <a name="{@id}"/>
+      </xsl:if>
+      <xsl:choose>
+       <xsl:when test="@key">
+         <xsl:value-of select="@key"/>
+       </xsl:when>
+       <xsl:otherwise>
+         <xsl:value-of select="@id"/>
+       </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+    <xsl:variable name="dd">
+      <xsl:apply-templates/>
+      <xsl:if test="@href">
+        <xsl:text>  (See </xsl:text>
+        <a href="{@href}">
+          <xsl:value-of select="@href"/>
+        </a>
+        <xsl:text>.)</xsl:text>
+      </xsl:if>
+    </xsl:variable>
+
+    <xsl:choose>
+      <xsl:when test="@diff and $show.diff.markup = '1'">
+       <dt class="label">
+         <span class="diff-{@diff}">
+           <xsl:copy-of select="$dt"/>
+         </span>
+       </dt>
+       <dd>
+         <div class="diff-{@diff}">
+           <xsl:copy-of select="$dd"/>
+         </div>
+       </dd>
+      </xsl:when>
+      <xsl:when test="@diff='del' and $show.diff.markup='0'">
+       <!-- suppressed -->
+      </xsl:when>
+      <xsl:otherwise>
+       <dt class="label">
+         <xsl:copy-of select="$dt"/>
+       </dt>
+       <dd>
+         <xsl:copy-of select="$dd"/>
+       </dd>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template match="gitem/label">
+    <xsl:variable name="diffval" select="ancestor-or-self::*/@diff"/>
+    <xsl:choose>
+      <xsl:when test="$diffval != '' and $show.diff.markup='1'">
+       <dt class="label">
+         <span class="diff-{ancestor-or-self::*/@diff}">
+           <xsl:apply-templates/>
+         </span>
+       </dt>
+      </xsl:when>
+      <xsl:when test="$diffval='del' and $show.diff.markup='0'">
+       <!-- suppressed -->
+      </xsl:when>
+      <xsl:otherwise>
+       <dt class="label">
+         <xsl:apply-templates/>
+       </dt>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template match="gitem/def">
+    <xsl:variable name="diffval" select="ancestor-or-self::*/@diff"/>
+    <xsl:choose>
+      <xsl:when test="$diffval != '' and $show.diff.markup='1'">
+       <dd>
+         <div class="diff-{ancestor-or-self::*/@diff}">
+           <xsl:apply-templates/>
+         </div>
+       </dd>
+      </xsl:when>
+      <xsl:when test="$diffval='del' and $show.diff.markup='0'">
+       <!-- suppressed -->
+      </xsl:when>
+      <xsl:otherwise>
+       <dd>
+         <xsl:apply-templates/>
+       </dd>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- authlist: list of authors (editors, really) -->
+  <!-- called in enforced order from header's template, in <dl>
+       context -->
+  <xsl:template match="authlist[@diff]">
+    <xsl:choose>
+      <xsl:when test="$show.diff.markup='1'">
+       <dt>
+         <span class="diff-{ancestor-or-self::*/@diff}">
+           <xsl:text>Editor</xsl:text>
+           <xsl:if test="count(author) > 1">
+             <xsl:text>s</xsl:text>
+           </xsl:if>
+           <xsl:text>:</xsl:text>
+         </span>
+       </dt>
+      </xsl:when>
+      <xsl:when test="@diff='del' and $show.diff.markup='0'">
+       <!-- suppressed -->
+      </xsl:when>
+      <xsl:otherwise>
+       <dt>
+         <xsl:text>Editor</xsl:text>
+         <xsl:if test="count(author) > 1">
+           <xsl:text>s</xsl:text>
+         </xsl:if>
+         <xsl:text>:</xsl:text>
+       </dt>
+      </xsl:otherwise>
+    </xsl:choose>
+    <xsl:apply-templates/>
+  </xsl:template>
+
+  <!-- author: an editor of a spec -->
+  <!-- only appears in authlist -->
+  <!-- called in <dl> context -->
+  <xsl:template match="author[@diff]" priority="1">
+    <xsl:choose>
+      <xsl:when test="@diff and $show.diff.markup='1'">
+       <dd>
+         <span class="diff-{ancestor-or-self::*/@diff}">
+           <xsl:apply-templates/>
+           <xsl:if test="@role = '2e'">
+             <xsl:text> - Second Edition</xsl:text>
+           </xsl:if>
+         </span>
+       </dd>
+      </xsl:when>
+      <xsl:when test="@diff='del' and $show.diff.markup='0'">
+       <!-- suppressed -->
+      </xsl:when>
+      <xsl:otherwise>
+       <dd>
+         <xsl:apply-templates/>
+         <xsl:if test="@role = '2e'">
+           <xsl:text> - Second Edition</xsl:text>
+         </xsl:if>
+       </dd>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+</xsl:stylesheet>