Merged all the namespace lookup/create/disable functions into
authorKasimier T. Buchcik <kbuchcik@src.gnome.org>
Mon, 19 Jun 2006 17:45:33 +0000 (17:45 +0000)
committerKasimier T. Buchcik <kbuchcik@src.gnome.org>
Mon, 19 Jun 2006 17:45:33 +0000 (17:45 +0000)
* libxslt/attributes.c libxslt/attrvt.c libxslt/namespaces.c
  libxslt/namespaces.h libxslt/preproc.c libxslt/templates.c
  libxslt/transform.c libxslt/variables.c libxslt/xslt.c
  libxslt/xsltInternals.h libxslt/xsltutils.c:
  Merged all the namespace lookup/create/disable functions
  into xsltGetSpecialNamespace(). Changed xsltGetNamespace()
  and xsltGetPlainNamespace() to call xsltGetSpecialNamespace(),
  but kept the ns-aliasing mechanism; the ns-aliasing needs
  to be removed when we move to the refactored code, which
  applies ns-alias only at compilaton time.
  Refactored xsltElementComp() (preproc.c); enhanced error reports.
  Fixed: if the "namespace" attribute was not given, then this
  performed incorrectly only a lookup for a default namespace;
  i.e., without taking any prefix on the "name" attribute into
  account.
  Refactored xsltElement() (transform.c); enhanced error reports.
  Refactored xsltAttributeComp() (preproc.c). Added namespace
  lookup as in xsltElementComp(). Enhanced error reports.
  Refactored xsltAttribute() (transform.c); enhanced error reports.
  xsltCopyTreeInternal(): eliminated the need to call xmlGetNsList()
  for every element in the tree; this needs to be done only for
  the top-most elements. For subsequent elements reconcile only
  the ns-declarations. Disallowed setting of ns-declarations if
  children have been already added to an element.
  Removed ns-aliasing code where necessary.
  xsltCopyProp(): disallowed setting of attribute nodes if
  children have been already added to an element.
  xsltCopy(): removed the incorrect skipping of attributes in the
  XSLT namespace. Removed the incorrect ns-aliasing for attributes.
  Changed to use the introduced function xsltShallowCopyAttr().
  xsltShallowCopyAttr():  Centralized all attribute-copy related
  code in this function. It will now be called by
  xsltCopyTreeInternal(), xsltCopyOf() and xsltCopy().
  xsltCopyAttrListNoOverwrite(): Renamed. Refactored. Optimized to
  use xsltGetSpecialNamespace() and xmlNewDocProp().
  Further substitution of various scattered namespace-lookup
  related code for the use of xsltGetSpecialNamespace().
  xsltAttrTemplateProcess(): Refactored. Removed the incorrect
  processing of attribute-sets. Attribute sets need to be applied
  before adding any normal attribute of the literal result element;
  this is now done in  xsltAttrListTemplateProcess(). Fixed to
  ensure that the ns-prefix of the overwriting attribute is used.
  xsltAttrListTemplateProcess(): Refactored. Moved semantics from
  xsltAttrTemplateProcess() over to this function in order to
  optimize processing of multiple attributes. This does not call
  xsltAttrTemplateProcess() anymore.
  Fixed: do not exclude the XSLT namespace after ns-aliasing have
  beed applied.
  The IFDEFed-out refactored code fixes the following issues:
  - #313711: namespace collision with namespace-alias (reported
              by by Oleg Paraschenko)
  - #338214: Incorrect scope for exclude-result-prefixes
  - #341392: Excluding namespace declarations of literal result
             elements.
  - #341325: Namespace aliasing and resulting namespace prefixes
  Already enabled fixes:
  - #344183: xsl:copy misses to copy attributes in the XSLT namespace
  - #341463: Namespace-alias using #default for result-prefix with no
        default namespace in scope
  - #313890: namespace collision with xsl:element and xsl:attribute,
        reported by Oleg Paraschenko
  - #344176: xsl:copy misses to set an element's namespace-URI in
             some cases
  - #305739: the "name" QName of xsl:element is incorrectly always
        resolved to the default namespace

12 files changed:
ChangeLog
libxslt/attributes.c
libxslt/attrvt.c
libxslt/namespaces.c
libxslt/namespaces.h
libxslt/preproc.c
libxslt/templates.c
libxslt/transform.c
libxslt/variables.c
libxslt/xslt.c
libxslt/xsltInternals.h
libxslt/xsltutils.c

index fe9ca19..2690b16 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,71 @@
+Mon Jun 19 13:33:50 CEST 2006 Kasimier Buchcik <libxml2-cvs@cazic.net>
+
+       * libxslt/attributes.c libxslt/attrvt.c libxslt/namespaces.c
+         libxslt/namespaces.h libxslt/preproc.c libxslt/templates.c
+         libxslt/transform.c libxslt/variables.c libxslt/xslt.c
+         libxslt/xsltInternals.h libxslt/xsltutils.c:
+         Merged all the namespace lookup/create/disable functions
+         into xsltGetSpecialNamespace(). Changed xsltGetNamespace()
+         and xsltGetPlainNamespace() to call xsltGetSpecialNamespace(),
+         but kept the ns-aliasing mechanism; the ns-aliasing needs
+         to be removed when we move to the refactored code, which
+         applies ns-alias only at compilaton time.
+         Refactored xsltElementComp() (preproc.c); enhanced error reports.
+         Fixed: if the "namespace" attribute was not given, then this
+         performed incorrectly only a lookup for a default namespace;
+         i.e., without taking any prefix on the "name" attribute into
+         account.
+         Refactored xsltElement() (transform.c); enhanced error reports.
+         Refactored xsltAttributeComp() (preproc.c). Added namespace
+         lookup as in xsltElementComp(). Enhanced error reports.
+         Refactored xsltAttribute() (transform.c); enhanced error reports.
+         xsltCopyTreeInternal(): eliminated the need to call xmlGetNsList()
+         for every element in the tree; this needs to be done only for
+         the top-most elements. For subsequent elements reconcile only
+         the ns-declarations. Disallowed setting of ns-declarations if
+         children have been already added to an element.
+         Removed ns-aliasing code where necessary.
+         xsltCopyProp(): disallowed setting of attribute nodes if
+         children have been already added to an element.
+         xsltCopy(): removed the incorrect skipping of attributes in the
+         XSLT namespace. Removed the incorrect ns-aliasing for attributes.
+         Changed to use the introduced function xsltShallowCopyAttr().
+         xsltShallowCopyAttr():  Centralized all attribute-copy related
+         code in this function. It will now be called by
+         xsltCopyTreeInternal(), xsltCopyOf() and xsltCopy().
+         xsltCopyAttrListNoOverwrite(): Renamed. Refactored. Optimized to
+         use xsltGetSpecialNamespace() and xmlNewDocProp().
+         Further substitution of various scattered namespace-lookup
+         related code for the use of xsltGetSpecialNamespace().
+         xsltAttrTemplateProcess(): Refactored. Removed the incorrect
+         processing of attribute-sets. Attribute sets need to be applied
+         before adding any normal attribute of the literal result element;
+         this is now done in  xsltAttrListTemplateProcess(). Fixed to
+         ensure that the ns-prefix of the overwriting attribute is used.
+         xsltAttrListTemplateProcess(): Refactored. Moved semantics from
+         xsltAttrTemplateProcess() over to this function in order to
+         optimize processing of multiple attributes. This does not call
+         xsltAttrTemplateProcess() anymore.
+         Fixed: do not exclude the XSLT namespace after ns-aliasing have
+         beed applied.
+         The IFDEFed-out refactored code fixes the following issues:
+         - #313711: namespace collision with namespace-alias (reported
+                     by by Oleg Paraschenko)
+         - #338214: Incorrect scope for exclude-result-prefixes
+         - #341392: Excluding namespace declarations of literal result
+                    elements.
+         - #341325: Namespace aliasing and resulting namespace prefixes
+         Already enabled fixes:
+         - #344183: xsl:copy misses to copy attributes in the XSLT namespace
+         - #341463: Namespace-alias using #default for result-prefix with no
+                    default namespace in scope
+         - #313890: namespace collision with xsl:element and xsl:attribute,
+                    reported by Oleg Paraschenko
+         - #344176: xsl:copy misses to set an element's namespace-URI in
+                    some cases
+         - #305739: the "name" QName of xsl:element is incorrectly always
+                    resolved to the default namespace
+
 Mon Jun 12 16:34:15 CEST 2006 Daniel Veillard <daniel@veillard.com>
 
        * doc/xsltproc.1 doc/xsltproc.xml: more info about --output
index 2f5d660..46e365c 100644 (file)
@@ -629,7 +629,7 @@ xsltResolveStylesheetAttributeSet(xsltStylesheetPtr style) {
 /**
  * xsltAttributeInternal:
  * @ctxt:  a XSLT process context
- * @node:  the node in the source tree.
+ * @node:  the current node in the source tree
  * @inst:  the xsl:attribute element
  * @comp:  precomputed information
  * @fromAttributeSet:  the attribute comes from an attribute-set
@@ -637,20 +637,15 @@ xsltResolveStylesheetAttributeSet(xsltStylesheetPtr style) {
  * Process the xslt attribute node on the source node
  */
 static void
-xsltAttributeInternal(xsltTransformContextPtr ctxt, xmlNodePtr node,
+xsltAttributeInternal(xsltTransformContextPtr ctxt,
+                     xmlNodePtr currentNode,
                       xmlNodePtr inst,
                      xsltStylePreCompPtr castedComp,
-                      int fromAttributeSet) {
+                      int fromAttributeSet)
+{
 #ifdef XSLT_REFACTORED
     xsltStyleItemAttributePtr comp =
-       (xsltStyleItemAttributePtr) castedComp;
-    /*
-    * TODO: Change the fields of the compiled struct:
-    *  1) @name (char)
-    *  2) @nameType (String, AVT)
-    *  3) @nsName (char)
-    *  4) nsNameType (None, String, AVT)
-    */
+       (xsltStyleItemAttributePtr) castedComp;   
 #else
     xsltStylePreCompPtr comp = castedComp;
 #endif
@@ -661,7 +656,14 @@ xsltAttributeInternal(xsltTransformContextPtr ctxt, xmlNodePtr node,
     xmlNsPtr ns = NULL;
     xmlAttrPtr attr;    
 
-    if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
+    if ((ctxt == NULL) || (currentNode == NULL) || (inst == NULL))
+        return;
+
+    /* 
+    * A comp->has_name == 0 indicates that we need to skip this instruction,
+    * since it was evaluated to be invalid already during compilation.
+    */
+    if (!comp->has_name)
         return;
     /*
     * BIG NOTE: This previously used xsltGetSpecialNamespace() and
@@ -725,13 +727,11 @@ xsltAttributeInternal(xsltTransformContextPtr ctxt, xmlNodePtr node,
     /*
     * Process the name
     * ----------------
-    */
-    if (!comp->has_name) /* TODO: raise error */
-        return;
+    */    
 
 #ifdef WITH_DEBUGGER
     if (ctxt->debugStatus != XSLT_DEBUG_NONE)
-        xslHandleDebugger(inst, node, NULL, ctxt);
+        xslHandleDebugger(inst, currentNode, NULL, ctxt);
 #endif
 
     if (comp->name == NULL) {
@@ -751,34 +751,55 @@ xsltAttributeInternal(xsltTransformContextPtr ctxt, xmlNodePtr node,
        }
        name = xsltSplitQName(ctxt->dict, prop, &prefix);
        xmlFree(prop);
-    } else {
-       name = xsltSplitQName(ctxt->dict, comp->name, &prefix);
-    }
 
-    if (!xmlStrncasecmp(prefix, (xmlChar *) "xmlns", 5)) {
+       /*
+       * Reject a prefix of "xmlns".
+       */
+       if ((prefix != NULL) &&
+           (!xmlStrncasecmp(prefix, (xmlChar *) "xmlns", 5)))
+       {
 #ifdef WITH_XSLT_DEBUG_PARSING
-        xsltGenericDebug(xsltGenericDebugContext,
-           "xsltAttribute: xmlns prefix forbidden\n");
+           xsltGenericDebug(xsltGenericDebugContext,
+               "xsltAttribute: xmlns prefix forbidden\n");
 #endif
+           /*
+           * SPEC XSLT 1.0:
+           *  "It is an error if the string that results from instantiating
+           *  the attribute value template is not a QName or is the string
+           *  xmlns. An XSLT processor may signal the error; if it does not
+           *  signal the error, it must recover by not adding the attribute
+           *  to the result tree."
+           * TODO: Decide which way to go here.
+           */
+           goto error;
+       }
+
+    } else {
        /*
-       * SPEC XSLT 1.0:
-       *  "It is an error if the string that results from instantiating
-       *  the attribute value template is not a QName or is the string
-       *  xmlns. An XSLT processor may signal the error; if it does not
-       *  signal the error, it must recover by not adding the attribute
-       *  to the result tree."
-       * TODO: Decide which way to go here.
+       * The "name" value was static.
        */
-        goto error;
+#ifdef XSLT_REFACTORED
+       prefix = comp->nsPrefix;
+       name = comp->name;
+#else
+       name = xsltSplitQName(ctxt->dict, comp->name, &prefix);
+#endif
     }
+    
     /*
     * Process namespace semantics
     * ---------------------------
     *
     * Evaluate the namespace name.
     */
-    if (comp->has_ns) {         
+    if (comp->has_ns) {
+       /*
+       * The "namespace" attribute was existent.
+       */
        if (comp->ns != NULL) {
+           /*
+           * No AVT; just plain text for the namespace name.
+           */
            if (comp->ns[0] != 0)
                nsName = comp->ns;
        } else {
@@ -816,19 +837,21 @@ xsltAttributeInternal(xsltTransformContextPtr ctxt, xmlNodePtr node,
            *  Saxon, Xalan-J and MSXML).
            */
            xsltTransformError(ctxt, NULL, inst,
-               "xsl:attribute: The effective prefix '%s', has no "
+               "xsl:attribute: The QName '%s:%s' has no "
                "namespace binding in scope in the stylesheet; "
                "this is an error, since the namespace was not "
-               "specified by the instruction itself.\n", prefix);
+               "specified by the instruction itself.\n", prefix, name);
        } else
            nsName = ns->href;  
     }
 
     if (fromAttributeSet) {
        /*
-       * I think this tries to ensure that xsl:attribute(s) coming
+       * This tries to ensure that xsl:attribute(s) coming
        * from an xsl:attribute-set won't override attribute of
        * literal result elements or of explicit xsl:attribute(s).
+       * URGENT TODO: This might be buggy, since it will miss to
+       *  overwrite two equal attributes both from attribute sets.
        */
        attr = xmlHasNsProp(targetElem, name, nsName);
        if (attr != NULL)
@@ -836,22 +859,15 @@ xsltAttributeInternal(xsltTransformContextPtr ctxt, xmlNodePtr node,
     }
 
     /*
-    * Something about ns-prefixes:
-    * SPEC XSLT 1.0:
-    *  "XSLT processors may make use of the prefix of the QName specified
-    *  in the name attribute when selecting the prefix used for outputting
-    *  the created attribute as XML; however, they are not required to do
-    *  so and, if the prefix is xmlns, they must not do so"
-    */        
-    /*
     * Find/create a matching ns-decl in the result tree.
     */
     ns = NULL;
+    
 #if 0
     if (0) {   
        /*
        * OPTIMIZE TODO: How do we know if we are adding to a
-       *  fragment or not?
+       *  fragment or to the result tree?
        *
        * If we are adding to a result tree fragment (i.e., not to the
        * actual result tree), we'll don't bother searching for the
@@ -864,95 +880,37 @@ xsltAttributeInternal(xsltTransformContextPtr ctxt, xmlNodePtr node,
        }
     }
 #endif
-    if (nsName != NULL) {
-       /*
-       * The owner-element might be in the same namespace.
-       */
-       if ((targetElem->ns != NULL) &&
-           (targetElem->ns->prefix != NULL) &&     
-           xmlStrEqual(targetElem->ns->href, nsName))
-       {
-           ns = targetElem->ns;
-           goto namespace_finished;
-       }
-       if (prefix != NULL) {
-           /*
-           * Search by ns-prefix.
-           */
-           ns = xmlSearchNs(targetElem->doc, targetElem, prefix);
-           if ((ns != NULL) && (xmlStrEqual(ns->href, nsName))) {
-               goto namespace_finished;
-           }
-       }
-       /*
-       * Fallback to a search by ns-name.
-       */      
-       ns = xmlSearchNsByHref(targetElem->doc, targetElem, nsName);
-       if ((ns != NULL) && (ns->prefix != NULL)) {
-           goto namespace_finished;
-       }
+
+    if (nsName != NULL) {      
        /*
-       * OK, we need to declare the namespace on the target element.
+       * Something about ns-prefixes:
+       * SPEC XSLT 1.0:
+       *  "XSLT processors may make use of the prefix of the QName specified
+       *  in the name attribute when selecting the prefix used for outputting
+       *  the created attribute as XML; however, they are not required to do
+       *  so and, if the prefix is xmlns, they must not do so"
        */
-       if (prefix) {
-           if (targetElem->nsDef != NULL) {
-               ns = targetElem->nsDef;
-               do {
-                   if ((ns->prefix) && xmlStrEqual(ns->prefix, prefix)) {
-                       /*
-                       * The prefix is aready occupied.
-                       */
-                       break;
-                   }
-                   ns = ns->next;
-               } while (ns != NULL);
-               if (ns == NULL) {
-                   ns = xmlNewNs(targetElem, nsName, prefix);
-                   goto namespace_finished;
-               }
-           }
-       }
        /*
-       * Generate a new prefix.
+       * xsl:attribute can produce a scenario where the prefix is NULL,
+       * so generate a prefix.
        */
-       {
-           const xmlChar *basepref = prefix;
-           xmlChar pref[30];
-           int counter = 1;
-           
-           if (prefix != NULL)
-               basepref = prefix;
-           else
-               basepref = xmlStrdup(BAD_CAST "ns");
-           
-           do {
-               snprintf((char *) pref, 30, "%s%d",
-                   basepref, counter++);
-               ns = xmlSearchNs(targetElem->doc, targetElem, BAD_CAST pref);
-               if (counter > 1000) {
-                   xsltTransformError(ctxt, NULL, inst,
-                       "Namespace fixup error: Failed to compute a "
-                       "new unique ns-prefix for the generated attribute "
-                       "{%s}%s'.\n", nsName, name);                                    
-                   ns = NULL;
-                   break;
-               }
-           } while (ns != NULL);
-           if (basepref != prefix)
-               xmlFree((xmlChar *)basepref);
-           ns = xmlNewNs(targetElem, nsName, BAD_CAST pref);
-       }
+       if (prefix == NULL) {
+           xmlChar *pref = xmlStrdup(BAD_CAST "ns_1");
 
-namespace_finished:
+           ns = xsltGetSpecialNamespace(ctxt, inst, nsName, BAD_CAST pref,
+               targetElem);
 
+           xmlFree(pref);
+       } else {
+           ns = xsltGetSpecialNamespace(ctxt, inst, nsName, prefix,
+               targetElem);
+       }
        if (ns == NULL) {
            xsltTransformError(ctxt, NULL, inst,
                "Namespace fixup error: Failed to acquire an in-scope "
-               "namespace binding of the generated attribute '{%s}%s'.\n",
+               "namespace binding for the generated attribute '{%s}%s'.\n",
                nsName, name);
-           /*
-           * TODO: Should we just stop here?
-           */
+           goto error;
        }
     }
     /*
@@ -969,11 +927,10 @@ namespace_finished:
            ((inst->children->type == XML_TEXT_NODE) ||
             (inst->children->type == XML_CDATA_SECTION_NODE)))
     {
-       xmlNodePtr origTxt = inst->children, copyTxt;
+       xmlNodePtr copyTxt;
+       
        /*
-       * Optimization: if the content is just 1 text node, then
-       * just need to copy it over, or just assign it to the result
-       * if the string is shared.
+       * xmlSetNsProp() will take care of duplicates.
        */
        attr = xmlSetNsProp(ctxt->insert, ns, name, NULL);
        if (attr == NULL) /* TODO: report error ? */
@@ -992,44 +949,46 @@ namespace_finished:
            * This is a safe scenario where we don't need to lookup
            * the dict.
            */
-           copyTxt->content = origTxt->content;
+           copyTxt->content = inst->children->content;
            /*
            * Copy "disable-output-escaping" information.
            * TODO: Does this have any effect for attribute values
            *  anyway?
            */
-           if (origTxt->name == xmlStringTextNoenc)
+           if (inst->children->name == xmlStringTextNoenc)
                copyTxt->name = xmlStringTextNoenc;
        } else {
            /*
            * Copy the value.
            */
-           copyTxt = xmlNewText(origTxt->content);
+           copyTxt = xmlNewText(inst->children->content);
            if (copyTxt == NULL) /* TODO: report error */
-               goto error;
-           /*
-           * Copy "disable-output-escaping" information.
-           * TODO: Does this have any effect for attribute values
-           *  anyway?
-           */
-           if (origTxt->name == xmlStringTextNoenc)
-               copyTxt->name = xmlStringTextNoenc;
-       }
-       if (copyTxt != NULL) {
-           copyTxt->doc = attr->doc;
-           xmlAddChild((xmlNodePtr) attr, copyTxt);
+               goto error;                 
        }
+       attr->children = attr->last = copyTxt;
+       copyTxt->parent = (xmlNodePtr) attr;
+       copyTxt->doc = attr->doc;
+       /*
+       * Copy "disable-output-escaping" information.
+       * TODO: Does this have any effect for attribute values
+       *  anyway?
+       */
+       if (inst->children->name == xmlStringTextNoenc)
+           copyTxt->name = xmlStringTextNoenc; 
+
     } else {
        /*
        * The sequence constructor might be complex, so instantiate it.
        */
-       value = xsltEvalTemplateString(ctxt, node, inst);
+       value = xsltEvalTemplateString(ctxt, currentNode, inst);
        if (value != NULL) {
            attr = xmlSetNsProp(ctxt->insert, ns, name, value);
            xmlFree(value);
        } else {
            /*
            * TODO: Do we have to add the empty string to the attr?
+           * TODO: Does a  value of NULL indicate an
+           *  error in xsltEvalTemplateString() ?
            */
            attr = xmlSetNsProp(ctxt->insert, ns, name,
                (const xmlChar *) "");
@@ -1059,69 +1018,100 @@ xsltAttribute(xsltTransformContextPtr ctxt, xmlNodePtr node,
  * xsltApplyAttributeSet:
  * @ctxt:  the XSLT stylesheet
  * @node:  the node in the source tree.
- * @inst:  the xslt attribute node
- * @attributes:  the set list.
+ * @inst:  the attribute node "xsl:use-attribute-sets"
+ * @attrSets:  the list of QNames of the attribute-sets to be applied
  *
- * Apply the xsl:use-attribute-sets
+ * Apply the xsl:use-attribute-sets.
+ * If @attrSets is NULL, then @inst will be used to exctract this
+ * value.
+ * If both, @attrSets and @inst, are NULL, then this will do nothing.
  */
-
 void
 xsltApplyAttributeSet(xsltTransformContextPtr ctxt, xmlNodePtr node,
-                      xmlNodePtr inst ATTRIBUTE_UNUSED,
-                      const xmlChar * attributes)
+                      xmlNodePtr inst,
+                      const xmlChar *attrSets)
 {
     const xmlChar *ncname = NULL;
-    const xmlChar *prefix = NULL;
-    const xmlChar *attrib, *endattr;
-    xsltAttrElemPtr values;
-    xsltStylesheetPtr style;
+    const xmlChar *prefix = NULL;    
+    const xmlChar *curstr, *endstr;
+    xsltAttrElemPtr attrs;
+    xsltStylesheetPtr style;    
 
-    if (attributes == NULL) {
-        return;
+    if (attrSets == NULL) {
+       if (inst == NULL)
+           return;
+       else {
+           /*
+           * Extract the value from @inst.
+           */
+           if (inst->type == XML_ATTRIBUTE_NODE) {
+               if ( ((xmlAttrPtr) inst)->children != NULL)
+                   attrSets = ((xmlAttrPtr) inst)->children->content;
+               
+           }
+           if (attrSets == NULL) {
+               /*
+               * TODO: Return an error?
+               */
+               return;
+           }
+       }
     }
-
-    attrib = attributes;
-    while (*attrib != 0) {
-        while (IS_BLANK(*attrib))
-            attrib++;
-        if (*attrib == 0)
+    /*
+    * Parse/apply the list of QNames.
+    */
+    curstr = attrSets;
+    while (*curstr != 0) {
+        while (IS_BLANK(*curstr))
+            curstr++;
+        if (*curstr == 0)
             break;
-        endattr = attrib;
-        while ((*endattr != 0) && (!IS_BLANK(*endattr)))
-            endattr++;
-        attrib = xmlDictLookup(ctxt->dict, attrib, endattr - attrib);
-        if (attrib) {
-#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
+        endstr = curstr;
+        while ((*endstr != 0) && (!IS_BLANK(*endstr)))
+            endstr++;
+        curstr = xmlDictLookup(ctxt->dict, curstr, endstr - curstr);
+        if (curstr) {
+           /*
+           * TODO: Validate the QName.
+           */
+
+#ifdef WITH_XSLT_DEBUG_curstrUTES
             xsltGenericDebug(xsltGenericDebugContext,
-                             "apply attribute set %s\n", attrib);
+                             "apply curstrute set %s\n", curstr);
 #endif
-            ncname = xsltSplitQName(ctxt->dict, attrib, &prefix);
+            ncname = xsltSplitQName(ctxt->dict, curstr, &prefix);
 
             style = ctxt->style;
+
 #ifdef WITH_DEBUGGER
-            if ((style != NULL) && (style->attributeSets != NULL) &&
-               (ctxt->debugStatus != XSLT_DEBUG_NONE)) {
-                values =
+            if ((style != NULL) &&
+               (style->attributeSets != NULL) &&
+               (ctxt->debugStatus != XSLT_DEBUG_NONE))
+           {
+                attrs =
                     xmlHashLookup2(style->attributeSets, ncname, prefix);
-                if ((values != NULL) && (values->attr != NULL))
-                    xslHandleDebugger(values->attr->parent, node, NULL,
-                                      ctxt);
+                if ((attrs != NULL) && (attrs->attr != NULL))
+                    xslHandleDebugger(attrs->attr->parent, node, NULL,
+                       ctxt);
             }
 #endif
+           /*
+           * Lookup the referenced curstrute-set.
+           */
             while (style != NULL) {
-                values =
+                attrs =
                     xmlHashLookup2(style->attributeSets, ncname, prefix);
-                while (values != NULL) {
-                    if (values->attr != NULL) {
-                        xsltAttributeInternal(ctxt, node, values->attr,
-                                              values->attr->psvi, 1);
+                while (attrs != NULL) {
+                    if (attrs->attr != NULL) {
+                        xsltAttributeInternal(ctxt, node, attrs->attr,
+                           attrs->attr->psvi, 1);
                     }
-                    values = values->next;
+                    attrs = attrs->next;
                 }
                 style = xsltNextImport(style);
             }
         }
-        attrib = endattr;
+        curstr = endstr;
     }
 }
 
index cafcf74..b63b77b 100644 (file)
@@ -181,7 +181,8 @@ xsltCompileAttr(xsltStylesheetPtr style, xmlAttrPtr attr) {
     if ((attr->children->type != XML_TEXT_NODE) || 
         (attr->children->next != NULL)) {
         xsltTransformError(NULL, style, attr->parent,
-               "Attribute %s content is not a text node\n", attr->name);
+           "Attribute '%s': The content is expected to be a single text "
+           "node when compiling an AVT.\n", attr->name);
        style->errors++;
        return;
     }
@@ -200,8 +201,12 @@ xsltCompileAttr(xsltStylesheetPtr style, xmlAttrPtr attr) {
 #endif
         return;
     }
+    /*
+    * Create a new AVT object.
+    */
     avt = xsltNewAttrVT(style);
-    if (avt == NULL) return;
+    if (avt == NULL)
+       return;
     attr->psvi = avt;
 
     avt->nsList = xmlGetNsList(attr->doc, attr->parent);
@@ -223,7 +228,7 @@ xsltCompileAttr(xsltStylesheetPtr style, xmlAttrPtr attr) {
            }
            if (*(cur+1) == '}') {      /* skip empty AVT */
                ret = xmlStrncat(ret, str, cur - str);
-               cur+=2;
+               cur += 2;
                str = cur;
                continue;
            }
@@ -232,7 +237,7 @@ xsltCompileAttr(xsltStylesheetPtr style, xmlAttrPtr attr) {
                str = cur;
                if (avt->nb_seg == 0)
                    avt->strstart = 1;
-               if ((avt=xsltSetAttrVTsegment(avt, (void *) ret)) == NULL)
+               if ((avt = xsltSetAttrVTsegment(avt, (void *) ret)) == NULL)
                    goto error;
                ret = NULL;
                lastavt = 0;
@@ -242,13 +247,17 @@ xsltCompileAttr(xsltStylesheetPtr style, xmlAttrPtr attr) {
            while ((*cur != 0) && (*cur != '}')) cur++;
            if (*cur == 0) {
                xsltTransformError(NULL, style, attr->parent,
-                    "Attribute template %s: unmatched '{'\n", attr->name);
+                    "Attribute '%s': The AVT has an unmatched '{'.\n",
+                    attr->name);
                style->errors++;
                goto error;
            }
            str++;
            expr = xmlStrndup(str, cur - str);
            if (expr == NULL) {
+               /*
+               * TODO: What needs to be done here?
+               */
                XSLT_TODO
                goto error;
            } else {
@@ -257,18 +266,18 @@ xsltCompileAttr(xsltStylesheetPtr style, xmlAttrPtr attr) {
                comp = xsltXPathCompile(style, expr);
                if (comp == NULL) {
                    xsltTransformError(NULL, style, attr->parent,
-                        "Attribute template %s: failed to compile %s\n",
-                                      attr->name, expr);
+                        "Attribute '%s': Failed to compile the expression "
+                        "'%s' in the AVT.\n", attr->name, expr);
                    style->errors++;
                    goto error;
                }
                if (avt->nb_seg == 0)
                    avt->strstart = 0;
                if (lastavt == 1) {
-                   if ((avt=xsltSetAttrVTsegment(avt, NULL)) == NULL)
+                   if ((avt = xsltSetAttrVTsegment(avt, NULL)) == NULL)
                        goto error;
                }
-               if ((avt=xsltSetAttrVTsegment(avt, (void *) comp))==NULL)
+               if ((avt = xsltSetAttrVTsegment(avt, (void *) comp)) == NULL)
                    goto error;
                lastavt = 1;
                xmlFree(expr);
@@ -285,7 +294,8 @@ xsltCompileAttr(xsltStylesheetPtr style, xmlAttrPtr attr) {
                continue;
            } else {
                xsltTransformError(NULL, style, attr->parent,
-                    "Attribute template %s: unmatched '}'\n", attr->name);
+                    "Attribute '%s': The AVT has an unmatched '}'.\n",
+                    attr->name);
                goto error;
            }
        } else
@@ -296,7 +306,7 @@ xsltCompileAttr(xsltStylesheetPtr style, xmlAttrPtr attr) {
        str = cur;
        if (avt->nb_seg == 0)
            avt->strstart = 1;
-       if ((avt=xsltSetAttrVTsegment(avt, (void *) ret)) == NULL)
+       if ((avt = xsltSetAttrVTsegment(avt, (void *) ret)) == NULL)
            goto error;
        ret = NULL;
     }
index 8f783bb..0cb302d 100644 (file)
@@ -196,15 +196,15 @@ xsltNamespaceAlias(xsltStylesheetPtr style, xmlNodePtr node)
      */
     
        
-       /*
-       * Store the ns-node in the alias-object.
-       */
-       alias = xsltNewNsAlias(XSLT_CCTXT(style));
-       if (alias == NULL)
-           return;
-       alias->literalNs = literalNs;
-       alias->targetNs = targetNs;
-       XSLT_CCTXT(style)->hasNsAliases = 1;
+     /*
+     * Store the ns-node in the alias-object.
+    */
+    alias = xsltNewNsAlias(XSLT_CCTXT(style));
+    if (alias == NULL)
+       return;
+    alias->literalNs = literalNs;
+    alias->targetNs = targetNs;
+    XSLT_CCTXT(style)->hasNsAliases = 1;
 
 
 #else /* XSLT_REFACTORED */
@@ -309,264 +309,294 @@ error:
 }
 
 /**
- * xsltNsInScope:
- * @doc:  the document
- * @node:  the current node
- * @ancestor:  the ancestor carrying the namespace
- * @prefix:  the namespace prefix
- *
- * Copy of xmlNsInScope which is not public ...
- * 
- * Returns 1 if true, 0 if false and -1 in case of error.
- */
-static int
-xsltNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
-             xmlNodePtr ancestor, const xmlChar * prefix)
-{
-    xmlNsPtr tst;
-
-    while ((node != NULL) && (node != ancestor)) {
-        if ((node->type == XML_ENTITY_REF_NODE) ||
-            (node->type == XML_ENTITY_NODE) ||
-            (node->type == XML_ENTITY_DECL))
-            return (-1);
-        if (node->type == XML_ELEMENT_NODE) {
-            tst = node->nsDef;
-            while (tst != NULL) {
-                if ((tst->prefix == NULL)
-                    && (prefix == NULL))
-                    return (0);
-                if ((tst->prefix != NULL)
-                    && (prefix != NULL)
-                    && (xmlStrEqual(tst->prefix, prefix)))
-                    return (0);
-                tst = tst->next;
-            }
-        }
-        node = node->parent;
-    }
-    if (node != ancestor)
-        return (-1);
-    return (1);
-}
-
-/**
- * xsltSearchPlainNsByHref:
- * @doc:  the document
- * @node:  the current node
- * @href:  the namespace value
- *
- * Search a Ns aliasing a given URI and without a NULL prefix.
- * Recurse on the parents until it finds
- * the defined namespace or return NULL otherwise.
- * Returns the namespace pointer or NULL.
- */
-static xmlNsPtr
-xsltSearchPlainNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
-{
-    xmlNsPtr cur;
-    xmlNodePtr orig = node;
-
-    if ((node == NULL) || (href == NULL))
-        return (NULL);
-
-    while (node != NULL) {
-        if ((node->type == XML_ENTITY_REF_NODE) ||
-            (node->type == XML_ENTITY_NODE) ||
-            (node->type == XML_ENTITY_DECL))
-            return (NULL);
-        if (node->type == XML_ELEMENT_NODE) {
-            cur = node->nsDef;
-            while (cur != NULL) {
-                if ((cur->href != NULL) && (cur->prefix != NULL) &&
-                   (href != NULL) && (xmlStrEqual(cur->href, href))) {
-                   if (xsltNsInScope(doc, orig, node, cur->href) == 1)
-                       return (cur);
-                }
-                cur = cur->next;
-            }
-            if (orig != node) {
-                cur = node->ns;
-                if (cur != NULL) {
-                    if ((cur->href != NULL) && (cur->prefix != NULL) &&
-                       (href != NULL) && (xmlStrEqual(cur->href, href))) {
-                       if (xsltNsInScope(doc, orig, node, cur->href) == 1)
-                           return (cur);
-                    }
-                }
-            }    
-        }
-        node = node->parent;
-    }
-    return (NULL);
-}
-
-/**
- * xsltGetPlainNamespace:
- * @ctxt:  a transformation context
- * @cur:  the input node
- * @ns:  the namespace
- * @out:  the output node (or its parent)
+ * xsltGetSpecialNamespace:
+ * @ctxt:  the transformation context
+ * @invocNode: the invoking node; e.g. a literal result element/attr;
+ *             only used for error reports
+ * @nsName:  the namespace name (or NULL)
+ * @nsPrefix:  the suggested namespace prefix (or NULL)
+ * @target:  the result element on which to anchor a namespace
  *
- * Find the right namespace value for this prefix, if needed create
- * and add a new namespace decalaration on the node
- * Handle namespace aliases and make sure the prefix is not NULL, this
- * is needed for attributes.
- * Called from:
- *   xsltAttrTemplateProcess() (templates.c)
- *   xsltCopyProp() (transform.c)
+ * Find a matching (prefix and ns-name) ns-declaration
+ * for the requested @nsName and @nsPrefix in the result tree.
+ * If none is found then a new ns-declaration will be
+ * added to @resultElem. If, in this case, the given prefix is
+ * already in use, then a ns-declaration with a modified ns-prefix
+ * be we created. Note that this function's priority is to
+ * preserve ns-prefixes; it will only change a prefix if there's
+ * a namespace clash.
+ * If both @nsName and @nsPrefix are NULL, then this will try to
+ * "undeclare" a default namespace by declaring an xmlns="".
  *
- * Returns the namespace node to use or NULL
+ * Returns a namespace declaration or NULL.
  */
 xmlNsPtr
-xsltGetPlainNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur,
-                      xmlNsPtr ns, xmlNodePtr out) {    
-    xmlNsPtr ret;
-    const xmlChar *URI = NULL; /* the replacement URI */
+xsltGetSpecialNamespace(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
+               const xmlChar *nsName, const xmlChar *nsPrefix,
+               xmlNodePtr target)
+{
+    xmlNsPtr ns;
+    int prefixOccupied = 0;
 
-    if ((ctxt == NULL) || (cur == NULL) || (out == NULL) || (ns == NULL))
+    if ((ctxt == NULL) || (target == NULL) ||
+       (target->type != XML_ELEMENT_NODE))
        return(NULL);
 
-#ifdef XSLT_REFACTORED
     /*
-    * Namespace exclusion and ns-aliasing is performed at
-    * compilation-time in the refactored code.
+    * NOTE: Namespace exclusion and ns-aliasing is performed at
+    *  compilation-time in the refactored code; so this need not be done
+    *  here (it was in the old code).
+    * NOTE: @invocNode was named @cur in the old code and was documented to
+    *  be an input node; since it was only used to anchor an error report
+    *  somewhere, we can safely change this to @invocNode, which now
+    *  will be the XSLT instruction (also a literal result element/attribute),
+    *  which was responsible for this call.
     */
-    URI = ns->href;
-#else
-    {
-       xsltStylesheetPtr style;
-       style = ctxt->style;
-       while (style != NULL) {
-           if (style->nsAliases != NULL)
-               URI = (const xmlChar *) xmlHashLookup(style->nsAliases, ns->href);
-           if (URI != NULL)
-               break;
+    /*
+    * OPTIMIZE TODO: This all could be optimized by keeping track of
+    *  the ns-decls currently in-scope via a specialized context.
+    */    
+    if ((nsPrefix == NULL) && ((nsName == NULL) || (nsName[0] == 0))) {
+       /*
+       * NOTE: the "undeclaration" of the default namespace was
+       * part of the logic of the old xsltGetSpecialNamespace() code,
+       * so we'll keep that mechanism.
+       * Related to the old code: bug #302020:
+       */
+       /*
+       * OPTIMIZE TODO: This all could be optimized by keeping track of
+       *  the ns-decls currently in-scope via a specialized context.
+       */
+       /*
+       * Search on the result element itself.
+       */
+       if (target->nsDef != NULL) {
+           ns = target->nsDef;
+           do {
+               if (ns->prefix == NULL) {
+                   if ((ns->href != NULL) && (ns->href[0] != 0)) {
+                       /*
+                       * Raise a namespace normalization error.
+                       */
+                       xsltTransformError(ctxt, NULL, invocNode,
+                           "Namespace normalization error: Cannot undeclare "
+                           "the default namespace, since the default namespace "
+                           "'%s' is already declared on the result element "
+                           "'%s'.\n", ns->href, target->name);
+                       return(NULL);
+                   } else {
+                       /*
+                       * The default namespace was undeclared on the
+                       * result element.
+                       */
+                       return(NULL);
+                   }
+                   break;
+               }
+               ns = ns->next;
+           } while (ns != NULL);
+       }       
+       if ((target->parent != NULL) &&
+           (target->parent->type == XML_ELEMENT_NODE))
+       {
+           /*
+           * The parent element is in no namespace, so assume
+           * that there is no default namespace in scope.
+           */
+           if (target->parent->ns == NULL)
+               return(NULL);
            
-           style = xsltNextImport(style);
+           ns = xmlSearchNs(target->doc, target->parent,
+               NULL);
+           /*
+           * Fine if there's no default ns is scope, or if the
+           * default ns was undeclared.
+           */
+           if ((ns == NULL) || (ns->href == NULL) || (ns->href[0] == 0))
+               return(NULL);
+           
+           /*
+           * Undeclare the default namespace.
+           */
+           xmlNewNs(target, BAD_CAST "", NULL);
+           /* TODO: Check result */    
+           return(NULL);
        }
+       return(NULL);
     }
-
-    if (URI == UNDEFINED_DEFAULT_NS) {
-        xmlNsPtr dflt;
-       dflt = xmlSearchNs(cur->doc, cur, NULL);
-        if (dflt == NULL)
-           return NULL;
-       else
-           URI = dflt->href;
+    /*
+    * Handle the XML namespace.
+    * QUESTION: Is this faster than using xmlStrEqual() anyway?
+    */
+    if ((nsPrefix != NULL) &&
+       (nsPrefix[0] == 'x') && (nsPrefix[1] == 'm') &&
+       (nsPrefix[2] == 'l') && (nsPrefix[3] == 0))
+    {
+       return(xmlSearchNs(target->doc, target, nsPrefix));
     }
-
-    if (URI == NULL)
-       URI = ns->href;
-#endif
-
-    if ((out->parent != NULL) &&
-       (out->parent->type == XML_ELEMENT_NODE) &&
-       (out->parent->ns != NULL) &&
-       (out->parent->ns->prefix != NULL) &&
-       (xmlStrEqual(out->parent->ns->href, URI)))
-       ret = out->parent->ns;
-    else {
-       if (ns->prefix != NULL) {
-           ret = xmlSearchNs(out->doc, out, ns->prefix);
-           if ((ret == NULL) || (!xmlStrEqual(ret->href, URI)) ||
-               (ret->prefix == NULL)) {
-               ret = xsltSearchPlainNsByHref(out->doc, out, URI);
+    /*
+    * First: search on the result element itself.
+    */
+    if (target->nsDef != NULL) {
+       ns = target->nsDef;
+       do {
+           if ((ns->prefix == NULL) == (nsPrefix == NULL)) {
+               if (ns->prefix == nsPrefix) {
+                   if (xmlStrEqual(ns->href, nsName))
+                       return(ns);
+                   prefixOccupied = 1;
+                   break;
+               } else if (xmlStrEqual(ns->prefix, nsPrefix)) {
+                   if (xmlStrEqual(ns->href, nsName))
+                       return(ns);
+                   prefixOccupied = 1;
+                   break;
+               }
            }
-       } else {
-           ret = xsltSearchPlainNsByHref(out->doc, out, URI);
-       }
-    }
-
-    if (ret == NULL) {
-       if (out->type == XML_ELEMENT_NODE)
-           ret = xmlNewNs(out, URI, ns->prefix);
+           ns = ns->next;
+       } while (ns != NULL);
     }
-    return(ret);
-}
-
-/**
- * xsltGetSpecialNamespace:
- * @ctxt:  a transformation context
- * @cur:  the input node
- * @URI:  the namespace URI
- * @prefix:  the suggested prefix
- * @out:  the output node (or its parent)
- *
- * Find the right namespace value for this URI, if needed create
- * and add a new namespace decalaration on the node
- *
- * Returns the namespace node to use or NULL
- */
-xmlNsPtr
-xsltGetSpecialNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur,
-               const xmlChar *URI, const xmlChar *prefix, xmlNodePtr out) {
-    xmlNsPtr ret;
-    static int prefixno = 1;
-    char nprefix[10];
-
-    if ((ctxt == NULL) || (cur == NULL) || (out == NULL) || (URI == NULL))
-       return(NULL);
-
-    if ((prefix == NULL) && (URI[0] == 0)) {
+    if (prefixOccupied) {
        /*
-       * This tries to "undeclare" a default namespace.
-       * This fixes a part of bug #302020:
-       *  1) Added a check whether the queried ns-decl
-       *     is already an "undeclaration" of the default
-       *     namespace.
-       *  2) This fires an error if the default namespace
-       *     couldn't be "undeclared". 
+       * If the ns-prefix is occupied by an other ns-decl on the
+       * result element, then this means:
+       * 1) The desired prefix is shadowed
+       * 2) There's no way around changing the prefix  
+       *
+       * Try a desperate search for an in-scope ns-decl
+       * with a matching ns-name before we use the last option,
+       * which is to recreate the ns-decl with a modified prefix.
        */
-       ret = xmlSearchNs(out->doc, out, NULL);
-       if ((ret == NULL) ||
-           (ret->href == NULL) || (ret->href[0] == 0))
-           return(ret);
-
-       if (ret != NULL) {
-           xmlNsPtr newns;
-
-           newns = xmlNewNs(out, URI, prefix);
-           if (newns == NULL) {
-               xsltTransformError(ctxt, NULL, cur,
-                   "Namespace fixup error: Failed to undeclare "
-                   "the default namespace '%s'.\n",
-                   ret->href);
+       ns = xmlSearchNsByHref(target->doc, target, nsName);
+       if (ns != NULL)
+           return(ns);
+
+       /*
+       * Fallback to changing the prefix.
+       */    
+    } else if ((target->parent != NULL) &&
+       (target->parent->type == XML_ELEMENT_NODE))
+    {
+       /*
+       * Try to find a matching ns-decl in the ancestor-axis.
+       *
+       * Check the common case: The parent element of the current
+       * result element is in the same namespace (with an equal ns-prefix).
+       */     
+       if ((target->parent->ns != NULL) &&
+           ((target->parent->ns->prefix != NULL) == (nsPrefix != NULL)))
+       {
+           ns = target->parent->ns;
+           
+           if (nsPrefix == NULL) {
+               if (xmlStrEqual(ns->href, nsName))
+                   return(ns);
+           } else if (xmlStrEqual(ns->prefix, nsPrefix) &&
+               xmlStrEqual(ns->href, nsName))
+           {
+               return(ns);
+           }
+       }
+       /*
+       * Lookup the remaining in-scope namespaces.
+       */    
+       ns = xmlSearchNs(target->doc, target->parent, nsPrefix);
+       if (ns != NULL) {
+           if (xmlStrEqual(ns->href, nsName))
+               return(ns);         
+           /*
+           * Now check for a nasty case: We need to ensure that the new
+           * ns-decl won't shadow a prefix in-use by an existing attribute.
+           * <foo xmlns:a="urn:test:a">
+           *   <bar a:a="val-a">
+           *     <xsl:attribute xmlns:a="urn:test:b" name="a:b">
+           *        val-b</xsl:attribute>
+           *   </bar>
+           * </foo>
+           */
+           if (target->properties) {
+               xmlAttrPtr attr = target->properties;
+               do {
+                   if ((attr->ns) &&
+                       xmlStrEqual(attr->ns->prefix, nsPrefix))
+                   {
+                       /*
+                       * Bad, this prefix is already in use.
+                       * Since we'll change the prefix anyway, try
+                       * a search for a matching ns-decl based on the
+                       * namespace name.
+                       */
+                       ns = xmlSearchNsByHref(target->doc, target, nsName);
+                       if (ns != NULL)
+                           return(ns);
+                       goto declare_new_prefix;
+                   }
+                   attr = attr->next;
+               } while (attr != NULL);
            }
+       } else {
            /*
-           * TODO: Why does this try to return an xmlns="" at all?
+           * Either no matching ns-prefix was found or the namespace is
+           * shadowed.
+           * Create a new ns-decl on the current result element.
+           *
+           * Hmm, we could also try to reuse an in-scope
+           * namespace with a matching ns-name but a different
+           * ns-prefix.
+           * What has higher priority? 
+           *  1) If keeping the prefix: create a new ns-decl.
+           *  2) If reusal: first lookup ns-names; then fallback
+           *     to creation of a new ns-decl.
+           * REVISIT: this currently uses case 1) although
+           *  the old way was use xmlSearchNsByHref() and to let change
+           *  the prefix.
            */
-           return(newns);
+#if 0
+           ns = xmlSearchNsByHref(target->doc, target, nsName);
+           if (ns != NULL)
+               return(ns);
+#endif
        }
-       return(NULL);
+       /*
+       * Create the ns-decl on the current result element.
+       */
+       ns = xmlNewNs(target, nsName, nsPrefix);
+       /* TODO: check errors */
+       return(ns);
+    } else {
+       /*
+       * This is either the root of the tree or something weird is going on.
+       */
+       ns = xmlNewNs(target, nsName, nsPrefix);
+       /* TODO: Check result */
+       return(ns);
     }
 
-    if ((out->parent != NULL) &&
-       (out->parent->type == XML_ELEMENT_NODE) &&
-       (out->parent->ns != NULL) &&
-       (xmlStrEqual(out->parent->ns->href, URI)))
+declare_new_prefix:
+    /*
+    * Fallback: we need to generate a new prefix and declare the namespace
+    * on the result element.
+    */
     {
-       ret = out->parent->ns;
-    } else 
-       ret = xmlSearchNsByHref(out->doc, out, URI);
-
-    if ((ret == NULL) || (ret->prefix == NULL)) {
-       if (prefix == NULL) {
-           do {
-               sprintf(nprefix, "ns%d", prefixno++);
-               ret = xmlSearchNs(out->doc, out, (xmlChar *)nprefix);
-           } while (ret != NULL);
-           prefix = (const xmlChar *) &nprefix[0];
-       } else if ((ret != NULL) && (ret->prefix == NULL)) {
-           /* found ns but no prefix - search for the prefix */
-           ret = xmlSearchNs(out->doc, out, prefix);
-           if (ret != NULL)
-               return(ret);    /* found it */
-       }
-       if (out->type == XML_ELEMENT_NODE)
-           ret = xmlNewNs(out, URI, prefix);
+       xmlChar pref[30];
+       int counter = 1;
+               
+       do {
+           snprintf((char *) pref, 30, "%s_%d", nsPrefix, counter++);
+           ns = xmlSearchNs(target->doc, target, BAD_CAST pref);
+           if (counter > 1000) {
+               xsltTransformError(ctxt, NULL, invocNode,
+                   "Internal error in xsltAcquireResultInScopeNs(): "              
+                   "Failed to compute a unique ns-prefix for the "
+                   "generated element");
+               return(NULL);
+           }
+       } while (ns != NULL);
+       ns = xmlNewNs(target, nsName, BAD_CAST pref);
+       /* TODO: Check result */
+       return(ns);
     }
-    return(ret);
+    return(NULL);   
 }
 
 /**
@@ -576,33 +606,47 @@ xsltGetSpecialNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur,
  * @ns:  the namespace
  * @out:  the output node (or its parent)
  *
- * REFACTORED NOTE: Won't be used anymore in the refactored code
- *  for literal result elements/attributes.
+ * Find a matching (prefix and ns-name) ns-declaration
+ * for the requested @ns->prefix and @ns->href in the result tree.
+ * If none is found then a new ns-declaration will be
+ * added to @resultElem. If, in this case, the given prefix is
+ * already in use, then a ns-declaration with a modified ns-prefix
+ * be we created.
  *
- * Find the right namespace value for this prefix, if needed create
- * and add a new namespace decalaration on the node
- * Handle namespace aliases
+ * Called by:
+ *  - xsltCopyPropList() (*not*  anymore)
+ *  - xsltShallowCopyElement()
+ *  - xsltCopyTreeInternal() (*not*  anymore)
+ *  - xsltApplyOneTemplateInt() (*not* in the refactored code),
+ *  - xsltElement() (*not* anymore)
  *
- * Returns the namespace node to use or NULL
+ * Returns a namespace declaration or NULL in case of
+ *         namespace fixup failures or API or internal errors.
  */
 xmlNsPtr
 xsltGetNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur, xmlNsPtr ns,
-                xmlNodePtr out) {    
-    xmlNsPtr ret;
-    const xmlChar *URI = NULL; /* the replacement URI */
-
-    if ((ctxt == NULL) || (cur == NULL) || (out == NULL) || (ns == NULL))
-       return(NULL);
+                xmlNodePtr out)
+{    
     
+    if (ns == NULL)
+       return(NULL);
+
 #ifdef XSLT_REFACTORED
     /*
     * Namespace exclusion and ns-aliasing is performed at
-    * compilation-time in the refactored code.    
+    * compilation-time in the refactored code.
+    * Additionally, aliasing is not intended for non Literal
+    * Result Elements.
     */
-    URI = ns->href;
+    return(xsltGetSpecialNamespace(ctxt, cur, ns->href, ns->prefix, out));
 #else
     {
        xsltStylesheetPtr style;
+       const xmlChar *URI = NULL; /* the replacement URI */
+
+       if ((ctxt == NULL) || (cur == NULL) || (out == NULL))
+           return(NULL);
+
        style = ctxt->style;
        while (style != NULL) {
            if (style->nsAliases != NULL)
@@ -613,60 +657,50 @@ xsltGetNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur, xmlNsPtr ns,
            
            style = xsltNextImport(style);
        }
-    }
-
-    if (URI == UNDEFINED_DEFAULT_NS) {
-        xmlNsPtr dflt;
-       /*
-       */
-       dflt = xmlSearchNs(cur->doc, cur, NULL);
-       if (dflt != NULL)
-           URI = dflt->href;
-       else
-           return NULL;
-    } else if (URI == NULL)
-       URI = ns->href;
+       
+       
+       if (URI == UNDEFINED_DEFAULT_NS) {
+           return(xsltGetSpecialNamespace(ctxt, cur, NULL, NULL, out));
+#if 0
+           /*
+           * TODO: Removed, since wrong. If there was no default
+           * namespace in the stylesheet then this must resolve to
+           * the NULL namespace.
+           */
+           xmlNsPtr dflt;          
+           dflt = xmlSearchNs(cur->doc, cur, NULL);
+           if (dflt != NULL)
+               URI = dflt->href;
+           else
+               return NULL;
 #endif
-    /*
-     * If the parent is an XML_ELEMENT_NODE, and has the "equivalent"
-     * namespace as ns (either both default, or both with a prefix
-     * with the same href) then return the parent's ns record
-     */
-    if ((out->parent != NULL) &&
-       (out->parent->type == XML_ELEMENT_NODE) &&
-       (out->parent->ns != NULL) &&
-       (((out->parent->ns->prefix == NULL) && (ns->prefix == NULL)) ||
-        ((out->parent->ns->prefix != NULL) && (ns->prefix != NULL))) &&
-       (xmlStrEqual(out->parent->ns->href, URI)))
-       ret = out->parent->ns;
-    else {
-        /*
-        * do a standard namespace search for ns in the output doc
-        */
-        ret = xmlSearchNs(out->doc, out, ns->prefix);
-       if ((ret != NULL) && (!xmlStrEqual(ret->href, URI)))
-           ret = NULL;
+       } else if (URI == NULL)
+           URI = ns->href;
 
-       /*
-        * if the search fails and it's not for the default prefix
-        * do a search by href
-        */
-       if ((ret == NULL) && (ns->prefix != NULL))
-           ret = xmlSearchNsByHref(out->doc, out, URI);
+       return(xsltGetSpecialNamespace(ctxt, cur, URI, ns->prefix, out));
     }
+#endif
+}
 
-    /*
-     * For an element node, if we don't find it, or it's the default
-     * and this element already defines a default (bug 165560), we need to
-     * create it.
-     */
-    if (out->type == XML_ELEMENT_NODE) {
-       if ((ret == NULL) || ((ret->prefix == NULL) && (out->ns == NULL) &&
-           (out->nsDef != NULL) && (!xmlStrEqual(URI, out->nsDef->href)))) {
-               ret = xmlNewNs(out, URI, ns->prefix);
-       }
-    }
-    return(ret);
+/**
+ * xsltGetPlainNamespace:
+ * @ctxt:  a transformation context
+ * @cur:  the input node
+ * @ns:  the namespace
+ * @out:  the result element
+ *
+ * Obsolete. 
+ * *Not* called by any Libxslt/Libexslt function.
+ * Exaclty the same as xsltGetNamespace(). 
+ *
+ * Returns a namespace declaration or NULL in case of
+ *         namespace fixup failures or API or internal errors.
+ */
+xmlNsPtr
+xsltGetPlainNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur,
+                      xmlNsPtr ns, xmlNodePtr out)
+{    
+    return(xsltGetNamespace(ctxt, cur, ns, out));
 }
 
 /**
@@ -679,12 +713,14 @@ xsltGetNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur, xmlNsPtr ns,
  * new namespaces are added automatically. This handles namespaces
  * aliases.
  * This function is intended only for *internal* use at
- * transformation-time. Use it *only* for copying ns-decls of
- * literal result elements.
+ * transformation-time for copying ns-declarations of Literal
+ * Result Elements.
  * 
  * Called by:
- *   xsltCopyTree() (transform.c)
- *   xsltCopyNode() (transform.c)
+ *   xsltCopyTreeInternal() (transform.c)
+ *   xsltShallowCopyElem() (transform.c)
+ *
+ * REVISIT: This function won't be used in the refactored code.
  *
  * Returns: a new xmlNsPtr, or NULL in case of error.
  */
@@ -739,6 +775,9 @@ xsltCopyNamespaceList(xsltTransformContextPtr ctxt, xmlNodePtr node,
            p = q;
        }
 #else
+       /*
+       * TODO: Remove this if the refactored code gets enabled.
+       */
        if (!xmlStrEqual(cur->href, XSLT_NAMESPACE)) {
            const xmlChar *URI;
            /* TODO apply cascading */
@@ -767,53 +806,27 @@ xsltCopyNamespaceList(xsltTransformContextPtr ctxt, xmlNodePtr node,
 /**
  * xsltCopyNamespace:
  * @ctxt:  a transformation context
- * @node:  the target node
- * @cur:  the namespace node
+ * @elem:  the target element node
+ * @ns:  the namespace node
  *
- * Do a copy of an namespace node. If @node is non-NULL the
- * new namespaces are added automatically. This handles namespaces
- * aliases
+ * Copies a namespace node (declaration). If @elem is not NULL,
+ * then the new namespace will be declared on @elem.
  *
- * Returns: a new xmlNsPtr, or NULL in case of error.
+ * Returns: a new xmlNsPtr, or NULL in case of an error.
  */
 xmlNsPtr
-xsltCopyNamespace(xsltTransformContextPtr ctxt, xmlNodePtr node,
-                 xmlNsPtr cur) {
-    xmlNsPtr ret = NULL;
-    
-    if (cur == NULL)
+xsltCopyNamespace(xsltTransformContextPtr ctxt, xmlNodePtr elem,
+                 xmlNsPtr ns)
+{    
+    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
        return(NULL);
-    if (cur->type != XML_NAMESPACE_DECL)
-       return(NULL);
-
     /*
      * One can add namespaces only on element nodes
      */
-    if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
-       node = NULL;
-
-#ifdef XSLT_REFACTORED
-    /*
-    * Namespace exclusion and ns-aliasing is performed at
-    * compilation-time in the refactored code.
-    */
-    ret = xmlNewNs(node, cur->href, cur->prefix);      
-#else
-    if (!xmlStrEqual(cur->href, XSLT_NAMESPACE)) {
-       const xmlChar *URI;
-
-       URI = (const xmlChar *) xmlHashLookup(ctxt->style->nsAliases,
-                                             cur->href);
-       if (URI == UNDEFINED_DEFAULT_NS)
-           return(NULL);
-       if (URI != NULL) {
-           ret = xmlNewNs(node, URI, cur->prefix);
-       } else {
-           ret = xmlNewNs(node, cur->href, cur->prefix);
-       }
-    }
-#endif
-    return(ret);
+    if ((elem != NULL) && (elem->type != XML_ELEMENT_NODE))
+       return(xmlNewNs(NULL, ns->href, ns->prefix));
+    else
+       return(xmlNewNs(elem, ns->href, ns->prefix));
 }
 
 
index acc3aa0..4c6f8ab 100644 (file)
@@ -45,8 +45,8 @@ XSLTPUBFUN xmlNsPtr XSLTCALL
                                         xmlNodePtr out);
 XSLTPUBFUN xmlNsPtr XSLTCALL   
                xsltCopyNamespace       (xsltTransformContextPtr ctxt,
-                                        xmlNodePtr node,
-                                        xmlNsPtr cur);
+                                        xmlNodePtr elem,
+                                        xmlNsPtr ns);
 XSLTPUBFUN xmlNsPtr XSLTCALL   
                xsltCopyNamespaceList   (xsltTransformContextPtr ctxt,
                                         xmlNodePtr node,
index c6c020b..344de8c 100644 (file)
@@ -878,31 +878,85 @@ xsltElementComp(xsltStylesheetPtr style, xmlNodePtr inst) {
     inst->psvi = comp;
     comp->inst = inst;
 
+    /*
+    * Attribute "name".
+    */
+    /*
+    * TODO: Precompile the AVT. See bug #344894.
+    */
     comp->name = xsltEvalStaticAttrValueTemplate(style, inst,
-                                (const xmlChar *)"name",
-                                NULL, &comp->has_name);
-    if (comp->name != NULL) {
-       if (xmlValidateQName(comp->name, 0)) {
-           xsltTransformError(NULL, style, inst,
-                   "xsl:element : invalid name\n");
-           if (style != NULL) style->errors++;
-       }
+       (const xmlChar *)"name", NULL, &comp->has_name);
+    if (! comp->has_name) {
+       xsltTransformError(NULL, style, inst,
+           "xsl:element: The attribute 'name' is missing.\n");
+       style->errors++;
+       goto error;
     }
+    /*
+    * Attribute "namespace".
+    */
+    /*
+    * TODO: Precompile the AVT. See bug #344894.
+    */
     comp->ns = xsltEvalStaticAttrValueTemplate(style, inst,
-                        (const xmlChar *)"namespace",
-                        NULL, &comp->has_ns);
-    if (comp->has_ns == 0) {
-       xmlNsPtr defaultNs;
-
-       defaultNs = xmlSearchNs(inst->doc, inst, NULL);
-       if (defaultNs != NULL) {
-           comp->ns = xmlDictLookup(style->dict, defaultNs->href, -1);
-           comp->has_ns = 1;
+       (const xmlChar *)"namespace", NULL, &comp->has_ns);
+    
+    if (comp->name != NULL) {  
+       if (xmlValidateQName(comp->name, 0)) {
+           xsltTransformError(NULL, style, inst,
+               "xsl:element: The value '%s' of the attribute 'name' is "
+               "not a valid QName.\n", comp->name);
+           style->errors++;
+       } else {
+           const xmlChar *prefix = NULL, *name;
+
+           name = xsltSplitQName(style->dict, comp->name, &prefix);
+           if (comp->has_ns == 0) {        
+               xmlNsPtr ns;
+
+               /*
+               * SPEC XSLT 1.0:
+               *  "If the namespace attribute is not present, then the QName is
+               *  expanded into an expanded-name using the namespace declarations
+               *  in effect for the xsl:element element, including any default
+               *  namespace declaration.
+               */              
+               ns = xmlSearchNs(inst->doc, inst, prefix);
+               if (ns != NULL) {
+                   comp->ns = xmlDictLookup(style->dict, ns->href, -1);
+                   comp->has_ns = 1;
+#ifdef XSLT_REFACTORED
+                   comp->nsPrefix = prefix;
+                   comp->name = name;
+#endif
+               } else if (prefix != NULL) {
+                   xsltTransformError(NULL, style, inst,
+                       "xsl:element: The prefixed QName '%s' "
+                       "has no namespace binding in scope in the "
+                       "stylesheet; this is an error, since the namespace was "
+                       "not specified by the instruction itself.\n", comp->name);
+                   style->errors++;
+               }
+           }       
+           if ((prefix != NULL) &&
+               (!xmlStrncasecmp(prefix, (xmlChar *)"xml", 3)))
+           {
+               /*
+               * Mark is to be skipped.
+               */
+               comp->has_name = 0;             
+           }
        }
-    }
+    }    
+    /*
+    * Attribute "use-attribute-sets",
+    */
     comp->use = xsltEvalStaticAttrValueTemplate(style, inst,
                       (const xmlChar *)"use-attribute-sets",
                       NULL, &comp->has_use);
+
+error:    
+    return;
 }
 
 /**
@@ -931,7 +985,8 @@ xsltAttributeComp(xsltStylesheetPtr style, xmlNodePtr inst) {
        return;
 
 #ifdef XSLT_REFACTORED
-    comp = (xsltStyleItemAttributePtr) xsltNewStylePreComp(style, XSLT_FUNC_ATTRIBUTE);
+    comp = (xsltStyleItemAttributePtr) xsltNewStylePreComp(style,
+       XSLT_FUNC_ATTRIBUTE);
 #else
     comp = xsltNewStylePreComp(style, XSLT_FUNC_ATTRIBUTE);
 #endif
@@ -942,22 +997,93 @@ xsltAttributeComp(xsltStylesheetPtr style, xmlNodePtr inst) {
     comp->inst = inst;
 
     /*
-     * TODO: more computation can be done there, especially namespace lookup
-     */
+    * Attribute "name".
+    */
+    /*
+    * TODO: Precompile the AVT. See bug #344894.
+    */
     comp->name = xsltEvalStaticAttrValueTemplate(style, inst,
                                 (const xmlChar *)"name",
                                 NULL, &comp->has_name);
+    if (! comp->has_name) {
+       xsltTransformError(NULL, style, inst,
+           "xsl:attribute: The attribute 'name' is missing.\n");
+       style->errors++;
+       return;
+    }    
+    /*
+    * Attribute "namespace".
+    */
+    /*
+    * TODO: Precompile the AVT. See bug #344894.
+    */
+    comp->ns = xsltEvalStaticAttrValueTemplate(style, inst,
+       (const xmlChar *)"namespace",
+       NULL, &comp->has_ns);
+
     if (comp->name != NULL) {
        if (xmlValidateQName(comp->name, 0)) {
            xsltTransformError(NULL, style, inst,
-                           "xsl:attribute : invalid QName\n");
-           if (style != NULL) style->errors++;
-       }
+               "xsl:attribute: The value '%s' of the attribute 'name' is "
+               "not a valid QName.\n", comp->name);
+           style->errors++;
+       } else {
+           const xmlChar *prefix = NULL, *name;
+
+           name = xsltSplitQName(style->dict, comp->name, &prefix);
+           if (prefix != NULL) {
+               if (comp->has_ns == 0) {
+                   xmlNsPtr ns;
+
+                   /*
+                   * SPEC XSLT 1.0:
+                   *  "If the namespace attribute is not present, then the
+                   *  QName is expanded into an expanded-name using the
+                   *  namespace declarations in effect for the xsl:element
+                   *  element, including any default namespace declaration.
+                   */              
+                   ns = xmlSearchNs(inst->doc, inst, prefix);
+                   if (ns != NULL) {
+                       comp->ns = xmlDictLookup(style->dict, ns->href, -1);
+                       comp->has_ns = 1;
+#ifdef XSLT_REFACTORED
+                       comp->nsPrefix = prefix;
+                       comp->name = name;
+#endif
+                   } else {
+                       xsltTransformError(NULL, style, inst,
+                           "xsl:attribute: The prefixed QName '%s' "
+                           "has no namespace binding in scope in the "
+                           "stylesheet; this is an error, since the "
+                           "namespace was not specified by the instruction "
+                           "itself.\n", comp->name);
+                       style->errors++;
+                   }
+               }
+               if (!xmlStrncasecmp(prefix, (xmlChar *) "xmlns", 5)) {
+                   /*
+                   * SPEC XSLT 1.0:
+                   *  "It is an error if the string that results from
+                   *  instantiating the attribute value template is not a
+                   *  QName or is the string xmlns. An XSLT processor may
+                   *  signal the error; if it does not signal the error,
+                   *  it must recover by not adding the attribute to the
+                   *  result tree."
+                   *
+                   * Reject a prefix of "xmlns". Mark to be skipped.
+                   */
+                   comp->has_name = 0;
+                   
+#ifdef WITH_XSLT_DEBUG_PARSING
+                   xsltGenericDebug(xsltGenericDebugContext,
+                       "xsltAttribute: xmlns prefix forbidden\n");
+#endif             
+                   return;
+               }
+               
+           }
+       }       
     }
-    comp->ns = xsltEvalStaticAttrValueTemplate(style, inst,
-                        (const xmlChar *)"namespace",
-                        NULL, &comp->has_ns);
-
 }
 
 /**
index d6dc728..c20e287 100644 (file)
@@ -180,10 +180,10 @@ xsltEvalXPathString(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp) {
 /**
  * xsltEvalTemplateString:
  * @ctxt:  the XSLT transformation context
- * @node:  the stylesheet node
+ * @currentNode:  the current node in the source tree
  * @parent:  the content parent
  *
- * Evaluate a template string value, i.e. the parent list is interpreter
+ * Evaluate a template string value, i.e. the parent list is interpreted
  * as template content and the resulting tree string value is returned
  * This is needed for example by xsl:comment and xsl:processing-instruction
  *
@@ -191,12 +191,14 @@ xsltEvalXPathString(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp) {
  *    caller.
  */
 xmlChar *
-xsltEvalTemplateString(xsltTransformContextPtr ctxt, xmlNodePtr node,
-                      xmlNodePtr parent) {
+xsltEvalTemplateString(xsltTransformContextPtr ctxt,
+                      xmlNodePtr currentNode,
+                      xmlNodePtr parent)
+{
     xmlNodePtr oldInsert, insert = NULL;
     xmlChar *ret;
 
-    if ((ctxt == NULL) || (node == NULL) || (parent == NULL))
+    if ((ctxt == NULL) || (currentNode == NULL) || (parent == NULL))
        return(NULL);
 
     if (parent->children == NULL)
@@ -211,14 +213,14 @@ xsltEvalTemplateString(xsltTransformContextPtr ctxt, xmlNodePtr node,
     insert = xmlNewDocNode(ctxt->output, NULL,
                           (const xmlChar *)"fake", NULL);
     if (insert == NULL) {
-       xsltTransformError(ctxt, NULL, node,
+       xsltTransformError(ctxt, NULL, currentNode,
                "Failed to create temporary node\n");
        return(NULL);
     }
     oldInsert = ctxt->insert;
     ctxt->insert = insert;
     /* OPTIMIZE TODO: if parent->children consists only of text-nodes. */
-    xsltApplyOneTemplate(ctxt, node, parent->children, NULL, NULL);
+    xsltApplyOneTemplate(ctxt, currentNode, parent->children, NULL, NULL);
 
     ctxt->insert = oldInsert;
 
@@ -232,17 +234,26 @@ xsltEvalTemplateString(xsltTransformContextPtr ctxt, xmlNodePtr node,
  * xsltAttrTemplateValueProcessNode:
  * @ctxt:  the XSLT transformation context
  * @str:  the attribute template node value
- * @node:  the node hosting the attribute
+ * @inst:  the instruction (or LRE) in the stylesheet holding the
+ *         attribute with an AVT
  *
  * Process the given string, allowing to pass a namespace mapping
  * context and return the new string value.
  *
+ * Called by:
+ *  - xsltAttrTemplateValueProcess() (templates.c)
+ *  - xsltEvalAttrValueTemplate() (templates.c)
+ *
+ * QUESTION: Why is this function public? It is not used outside
+ *  of templates.c.
+ *
  * Returns the computed string value or NULL, must be deallocated by the
  *    caller.
  */
 xmlChar *
 xsltAttrTemplateValueProcessNode(xsltTransformContextPtr ctxt,
-         const xmlChar *str, xmlNodePtr node) {
+         const xmlChar *str, xmlNodePtr inst)
+{
     xmlChar *ret = NULL;
     const xmlChar *cur;
     xmlChar *expr, *val;
@@ -268,7 +279,7 @@ xsltAttrTemplateValueProcessNode(xsltTransformContextPtr ctxt,
            cur++;
            while ((*cur != 0) && (*cur != '}')) cur++;
            if (*cur == 0) {
-               xsltTransformError(ctxt, NULL, NULL,
+               xsltTransformError(ctxt, NULL, inst,
                        "xsltAttrTemplateValueProcessNode: unmatched '{'\n");
                ret = xmlStrncat(ret, str, cur - str);
                return(ret);
@@ -285,10 +296,10 @@ xsltAttrTemplateValueProcessNode(xsltTransformContextPtr ctxt,
                /*
                 * TODO: keep precompiled form around
                 */
-               if ((nsList == NULL) && (node != NULL)) {
+               if ((nsList == NULL) && (inst != NULL)) {
                    int i = 0;
 
-                   nsList = xmlGetNsList(node->doc, node);
+                   nsList = xmlGetNsList(inst->doc, inst);
                    if (nsList != NULL) {
                        while (nsList[i] != NULL)
                            i++;
@@ -314,7 +325,7 @@ xsltAttrTemplateValueProcessNode(xsltTransformContextPtr ctxt,
                str = cur;
                continue;
            } else {
-               xsltTransformError(ctxt, NULL, NULL,
+               xsltTransformError(ctxt, NULL, inst,
                     "xsltAttrTemplateValueProcessNode: unmatched '}'\n");
            }
        } else
@@ -348,7 +359,8 @@ xsltAttrTemplateValueProcess(xsltTransformContextPtr ctxt, const xmlChar *str) {
 /**
  * xsltEvalAttrValueTemplate:
  * @ctxt:  the XSLT transformation context
- * @node:  the stylesheet node
+ * @inst:  the instruction (or LRE) in the stylesheet holding the
+ *         attribute with an AVT
  * @name:  the attribute QName
  * @ns:  the attribute namespace URI
  *
@@ -360,15 +372,16 @@ xsltAttrTemplateValueProcess(xsltTransformContextPtr ctxt, const xmlChar *str) {
  *    caller.
  */
 xmlChar *
-xsltEvalAttrValueTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
-                         const xmlChar *name, const xmlChar *ns) {
+xsltEvalAttrValueTemplate(xsltTransformContextPtr ctxt, xmlNodePtr inst,
+                         const xmlChar *name, const xmlChar *ns)
+{
     xmlChar *ret;
     xmlChar *expr;
 
-    if ((ctxt == NULL) || (node == NULL) || (name == NULL))
+    if ((ctxt == NULL) || (inst == NULL) || (name == NULL))
        return(NULL);
 
-    expr = xsltGetNsProp(node, name, ns);
+    expr = xsltGetNsProp(inst, name, ns);
     if (expr == NULL)
        return(NULL);
 
@@ -378,7 +391,7 @@ xsltEvalAttrValueTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
      *       attribute content and the XPath precompiled expressions around
      */
 
-    ret = xsltAttrTemplateValueProcessNode(ctxt, expr, node);
+    ret = xsltAttrTemplateValueProcessNode(ctxt, expr, inst);
 #ifdef WITH_XSLT_DEBUG_TEMPLATES
     XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
         "xsltEvalAttrValueTemplate: %s returns %s\n", expr, ret));
@@ -391,7 +404,8 @@ xsltEvalAttrValueTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
 /**
  * xsltEvalStaticAttrValueTemplate:
  * @style:  the XSLT stylesheet
- * @node:  the stylesheet node
+ * @inst:  the instruction (or LRE) in the stylesheet holding the
+ *         attribute with an AVT
  * @name:  the attribute Name
  * @ns:  the attribute namespace URI
  * @found:  indicator whether the attribute is present
@@ -403,15 +417,15 @@ xsltEvalAttrValueTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
  *    caller.
  */
 const xmlChar *
-xsltEvalStaticAttrValueTemplate(xsltStylesheetPtr style, xmlNodePtr node,
+xsltEvalStaticAttrValueTemplate(xsltStylesheetPtr style, xmlNodePtr inst,
                        const xmlChar *name, const xmlChar *ns, int *found) {
     const xmlChar *ret;
     xmlChar *expr;
 
-    if ((style == NULL) || (node == NULL) || (name == NULL))
+    if ((style == NULL) || (inst == NULL) || (name == NULL))
        return(NULL);
 
-    expr = xsltGetNsProp(node, name, ns);
+    expr = xsltGetNsProp(inst, name, ns);
     if (expr == NULL) {
        *found = 0;
        return(NULL);
@@ -431,68 +445,94 @@ xsltEvalStaticAttrValueTemplate(xsltStylesheetPtr style, xmlNodePtr node,
 /**
  * xsltAttrTemplateProcess:
  * @ctxt:  the XSLT transformation context
- * @target:  the result node
- * @cur:  the attribute template node
+ * @target:  the element where the attribute will be grafted
+ * @attr:  the attribute node of a literal result element
  *
- * Process the given attribute and return the new processed copy.
+ * Process one attribute of a Literal Result Element (in the stylesheet).
+ * Evaluates Attribute Value Templates and copies the attribute over to
+ * the result element.
+ * This does *not* process attribute sets (xsl:use-attribute-set).
+ * 
  *
- * Returns the attribute replacement.
+ * Returns the generated attribute node.
  */
 xmlAttrPtr
 xsltAttrTemplateProcess(xsltTransformContextPtr ctxt, xmlNodePtr target,
-                       xmlAttrPtr cur) {
+                       xmlAttrPtr attr)
+{
     const xmlChar *value;
-    xmlNsPtr ns;
     xmlAttrPtr ret;
-    if ((ctxt == NULL) || (cur == NULL) || (target == NULL))
+
+    if ((ctxt == NULL) || (attr == NULL) || (target == NULL))
        return(NULL);
     
-    if (cur->type != XML_ATTRIBUTE_NODE)
+    if (attr->type != XML_ATTRIBUTE_NODE)
        return(NULL);
 
-    if ((cur->children == NULL) || (cur->children->type != XML_TEXT_NODE) ||
-        (cur->children->next != NULL)) {
-       xsltTransformError(ctxt, NULL, cur->parent,
-               "attribute %s content problem\n", cur->name);
-        return(NULL);
-    }
-    value = cur->children->content;
-    if (value == NULL)
-        value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0);
-    if ((cur->ns != NULL) &&
-       (xmlStrEqual(cur->ns->href, XSLT_NAMESPACE))) {
-       if (xmlStrEqual(cur->name, (const xmlChar *)"use-attribute-sets")) {
-           xsltApplyAttributeSet(ctxt, ctxt->node, NULL, value);
-       }
+    /*
+    * Skip all XSLT attributes.
+    */
+#ifdef XSLT_REFACTORED    
+    if (attr->psvi == xsltXSLTAttrMarker)
        return(NULL);
-    }
-
+#else
+    if ((attr->ns != NULL) && xmlStrEqual(attr->ns->href, XSLT_NAMESPACE))
+       return(NULL);
+#endif
+    /*
+    * Get the value.
+    */
+    if (attr->children != NULL) {
+       if ((attr->children->type != XML_TEXT_NODE) ||
+           (attr->children->next != NULL))
+       {
+           xsltTransformError(ctxt, NULL, attr->parent,
+               "Internal error: The children of an attribute node of a "
+               "literal result element are not in the expected form.\n");
+           return(NULL);
+       }
+       value = attr->children->content;
+       if (value == NULL)
+           value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0);
+    } else
+       value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0);
+    /*
+    * Overwrite duplicates.
+    */
     ret = target->properties;
     while (ret != NULL) {
-        if (xmlStrEqual(ret->name, cur->name)) {
-           if (cur->ns == NULL) {
-               if (ret->ns == NULL)
-                   break;
-           } else {
-               if ((ret->ns != NULL) &&
-                   (xmlStrEqual(ret->ns->href, cur->ns->href)))
-                   break;
-           }
+        if (((attr->ns != NULL) == (ret->ns != NULL)) &&
+           xmlStrEqual(ret->name, attr->name) &&
+           ((attr->ns == NULL) || xmlStrEqual(ret->ns->href, attr->ns->href)))
+       {
+           break;
        }
         ret = ret->next;
     }
-    if (ret != NULL) {
+    if (ret != NULL) { 
         /* free the existing value */
        xmlFreeNodeList(ret->children);
        ret->children = ret->last = NULL;
+       /*
+       * Adjust ns-prefix if needed.
+       */
+       if ((ret->ns != NULL) &&
+           (! xmlStrEqual(ret->ns->prefix, attr->ns->prefix)))
+       {
+           ret->ns = xsltGetNamespace(ctxt, attr->parent, attr->ns, target);
+       }
     } else {
         /* create a new attribute */
-       if (cur->ns != NULL)
-           ns = xsltGetPlainNamespace(ctxt, cur->parent, cur->ns, target);
+       if (attr->ns != NULL)
+           ret = xmlNewNsProp(target,
+               xsltGetNamespace(ctxt, attr->parent, attr->ns, target),
+                   attr->name, NULL);
        else
-           ns = NULL;
-       ret = xmlNewNsProp(target, ns, cur->name, NULL);
+           ret = xmlNewNsProp(target, NULL, attr->name, NULL); 
     }
+    /*
+    * Set the value.
+    */
     if (ret != NULL) {
         xmlNodePtr text;
 
@@ -501,11 +541,30 @@ xsltAttrTemplateProcess(xsltTransformContextPtr ctxt, xmlNodePtr target,
            ret->last = ret->children = text;
            text->parent = (xmlNodePtr) ret;
            text->doc = ret->doc;
-           if (cur->psvi != NULL) {
+
+           if (attr->psvi != NULL) {
+               /*
+               * Evaluate the Attribute Value Template.
+               */
                xmlChar *val;
-               val = xsltEvalAVT(ctxt, cur->psvi, cur->parent);
+               val = xsltEvalAVT(ctxt, attr->psvi, attr->parent);
                if (val == NULL) {
-                   text->content = xmlStrdup(BAD_CAST "runtime error");
+                   /*
+                   * TODO: Damn, we need an easy mechanism to report
+                   * qualified names!
+                   */
+                   if (attr->ns) {
+                       xsltTransformError(ctxt, NULL, attr->parent,
+                           "Internal error: Failed to evaluate the AVT "
+                           "of attribute '{%s}%s'.\n",
+                           attr->ns->href, attr->name);
+                   } else {
+                       xsltTransformError(ctxt, NULL, attr->parent,
+                           "Internal error: Failed to evaluate the AVT "
+                           "of attribute '%s'.\n",
+                           attr->name);
+                   }
+                   text->content = xmlStrdup(BAD_CAST "");
                } else {
                    text->content = val;
                }
@@ -518,8 +577,15 @@ xsltAttrTemplateProcess(xsltTransformContextPtr ctxt, xmlNodePtr target,
            }
        }
     } else {
-       xsltTransformError(ctxt, NULL, cur->parent,
-               "Failed to create attribute %s\n", cur->name);
+       if (attr->ns) {
+           xsltTransformError(ctxt, NULL, attr->parent,
+               "Internal error: Failed to create attribute '{%s}%s'.\n",
+               attr->ns->href, attr->name);
+       } else {
+           xsltTransformError(ctxt, NULL, attr->parent,
+               "Internal error: Failed to create attribute '%s'.\n",
+               attr->name);
+       }
     }
     return(ret);
 }
@@ -531,32 +597,206 @@ xsltAttrTemplateProcess(xsltTransformContextPtr ctxt, xmlNodePtr target,
  * @target:  the element where the attributes will be grafted
  * @cur:  the first attribute
  *
- * Do a copy of an attribute list with attribute template processing
+ * Processes all attributes of a Literal Result Element.
+ * Attribute references are applied via xsl:use-attribute-set
+ * attributes.
+ * Copies all non XSLT-attributes over to the @target element
+ * and evaluates Attribute Value Templates.
  *
- * Returns: a new xmlAttrPtr, or NULL in case of error.
+ * Called by xsltApplyOneTemplateInt() (transform.c).
+ *
+ * Returns a new list of attribute nodes, or NULL in case of error.
+ *         (Don't assign the result to @target->properties; if
+ *         the result is NULL, you'll get memory leaks, since the
+ *         attributes will be disattached.)
  */
 xmlAttrPtr
 xsltAttrListTemplateProcess(xsltTransformContextPtr ctxt, 
-                           xmlNodePtr target, xmlAttrPtr cur) {
-    xmlAttrPtr ret = NULL;
-    xmlAttrPtr q;
-    xmlNodePtr oldInsert;
+                           xmlNodePtr target, xmlAttrPtr attrs)
+{
+    xmlAttrPtr attr, copy, last;
+    xmlNodePtr oldInsert, text;
+    xmlNsPtr origNs = NULL, copyNs = NULL;
+    const xmlChar *value;
+    xmlChar *valueAVT;
+
+    if ((ctxt == NULL) || (target == NULL) || (attrs == NULL))
+       return(NULL);
 
     oldInsert = ctxt->insert;
-    ctxt->insert = target;
-    while (cur != NULL) {
-        q = xsltAttrTemplateProcess(ctxt, target, cur);
-       if (q != NULL) {
-           q->parent = target;
-           q->doc = target->doc;
-           if (ret == NULL) {
-               ret = q;
+    ctxt->insert = target;        
+
+    /*
+    * Instantiate LRE-attributes.
+    */
+    if (target->properties) {
+       last = target->properties;
+       while (last->next != NULL)
+           last = last->next;
+    } else {
+       last = NULL;
+    }    
+    attr = attrs;
+    do {
+       /*
+       * Skip XSLT attributes.
+       */
+#ifdef XSLT_REFACTORED
+       if (attr->psvi == xsltXSLTAttrMarker) {
+           goto next_attribute;
+       }
+#else
+       if ((attr->ns != NULL) &&
+           xmlStrEqual(attr->ns->href, XSLT_NAMESPACE))
+       {
+           goto next_attribute;
+       }
+#endif
+       /*
+       * Get the value.
+       */
+       if (attr->children != NULL) {
+           if ((attr->children->type != XML_TEXT_NODE) ||
+               (attr->children->next != NULL))
+           {
+               xsltTransformError(ctxt, NULL, attr->parent,
+                   "Internal error: The children of an attribute node of a "
+                   "literal result element are not in the expected form.\n");
+               goto error;
            }
+           value = attr->children->content;
+           if (value == NULL)
+               value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0);
+       } else
+           value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0);
+
+       /*
+       * Create a new attribute.
+       */
+       copy = xmlNewDocProp(target->doc, attr->name, NULL);
+       if (copy == NULL) {
+           if (attr->ns) {
+               xsltTransformError(ctxt, NULL, attr->parent,
+                   "Internal error: Failed to create attribute '{%s}%s'.\n",
+                   attr->ns->href, attr->name);
+           } else {
+               xsltTransformError(ctxt, NULL, attr->parent,
+                   "Internal error: Failed to create attribute '%s'.\n",
+                   attr->name);
+           }
+           goto error;
        }
-       cur = cur->next;
-    }
+       /*
+       * Attach it to the target element.
+       */
+       copy->parent = target;
+       if (last == NULL) {
+           target->properties = copy;
+           last = copy;
+       } else {
+           last->next = copy;
+           copy->prev = last;
+           last = copy;
+       }
+       /*
+       * Set the namespace. Avoid lookups of same namespaces.
+       */
+       if (attr->ns != origNs) {
+           origNs = attr->ns;
+           if (attr->ns != NULL) {
+#ifdef XSLT_REFACTORED
+               copyNs = xsltGetSpecialNamespace(ctxt, attr->parent,
+                   attr->ns->href, attr->ns->prefix, target);
+#else
+               copyNs = xsltGetNamespace(ctxt, attr->parent,
+                   attr->ns, target);
+#endif
+               if (copyNs == NULL)
+                   goto error;
+           } else
+               copyNs = NULL;
+       }
+       copy->ns = copyNs;
+       
+       /*
+       * Set the value.
+       */          
+       text = xmlNewText(NULL);
+       if (text != NULL) {
+           copy->last = copy->children = text;
+           text->parent = (xmlNodePtr) copy;
+           text->doc = copy->doc;
+           
+           if (attr->psvi != NULL) {
+               /*
+               * Evaluate the Attribute Value Template.
+               */              
+               valueAVT = xsltEvalAVT(ctxt, attr->psvi, attr->parent);
+               if (valueAVT == NULL) {
+                   /*
+                   * TODO: Damn, we need an easy mechanism to report
+                   * qualified names!
+                   */
+                   if (attr->ns) {
+                       xsltTransformError(ctxt, NULL, attr->parent,
+                           "Internal error: Failed to evaluate the AVT "
+                           "of attribute '{%s}%s'.\n",
+                           attr->ns->href, attr->name);                            
+                   } else {
+                       xsltTransformError(ctxt, NULL, attr->parent,
+                           "Internal error: Failed to evaluate the AVT "
+                           "of attribute '%s'.\n",
+                           attr->name);
+                   }
+                   text->content = xmlStrdup(BAD_CAST "");
+                   goto error;
+               } else {
+                   text->content = valueAVT;
+               }
+           } else if ((ctxt->internalized) &&
+               (target->doc != NULL) &&
+               (target->doc->dict == ctxt->dict))
+           {
+               text->content = (xmlChar *) value;
+           } else {
+               text->content = xmlStrdup(value);
+           }
+       }
+
+next_attribute:
+       attr = attr->next;
+    } while (attr != NULL);
+
+    /*
+    * Apply attribute-sets.
+    * The creation of such attributes will not overwrite any existing
+    * attribute.
+    */
+    attr = attrs;
+    do {
+#ifdef XSLT_REFACTORED
+       if ((attr->psvi == xsltXSLTAttrMarker) &&
+           xmlStrEqual(attr->name, (const xmlChar *)"use-attribute-sets"))
+       {
+           xsltApplyAttributeSet(ctxt, ctxt->node, (xmlNodePtr) attr, NULL);
+       }
+#else
+       if ((attr->ns != NULL) &&
+           xmlStrEqual(attr->name, (const xmlChar *)"use-attribute-sets") &&
+           xmlStrEqual(attr->ns->href, XSLT_NAMESPACE))
+       {
+           xsltApplyAttributeSet(ctxt, ctxt->node, (xmlNodePtr) attr, NULL);
+       }
+#endif
+       attr = attr->next;
+    } while (attr != NULL);
+
     ctxt->insert = oldInsert;
-    return(ret);
+    return(target->properties);
+
+error:
+    ctxt->insert = oldInsert;
+    return(NULL);
 }
 
 
@@ -565,9 +805,7 @@ xsltAttrListTemplateProcess(xsltTransformContextPtr ctxt,
  * @ctxt:  the XSLT transformation context
  * @node:  the attribute template node
  *
- * Process the given node and return the new string value.
- *
- * Returns the computed tree replacement
+ * Obsolete. Does always return NULL. Don't use it.
  */
 xmlNodePtr *
 xsltTemplateProcess(xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, xmlNodePtr node) {
index ed4d4db..76b5af8 100644 (file)
@@ -82,6 +82,20 @@ int xsltMaxDepth = 5000;
 #define IS_BLANK_NODE(n)                                               \
     (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
 
+
+/*
+* Forward declarations
+*/
+
+static xmlNsPtr
+xsltCopyNamespaceListInternal(xmlNodePtr node, xmlNsPtr cur);
+
+static xmlNodePtr
+xsltCopyTreeInternal(xsltTransformContextPtr ctxt,
+                    xmlNodePtr invocNode,
+                    xmlNodePtr node,
+                    xmlNodePtr insert, int isLRE, int topElemVisited);
+
 /**
  * templPush:
  * @ctxt: the transformation context
@@ -615,15 +629,18 @@ xsltCopyTextString(xsltTransformContextPtr ctxt, xmlNodePtr target,
     len = xmlStrlen(string);
     if ((ctxt->type == XSLT_OUTPUT_XML) &&
        (ctxt->style->cdataSection != NULL) &&
-       (target != NULL) && (target->type == XML_ELEMENT_NODE) &&
+       (target != NULL) &&
+       (target->type == XML_ELEMENT_NODE) &&
        (((target->ns == NULL) && 
          (xmlHashLookup2(ctxt->style->cdataSection,
                          target->name, NULL) != NULL)) ||
         ((target->ns != NULL) &&
          (xmlHashLookup2(ctxt->style->cdataSection,
-                         target->name, target->ns->href) != NULL)))) {
+                         target->name, target->ns->href) != NULL))))
+    {
        if ((target != NULL) && (target->last != NULL) &&
-           (target->last->type == XML_CDATA_SECTION_NODE)) {
+           (target->last->type == XML_CDATA_SECTION_NODE))
+       {
            return(xsltAddTextString(ctxt, target->last, string, len));
        }
        copy = xmlNewCDataBlock(ctxt->output, string, len);
@@ -711,6 +728,7 @@ xsltCopyText(xsltTransformContextPtr ctxt, xmlNodePtr target,
        /*
        * TODO: Since this doesn't merge adjacent CDATA-section nodes,
        * we'll get: <![CDATA[x]]><!CDATA[y]]>.
+       * TODO: Reported in #321505.
        */
        copy = xmlNewCDataBlock(ctxt->output, cur->content,
                                xmlStrlen(cur->content));
@@ -789,136 +807,51 @@ xsltCopyText(xsltTransformContextPtr ctxt, xmlNodePtr target,
 }
 
 /**
- * xsltCopyProp:
+ * xsltShallowCopyAttr:
  * @ctxt:  a XSLT process context
- * @targetElem:  the element where the attribute will be grafted
+ * @invocNode: responsible node in the stylesheet; used for error reports
+ * @target:  the element where the attribute will be grafted
  * @attr: the attribute to be copied
  *
- * Do a copy of an attribute
+ * Do a copy of an attribute.
+ * Called by:
+ *  - xsltCopyTreeInternal()
+ *  - xsltCopyOf()
+ *  - xsltCopy()
  *
  * Returns: a new xmlAttrPtr, or NULL in case of error.
  */
 static xmlAttrPtr
-xsltCopyProp(xsltTransformContextPtr ctxt, xmlNodePtr targetElem,
-            xmlAttrPtr attr)
+xsltShallowCopyAttr(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
+            xmlNodePtr target, xmlAttrPtr attr)
 {
-    xmlAttrPtr attrCopy;
+    xmlAttrPtr copy;
     xmlChar *value;
-#ifdef XSLT_REFACTORED 
-    xmlNodePtr txtNode;
-#endif
 
     if (attr == NULL)
        return(NULL);
 
-    if (targetElem->type != XML_ELEMENT_NODE) {
-       /*
-       * TODO: Hmm, it would be better to have the node at hand of the
-       *  instruction which lead to this here.
-       */
-       xsltTransformError(ctxt, NULL, NULL,
-           "Result tree construction error: cannot set an attribute node "
-           "on a non-element node.\n");
+    if (target->type != XML_ELEMENT_NODE) {
+       xsltTransformError(ctxt, NULL, invocNode,
+           "Cannot add an attribute node to a non-element node.\n");
        return(NULL);
-    }    
+    }
+    
+    if (target->children != NULL) {
+       xsltTransformError(ctxt, NULL, invocNode,
+           "Attribute nodes must be added before "
+           "any child nodes to an element.\n");
+       return(NULL);
+    }
 
-#ifdef XSLT_REFACTORED
-    /*
-    * Create the attribute node.
-    */
+    value = xmlNodeListGetString(attr->doc, attr->children, 1);
     if (attr->ns != NULL) {
-       xmlNsPtr ns = NULL;
-       const xmlChar *prefix = attr->ns->prefix;
-       
-       /*
-       * Process namespace semantics
-       *
-       * RESTRUCTURE TODO: This is the same code as in
-       *  xsltAttributeInternal() (attributes.c), but I currently
-       *  don't want to add yet another ns-lookup function.
-       */
-       if ((targetElem->ns != NULL) &&
-           (targetElem->ns->prefix != NULL) &&
-           xmlStrEqual(targetElem->ns->href, attr->ns->href))
-       {
-           ns = targetElem->ns;
-           goto namespace_finished;
-       }
-       if (prefix != NULL) {
-           /*
-           * Search by ns-prefix.
-           */
-           ns = xmlSearchNs(targetElem->doc, targetElem, prefix);
-           if ((ns != NULL) &&
-               (xmlStrEqual(ns->href, attr->ns->href)))
-           {
-               goto namespace_finished;
-           }
-       }
-       /*
-       * Fallback to a search by ns-name.
-       */      
-       ns = xmlSearchNsByHref(targetElem->doc, targetElem, attr->ns->href);
-       if ((ns != NULL) && (ns->prefix != NULL)) {
-           goto namespace_finished;
-       }
-       /*
-       * OK, we need to declare the namespace on the target element.
-       */
-       if (prefix) {
-           if (targetElem->nsDef != NULL) {
-               ns = targetElem->nsDef;
-               do {
-                   if ((ns->prefix) && xmlStrEqual(ns->prefix, prefix)) {
-                       /*
-                       * The prefix aready occupied.
-                       */
-                       break;
-                   }
-                   ns = ns->next;
-               } while (ns != NULL);
-               if (ns == NULL) {
-                   ns = xmlNewNs(targetElem, attr->ns->href, prefix);
-                   goto namespace_finished;
-               }
-           }
-       }
-       /*
-       * Generate a new prefix.
-       */
-       {
-           const xmlChar *basepref = prefix;
-           xmlChar pref[30];
-           int counter = 0;
-           
-           if (prefix != NULL)
-               basepref = prefix;
-           else
-               basepref = xmlStrdup(BAD_CAST "ns");
-           
-           do {
-               snprintf((char *) pref, 30, "%s_%d",
-                   basepref, counter++);
-               ns = xmlSearchNs(targetElem->doc,
-                   (xmlNodePtr) attr, BAD_CAST pref);
-               if (counter > 1000) {
-                   xsltTransformError(ctxt, NULL, (xmlNodePtr) attr,
-                       "Namespace fixup error: Failed to compute a "
-                       "new unique ns-prefix for the copied attribute "
-                       "{%s}%s'.\n", attr->ns->href, attr->name);
-                   ns = NULL;
-                   break;
-               }
-           } while (ns != NULL);
-           if (basepref != prefix)
-               xmlFree((xmlChar *)basepref);
-           ns = xmlNewNs(targetElem, attr->ns->href, BAD_CAST pref);
-       }
-
-namespace_finished:
+       xmlNsPtr ns; 
 
+       ns = xsltGetSpecialNamespace(ctxt, invocNode,
+           attr->ns->href, attr->ns->prefix, target);
        if (ns == NULL) {
-           xsltTransformError(ctxt, NULL, (xmlNodePtr) attr,
+           xsltTransformError(ctxt, NULL, invocNode,
                "Namespace fixup error: Failed to acquire an in-scope "
                "namespace binding of the copied attribute '{%s}%s'.\n",
                attr->ns->href, attr->name);
@@ -926,115 +859,155 @@ namespace_finished:
            * TODO: Should we just stop here?
            */
        }
-       attrCopy = xmlSetNsProp(targetElem, ns, attr->name, NULL);
+       /*
+       * Note that xmlSetNsProp() will take care of duplicates
+       * and assigns the new namespace even to a duplicate.
+       */
+       copy = xmlSetNsProp(target, ns, attr->name, value);
     } else {
-       attrCopy = xmlSetNsProp(targetElem, NULL, attr->name, NULL);
+       copy = xmlSetNsProp(target, NULL, attr->name, value);
     }
-    if (attrCopy == NULL)      
-       return(NULL);    
+    if (value != NULL)
+       xmlFree(value);
+
+    if (copy == NULL)
+       return(NULL);
+
+#if 0
     /*
     * NOTE: This was optimized according to bug #342695.
     * TODO: Can this further be optimized, if source and target
     *  share the same dict and attr->children is just 1 text node
     *  which is in the dict? How probable is such a case?
     */
+    /*
+    * TODO: Do we need to create an empty text node if the value
+    *  is the empty string?
+    */
     value = xmlNodeListGetString(attr->doc, attr->children, 1);
     if (value != NULL) {
-       txtNode = xmlNewDocText(targetElem->doc, NULL);
+       txtNode = xmlNewDocText(target->doc, NULL);
        if (txtNode == NULL)
            return(NULL);
-       if ((targetElem->doc != NULL) &&
-           (targetElem->doc->dict != NULL))
+       if ((target->doc != NULL) &&
+           (target->doc->dict != NULL))
        {
            txtNode->content =
-               (xmlChar *) xmlDictLookup(targetElem->doc->dict,
+               (xmlChar *) xmlDictLookup(target->doc->dict,
                    BAD_CAST value, -1);
-           xmlFree(value);         
+           xmlFree(value);
        } else
            txtNode->content = value;
-       attrCopy->children = txtNode;
-    }
-    /*
-    * URGENT TODO: Do we need to create an empty text node if the value
-    *  is the empty string?
-    */    
-
-#else /* not XSLT_REFACTORED */
-
-    value = xmlNodeListGetString(attr->doc, attr->children, 1);
-    if (attr->ns != NULL) {
-       xmlNsPtr ns;
-       ns = xsltGetPlainNamespace(ctxt, attr->parent, attr->ns, targetElem);
-       attrCopy = xmlSetNsProp(targetElem, ns, attr->name, value);
-    } else {
-       attrCopy = xmlSetNsProp(targetElem, NULL, attr->name, value);
+       copy->children = txtNode;
     }
-    if (value != NULL)
-       xmlFree(value);
-
-#endif /* not XSLT_REFACTORED */
+#endif
 
-    return(attrCopy);
+    return(copy);
 }
 
 /**
- * xsltCopyPropList:
+ * xsltCopyAttrListNoOverwrite:
  * @ctxt:  a XSLT process context
- * @target:  the element where the properties will be grafted
- * @cur:  the first property
+ * @invocNode: responsible node in the stylesheet; used for error reports
+ * @target:  the element where the new attributes will be grafted
+ * @attr:  the first attribute in the list to be copied
  *
- * Do a copy of a properties list.
+ * Copies a list of attribute nodes, starting with @attr, over to the
+ * @target element node.
  *
- * Returns: a new xmlAttrPtr, or NULL in case of error.
+ * Called by:
+ *  - xsltCopyTreeInternal()
+ *
+ * Returns 0 on success and -1 on errors and internal errors.
  */
-static xmlAttrPtr
-xsltCopyPropList(xsltTransformContextPtr ctxt, xmlNodePtr target,
-                xmlAttrPtr cur) {
-    xmlAttrPtr ret = NULL;
-    xmlAttrPtr p = NULL,q;
-    xmlNsPtr ns;
+static int
+xsltCopyAttrListNoOverwrite(xsltTransformContextPtr ctxt,
+                           xmlNodePtr invocNode,
+                           xmlNodePtr target, xmlAttrPtr attr)
+{
+    xmlAttrPtr last = NULL, copy;
+    xmlNsPtr origNs = NULL, copyNs = NULL;
+    xmlChar *value = NULL;
 
-    while (cur != NULL) {
-       if (cur->ns != NULL) {
-           ns = xsltGetNamespace(ctxt, cur->parent, cur->ns, target);
+    /*
+    * Don't use xmlCopyProp() here, since it will try to
+    * reconciliate namespaces.
+    */
+    while (attr != NULL) {
+       /*
+       * Find a namespace node in the tree of @target.
+       * Avoid searching for the same ns.
+       */
+       if (attr->ns != origNs) {
+           origNs = attr->ns;
+           if (attr->ns != NULL) {
+               copyNs = xsltGetSpecialNamespace(ctxt, invocNode,
+                   attr->ns->href, attr->ns->prefix, target);
+               if (copyNs == NULL)
+                   return(-1);
+           } else
+               copyNs = NULL;
+       }
+       if (attr->children)
+           value = xmlNodeListGetString(attr->doc, attr->children, 1);
+       /*
+       * REVISIT: I think xmlNewDocProp() is the only attr function
+       * which does not eval if the attr is of type ID. This is good,
+       * since we don't need this.
+       */
+       copy = xmlNewDocProp(target->doc, attr->name, BAD_CAST value);
+       if (copy == NULL)
+           return(-1);
+       copy->parent = target;
+       copy->ns = copyNs;
+       
+       if (last == NULL) {
+           target->properties = copy;
+           last = copy;
        } else {
-           ns = NULL;
+           last->next = copy;
+           copy->prev = last;
+           last = copy;
        }
-        q = xmlCopyProp(target, cur);
-       if (q != NULL) {
-           q->ns = ns;
-           if (p == NULL) {
-               ret = p = q;
-           } else {
-               p->next = q;
-               q->prev = p;
-               p = q;
-           }
+       /*
+       * OPTIMIZE TODO: How to avoid this intermediate string?
+       */
+       if (value != NULL) {
+           xmlFree(value);
+           value = NULL;
        }
-       cur = cur->next;
-    }
-    return(ret);
+       attr = attr->next;
+    }    
+    return(0);
 }
 
 /**
- * xsltCopyNode:
- * @ctxt:  a XSLT process context
- * @node:  the element node in the source tree.
- * @insert:  the parent in the result tree.
+ * xsltShallowCopyElem:
+ * @ctxt:  the XSLT process context
+ * @node:  the element node in the source tree
+ *         or the Literal Result Element
+ * @insert:  the parent in the result tree
+ * @isLRE: if @node is a Literal Result Element
  *
  * Make a copy of the element node @node
- * and insert it as last child of @insert
- * Intended *only* for copying literal result elements and
- * text-nodes.
+ * and insert it as last child of @insert.
+ *
+ * URGENT TODO: The problem with this one (for the non-refactored code)
+ * is that it is used for both, Literal Result Elements *and*
+ * copying input nodes.
+ *
+ * BIG NOTE: This is only called for XML_ELEMENT_NODEs.
+ *
  * Called from:
- *   xsltApplyOneTemplateInt()
- *   xsltCopy()
+ *   xsltApplyOneTemplateInt() (for Literal Result Elements - which is a problem)
+ *   xsltCopy() (for shallow-copying elements via xsl:copy)
  *
  * Returns a pointer to the new node, or NULL in case of error
  */
 static xmlNodePtr
-xsltCopyNode(xsltTransformContextPtr ctxt, xmlNodePtr node,
-            xmlNodePtr insert) {
+xsltShallowCopyElem(xsltTransformContextPtr ctxt, xmlNodePtr node,
+                   xmlNodePtr insert, int isLRE)
+{
     xmlNodePtr copy;
 
     if ((node->type == XML_DTD_NODE) || (insert == NULL))
@@ -1042,33 +1015,59 @@ xsltCopyNode(xsltTransformContextPtr ctxt, xmlNodePtr node,
     if ((node->type == XML_TEXT_NODE) ||
        (node->type == XML_CDATA_SECTION_NODE))
        return(xsltCopyText(ctxt, insert, node, 0));
+
     copy = xmlDocCopyNode(node, insert->doc, 0);
     if (copy != NULL) {
        copy->doc = ctxt->output;
        xmlAddChild(insert, copy);
+
        if (node->type == XML_ELEMENT_NODE) {
            /*
             * Add namespaces as they are needed
             */
-           if (node->nsDef != NULL)
-               xsltCopyNamespaceList(ctxt, copy, node->nsDef);
-       }
-       if ((node->type == XML_ELEMENT_NODE) ||
-            (node->type == XML_ATTRIBUTE_NODE)) {
+           if (node->nsDef != NULL) {
+               /*
+               * TODO: Remove the LRE case in the refactored code
+               * gets enabled.
+               */
+               if (isLRE)
+                   xsltCopyNamespaceList(ctxt, copy, node->nsDef);
+               else
+                   xsltCopyNamespaceListInternal(copy, node->nsDef);
+           }
+
+           /*
+           * URGENT TODO: The problem with this is that it does not
+           *  copy over all namespace nodes in scope.
+           *  The damn thing about this is, that we would need to
+           *  use the xmlGetNsList(), for every single node; this is
+           *  also done in xsltCopyTreeInternal(), but only for the top node.
+           */
            if (node->ns != NULL) {
-               copy->ns = xsltGetNamespace(ctxt, node, node->ns, copy);
+               if (isLRE) {
+                   /*
+                   * REVISIT TODO: Since the non-refactored code still does
+                   *  ns-aliasing, we need to call xsltGetNamespace() here.
+                   *  Remove this when ready.
+                   */
+                   copy->ns = xsltGetNamespace(ctxt, node, node->ns, copy);
+               } else {
+                   copy->ns = xsltGetSpecialNamespace(ctxt,
+                       node, node->ns->href, node->ns->prefix, copy);
+                   
+               }
            } else if ((insert->type == XML_ELEMENT_NODE) &&
-                      (insert->ns != NULL)) {
-               xmlNsPtr defaultNs;
-
-               defaultNs = xmlSearchNs(insert->doc, insert, NULL);
-               if (defaultNs != NULL)
-                   xmlNewNs(copy, BAD_CAST "", NULL);
+                      (insert->ns != NULL))
+           {
+               /*
+               * "Undeclare" the default namespace.
+               */
+               xsltGetSpecialNamespace(ctxt, node, NULL, NULL, copy);
            }
        }
     } else {
        xsltTransformError(ctxt, NULL, node,
-               "xsltCopyNode: copy %s failed\n", node->name);
+               "xsltShallowCopyElem: copy %s failed\n", node->name);
     }
     return(copy);
 }
@@ -1076,24 +1075,31 @@ xsltCopyNode(xsltTransformContextPtr ctxt, xmlNodePtr node,
 /**
  * xsltCopyTreeList:
  * @ctxt:  a XSLT process context
+ * @invocNode: responsible node in the stylesheet; used for error reports
  * @list:  the list of element nodes in the source tree.
  * @insert:  the parent in the result tree.
  * @literal:  is this a literal result element list
  *
  * Make a copy of the full list of tree @list
  * and insert it as last children of @insert
- * For literal result element, some of the namespaces may not be copied
- * over according to section 7.1 .
+ *
+ * NOTE: Not to be used for Literal Result Elements.
+ *
+ * Used by:
+ *  - xsltCopyOf()
  *
  * Returns a pointer to the new list, or NULL in case of error
  */
 static xmlNodePtr
-xsltCopyTreeList(xsltTransformContextPtr ctxt, xmlNodePtr list,
-            xmlNodePtr insert, int literal) {
+xsltCopyTreeList(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
+                xmlNodePtr list,
+                xmlNodePtr insert, int isLRE, int topElemVisited)
+{
     xmlNodePtr copy, ret = NULL;
 
     while (list != NULL) {
-       copy = xsltCopyTree(ctxt, list, insert, literal);
+       copy = xsltCopyTreeInternal(ctxt, invocNode,
+           list, insert, isLRE, topElemVisited);
        if (copy != NULL) {
            if (ret == NULL) {
                ret = copy;
@@ -1112,73 +1118,183 @@ xsltCopyTreeList(xsltTransformContextPtr ctxt, xmlNodePtr list,
  * Do a copy of a namespace list. If @node is non-NULL the
  * new namespaces are added automatically.
  * Called by:
- *   xsltCopyTree()
+ *   xsltCopyTreeInternal()
  *
- * TODO: What is the exact difference between this function
+ * QUESTION: What is the exact difference between this function
  *  and xsltCopyNamespaceList() in "namespaces.c"?
+ * ANSWER: xsltCopyNamespaceList() tries to apply ns-aliases.
  *
  * Returns: a new xmlNsPtr, or NULL in case of error.
  */
 static xmlNsPtr
-xsltCopyNamespaceListInternal(xmlNodePtr node, xmlNsPtr cur) {
+xsltCopyNamespaceListInternal(xmlNodePtr elem, xmlNsPtr ns) {
     xmlNsPtr ret = NULL;
-    xmlNsPtr p = NULL,q;
+    xmlNsPtr p = NULL, q, luNs;
 
-    if (cur == NULL)
-       return(NULL);
-    if (cur->type != XML_NAMESPACE_DECL)
+    if (ns == NULL)
        return(NULL);
-
     /*
      * One can add namespaces only on element nodes
      */
-    if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
-       node = NULL;
+    if ((elem != NULL) && (elem->type != XML_ELEMENT_NODE))
+       elem = NULL;
 
-    while (cur != NULL) {
-       if (cur->type != XML_NAMESPACE_DECL)
+    do {
+       if (ns->type != XML_NAMESPACE_DECL)
            break;
-
        /*
-        * Avoid duplicating namespace declarations on the tree
+        * Avoid duplicating namespace declarations on the tree.
         */
-       if ((node != NULL) && (node->ns != NULL) &&
-            (xmlStrEqual(node->ns->href, cur->href)) &&
-            (xmlStrEqual(node->ns->prefix, cur->prefix))) {
-           cur = cur->next;
-           continue;
-       }
-       
-       q = xmlNewNs(node, cur->href, cur->prefix);
+       if (elem != NULL) {         
+           if ((elem->ns != NULL) &&
+               xmlStrEqual(elem->ns->prefix, ns->prefix) &&
+               xmlStrEqual(elem->ns->href, ns->href))
+           {
+               ns = ns->next;
+               continue;
+           }
+           luNs = xmlSearchNs(elem->doc, elem, ns->prefix);
+           if ((luNs != NULL) && (xmlStrEqual(luNs->href, ns->href)))
+           {
+               ns = ns->next;
+               continue;
+           }
+       }               
+       q = xmlNewNs(elem, ns->href, ns->prefix);
        if (p == NULL) {
            ret = p = q;
        } else if (q != NULL) {
            p->next = q;
            p = q;
        }
-       cur = cur->next;
-    }
+       ns = ns->next;  
+    } while (ns != NULL);
     return(ret);
 }
 
 /**
- * xsltCopyTree:
- * @ctxt:  a XSLT process context
- * @node:  the element node in the source tree.
- * @insert:  the parent in the result tree.
- * @literal:  is this a literal result element list
+ * xsltShallowCopyNsNode:
+ * @ctxt:  the XSLT transformation context
+ * @invocNode: responsible node in the stylesheet; used for error reports
+ * @insert:  the target element node in the result tree
+ * @ns: the namespace node
+ *
+ * This is used for copying ns-nodes with xsl:copy-of and xsl:copy.
+ *
+ * Returns a new/existing ns-node, or NULL.
+ */
+static int
+xsltShallowCopyNsNode(xsltTransformContextPtr ctxt,
+                     xmlNodePtr invocNode,
+                     xmlNodePtr insert,
+                     xmlNsPtr ns)
+{
+    xmlNsPtr tmpns;
+
+    if ((insert == NULL) || (insert->type != XML_ELEMENT_NODE))
+       return(-1);
+    
+    if (insert->children != NULL) {
+       xsltTransformError(ctxt, NULL, invocNode,
+           "Namespace nodes must be added before "
+           "any child nodes are added to an element.\n");
+       return(1);
+    }
+    /*    
+    *
+    * BIG NOTE: Xalan-J simply overwrites any ns-decls with
+    * an equal prefix. We definitively won't do that.
+    *
+    * MSXML 4.0 and the .NET ignores ns-decls for which an
+    * equal prefix is already in use.
+    *
+    * Saxon raises an error like:
+    * "net.sf.saxon.xpath.DynamicError: Cannot create two namespace
+    * nodes with the same name".
+    *
+    * NOTE: We'll currently follow MSXML here.
+    * REVISIT TODO: Check if it's better to follow Saxon here.
+    */
+    if (ns->prefix == NULL) {
+       /*
+       * If we are adding ns-nodes to an element using e.g.
+       * <xsl:copy-of select="/foo/namespace::*">, then we need
+       * to ensure that we don't incorrectly declare a default
+       * namespace on an element in no namespace, which otherwise
+       * would move the element incorrectly into a namespace, if
+       * the node tree is serialized.
+       */
+       if (insert->ns == NULL)
+           goto occupied;
+    } else if ((ns->prefix[0] == 'x') &&
+       xmlStrEqual(ns->prefix, BAD_CAST "xml"))
+    {
+       return(0);
+    }
+
+    if (insert->nsDef != NULL) {
+       tmpns = insert->nsDef;
+       do {
+           if ((tmpns->prefix == NULL) == (ns->prefix == NULL)) {              
+               if ((tmpns->prefix == ns->prefix) ||
+                   xmlStrEqual(tmpns->prefix, ns->prefix))
+               {
+                   /*
+                   * Same prefix.
+                   */
+                   if (xmlStrEqual(tmpns->href, ns->href))
+                       return(0);
+                   goto occupied;
+               }
+           }
+           tmpns = tmpns->next;
+       } while (tmpns != NULL);
+    }
+    tmpns = xmlSearchNs(insert->doc, insert, ns->prefix);
+    if ((tmpns != NULL) && xmlStrEqual(tmpns->href, ns->href))
+       return(0);
+    /*
+    * Declare a new namespace.
+    * TODO: The problem (wrt efficiency) with this xmlNewNs() is
+    * that it will again search the already declared namespaces
+    * for a duplicate :-/
+    */
+    xmlNewNs(insert, ns->href, ns->prefix);
+    return(0);    
+
+occupied:
+    /*
+    * TODO: We could as well raise an error here (like Saxon does),
+    * or at least generate a warning.
+    */
+    return(0);
+}
+
+/**
+ * xsltCopyTreeInternal:
+ * @ctxt:  the XSLT transformation context
+ * @invocNode: responsible node in the stylesheet; used for error reports
+ * @node:  the element node in the source tree
+ * @insert:  the parent in the result tree
+ * @isLRE:  indicates if @node is a Literal Result Element
+ * @topElemVisited: indicates if a top-most element was already processed
  *
  * Make a copy of the full tree under the element node @node
  * and insert it as last child of @insert
- * For literal result element, some of the namespaces may not be copied
- * over according to section 7.1.
- * TODO: Why is this a public function?
+ *
+ * NOTE: Not to be used for Literal Result Elements.
+ *
+ * Used by:
+ *  - xsltCopyOf()
  *
  * Returns a pointer to the new tree, or NULL in case of error
  */
-xmlNodePtr
-xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr node,
-                    xmlNodePtr insert, int literal) {
+static xmlNodePtr
+xsltCopyTreeInternal(xsltTransformContextPtr ctxt,
+                    xmlNodePtr invocNode,
+                    xmlNodePtr node,
+                    xmlNodePtr insert, int isLRE, int topElemVisited)
+{
     xmlNodePtr copy;
 
     if (node == NULL)
@@ -1203,12 +1319,10 @@ xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr node,
            return(xsltCopyTextString(ctxt, insert, node->content, 0));
         case XML_ATTRIBUTE_NODE:
            return((xmlNodePtr)
-                  xsltCopyProp(ctxt, insert, (xmlAttrPtr) node));
+               xsltShallowCopyAttr(ctxt, invocNode, insert, (xmlAttrPtr) node));
         case XML_NAMESPACE_DECL:
-           if (insert->type != XML_ELEMENT_NODE)
-               return(NULL);
-           return((xmlNodePtr)
-                  xsltCopyNamespaceList(ctxt, insert, (xmlNsPtr) node));
+           return((xmlNodePtr) xsltShallowCopyNsNode(ctxt, invocNode,
+               insert, (xmlNsPtr) node));
            
         case XML_DOCUMENT_TYPE_NODE:
         case XML_DOCUMENT_FRAG_NODE:
@@ -1223,7 +1337,8 @@ xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr node,
     }    
     if (XSLT_IS_RES_TREE_FRAG(node)) {
        if (node->children != NULL)
-           copy = xsltCopyTreeList(ctxt, node->children, insert, 0);
+           copy = xsltCopyTreeList(ctxt, invocNode,
+               node->children, insert, 0, 0);
        else
            copy = NULL;
        return(copy);
@@ -1237,66 +1352,157 @@ xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr node,
         */
        if (insert->last != copy)
            return(insert->last);
-
        copy->next = NULL;
-       /*
-        * Add namespaces as they are needed
-        */
-       if ((node->type == XML_ELEMENT_NODE) ||
-           (node->type == XML_ATTRIBUTE_NODE)) {
-           xmlNsPtr *nsList, *cur, ns;
+
+       if (node->type == XML_ELEMENT_NODE) {       
            /*
-            * Must add any new namespaces in scope for the node.
-            * TODO: Since we try to reuse existing in-scope ns-decls by
-            *  using xmlSearchNsByHref(), this will eventually change
-            *  the prefix of an original ns-binding; thus it might
-            *  break QNames in element/attribute content.
-            */
-           nsList = xmlGetNsList(node->doc, node);
-           if (nsList != NULL) {
-               cur = nsList;
-               while (*cur != NULL) {
-                   ns = xmlSearchNsByHref(insert->doc, insert, (*cur)->href);
-                   if (ns == NULL)
-                       xmlNewNs(copy, (*cur)->href, (*cur)->prefix);
-                   cur++;
+           * Copy in-scope namespace nodes.
+           *
+           * REVISIT: Since we try to reuse existing in-scope ns-decls by
+           *  using xmlSearchNsByHref(), this will eventually change
+           *  the prefix of an original ns-binding; thus it might
+           *  break QNames in element/attribute content.
+           * OPTIMIZE TODO: If we had a xmlNsPtr * on the transformation
+           *  context, plus a ns-lookup function, which writes directly
+           *  to a given list, then we wouldn't need to create/free the
+           *  nsList every time.
+           */
+           if ((topElemVisited == 0) &&
+               (node->parent != NULL) &&
+               (node->parent->type != XML_DOCUMENT_NODE) &&
+               (node->parent->type != XML_HTML_DOCUMENT_NODE))
+           {
+               xmlNsPtr *nsList, *curns, ns;
+               
+               /*
+               * If this is a top-most element in a tree to be
+               * copied, then we need to ensure that all in-scope
+               * namespaces are copied over. For nodes deeper in the
+               * tree, it is sufficient to reconcile only the ns-decls
+               * (node->nsDef entries).
+               */
+               
+               nsList = xmlGetNsList(node->doc, node);
+               if (nsList != NULL) {
+                   curns = nsList;
+                   do {
+                       /*
+                       * Search by prefix first in order to break as less
+                       * QNames in element/attribute content as possible.
+                       */
+                       ns = xmlSearchNs(insert->doc, insert,
+                           (*curns)->prefix);
+                       
+                       if ((ns == NULL) ||
+                           (! xmlStrEqual(ns->href, (*curns)->href)))
+                       {
+                           ns = NULL;
+                           /*
+                           * Search by namespace name.
+                           * REVISIT TODO: Currently disabled.
+                           */
+#if 0
+                           ns = xmlSearchNsByHref(insert->doc,
+                               insert, (*curns)->href);
+#endif
+                       }
+                       if (ns == NULL) {
+                           /*
+                           * Declare a new namespace on the copied element.
+                           */
+                           ns = xmlNewNs(copy, (*curns)->href,
+                               (*curns)->prefix);
+                           /* TODO: Handle errors */
+                       }
+                       if (node->ns == *curns) {
+                           /*
+                           * If this was the original's namespace then set
+                           * the generated counterpart on the copy.
+                           */
+                           copy->ns = ns;
+                       }
+                       curns++;
+                   } while (*curns != NULL);
+                   xmlFree(nsList);
                }
-               xmlFree(nsList);
-           }
-           if (node->ns != NULL) {
+           } else if (node->nsDef != NULL) {           
                /*
-               * This will map  copy->ns to one of the newly created
-               * in-scope ns-decls.
+               * Copy over all namespace declaration attributes.               
                */
-               copy->ns = xsltGetNamespace(ctxt, node, node->ns, copy);                
+               if (node->nsDef != NULL) {
+                   if (isLRE)
+                       xsltCopyNamespaceList(ctxt, copy, node->nsDef);
+                   else
+                       xsltCopyNamespaceListInternal(copy, node->nsDef);
+               }
+           }
+           /*
+           * Set the namespace.
+           */
+           if (node->ns != NULL) {
+               if (copy->ns == NULL) {
+                   /*
+                   * This will map copy->ns to one of the newly created
+                   * in-scope ns-decls, OR create a new ns-decl on @copy.
+                   */
+                   copy->ns = xsltGetSpecialNamespace(ctxt, invocNode,
+                       node->ns->href, node->ns->prefix, copy);
+               }
            } else if ((insert->type == XML_ELEMENT_NODE) &&
                (insert->ns != NULL))
            {
-               xmlNsPtr defaultNs;
-
-               defaultNs = xmlSearchNs(insert->doc, insert, NULL);
-               if (defaultNs != NULL)
-                   xmlNewNs(copy, BAD_CAST "", NULL);
+               /*
+               * "Undeclare" the default namespace on @copy with xmlns="".
+               */
+               xsltGetSpecialNamespace(ctxt, invocNode, NULL, NULL, copy);
            }
+           /*
+           * Copy attribute nodes.
+           */
+           if (node->properties != NULL) {
+               xsltCopyAttrListNoOverwrite(ctxt, invocNode,
+                   copy, node->properties);
+           }
+           if (topElemVisited == 0)
+               topElemVisited = 1;
        }
-       if (node->nsDef != NULL) {
-           if (literal)
-               xsltCopyNamespaceList(ctxt, copy, node->nsDef);
-           else
-               xsltCopyNamespaceListInternal(copy, node->nsDef);
+       /*
+       * Copy the subtree.
+       */
+       if (node->children != NULL) {
+           xsltCopyTreeList(ctxt, invocNode,
+               node->children, copy, isLRE, topElemVisited);
        }
-       if (node->properties != NULL)
-           copy->properties = xsltCopyPropList(ctxt, copy,
-                                              node->properties);
-       if (node->children != NULL)
-           xsltCopyTreeList(ctxt, node->children, copy, literal);
     } else {
-       xsltTransformError(ctxt, NULL, node,
-               "xsltCopyTree: copy %s failed\n", node->name);
+       xsltTransformError(ctxt, NULL, invocNode,
+           "xsltCopyTreeInternal: Copying of '%s' failed.\n", node->name);
     }
     return(copy);
 }
 
+/**
+ * xsltCopyTree:
+ * @ctxt:  the XSLT transformation context
+ * @node:  the element node in the source tree
+ * @insert:  the parent in the result tree
+ * @literal:  indicates if @node is a Literal Result Element
+ *
+ * Make a copy of the full tree under the element node @node
+ * and insert it as last child of @insert
+ * For literal result element, some of the namespaces may not be copied
+ * over according to section 7.1.
+ * TODO: Why is this a public function?
+ *
+ * Returns a pointer to the new tree, or NULL in case of error
+ */
+xmlNodePtr
+xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr node,
+            xmlNodePtr insert, int literal)
+{
+    return(xsltCopyTreeInternal(ctxt, node, node, insert, literal, 0));
+    
+}
+
 /************************************************************************
  *                                                                     *
  *             Error/fallback processing                               *
@@ -1659,277 +1865,6 @@ xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node,
     }
 }
 
-#ifdef XSLT_REFACTORED
-/**
-* xsltTransLREUndeclareDefaultNs:
-* @ctxt:  the transformation context
-* @cur:  the literal result element
-* @ns:  the namespace
-* @out:  the output node (or its parent)
-*
-*
-* Find a matching (prefix and ns-name) ns-declaration
-*  for the given @ns in the result tree.
-* If none is found then a new ns-declaration will be
-*  added to @out. If, in this case, the given prefix is already
-*  in use, then a ns-declaration with a modified ns-prefix
-*  be we created.
-*
-* Returns the acquired ns-declaration
-*         or NULL in case of an API or internal error.
-*/
-static int
-xsltTransLREUndeclareResultDefaultNs(xsltTransformContextPtr ctxt,
-                                    xmlNodePtr cur,
-                                    xmlNodePtr resultElem)
-{
-    xmlNsPtr ns;
-    /*
-    * OPTIMIZE TODO: This all could be optimized by keeping track of
-    *  the ns-decls currently in-scope via a specialized context.
-    */
-    /*
-    * Search on the result element itself.
-    */
-    if (resultElem->nsDef != NULL) {
-       ns = resultElem->nsDef;
-       do {
-           if (ns->prefix == NULL) {
-               if ((ns->href != NULL) && (ns->href[0] != 0)) {
-                   /*
-                   * Raise a namespace normalization error.
-                   */
-                   xsltTransformError(ctxt, NULL, cur,
-                       "Namespace normalization error: Cannot undeclare "
-                       "the default namespace, since the default namespace "
-                       "'%s' is already declared on the result element.\n",
-                       ns->href);
-                   return(1);
-               } else {
-                   /*
-                   * The default namespace was undeclared on the
-                   * result element.
-                   */
-                   return(0);
-               }
-               break;
-           }
-           ns = ns->next;
-       } while (ns != NULL);
-    }
-
-    if ((resultElem->parent != NULL) &&
-       (resultElem->parent->type == XML_ELEMENT_NODE))
-    {
-       /*
-       * The parent element is in no namespace, so assume
-       * that there is no default namespace in scope.
-       */
-       if (resultElem->parent->ns == NULL)
-           return(0);
-
-       ns = xmlSearchNs(resultElem->doc, resultElem->parent,
-           NULL);
-       /*
-       * Fine if there's no default ns is scope, or if the
-       * default ns was undeclared.
-       */
-       if ((ns == NULL) || (ns->href == NULL) || (ns->href[0] == 0))
-           return(0);
-
-       /*
-       * Undeclare the default namespace.
-       */
-       ns = xmlNewNs(resultElem, BAD_CAST "", NULL);
-       /* TODO: Check result */        
-       return(0);
-    }
-    return(0);
-}
-
-/**
-* xsltTransLREAcquireResultInScopeNs:
-* @ctxt: the transformation context
-* @cur: the literal result element (in the stylesheet)
-* @literalNs: the namespace (in the stylsheet)
-* @resultElem: the generated result element
-*
-*
-* Find a matching (prefix and ns-name) ns-declaration
-*  for the given @ns in the result tree.
-* If none is found then a new ns-declaration will be
-*  added to @out. If, in this case, the given prefix is already
-*  in use, then a ns-declaration with a modified ns-prefix
-*  be we created.
-*
-* Returns the acquired ns-declaration
-*         or NULL in case of an API or internal error.
-*/
-static xmlNsPtr
-xsltTransLREAcquireResultInScopeNs(xsltTransformContextPtr ctxt,
-                                  xmlNodePtr cur,
-                                  xmlNsPtr literalNs,
-                                  xmlNodePtr resultElem)
-{    
-    xmlNsPtr ns;
-    int prefixOccupied = 0;
-
-    if ((ctxt == NULL) || (cur == NULL) || (resultElem == NULL))
-       return(NULL);
-    
-    /*
-    * OPTIMIZE TODO: This all could be optimized by keeping track of
-    *  the ns-decls currently in-scope via a specialized context.
-    */
-    /*
-    * NOTE: Namespace exclusion and ns-aliasing is performed at
-    * compilation-time in the refactored code; so this need not be done
-    * here.
-    */
-    /*
-    * First: search on the result element itself.
-    */
-    if (resultElem->nsDef != NULL) {
-       ns = resultElem->nsDef;
-       do {
-           if ((ns->prefix == NULL) == (literalNs->prefix == NULL)) {
-               if (literalNs->prefix == NULL) {
-                   if (xmlStrEqual(ns->href, literalNs->href))
-                       return(ns);
-                   prefixOccupied = 1;
-                   break;
-               } else if ((ns->prefix[0] == literalNs->prefix[0]) &&
-                    xmlStrEqual(ns->prefix, literalNs->prefix))
-               {
-                   if (xmlStrEqual(ns->href, literalNs->href))
-                       return(ns);
-                   prefixOccupied = 1;
-                   break;
-               }
-           }
-           ns = ns->next;
-       } while (ns != NULL);
-    }
-    if (prefixOccupied) {
-       /*
-       * If the ns-prefix is occupied by an other ns-decl on the
-       * result element, then this means:
-       * 1) The desired prefix is shadowed
-       * 2) There's no way around changing the prefix  
-       *
-       * Try a desperate search for an in-scope ns-decl
-       * with a matching ns-name before we use the last option,
-       * which is to recreate the ns-decl with a modified prefix.
-       */
-       ns = xmlSearchNsByHref(resultElem->doc, resultElem, literalNs->href);
-       if (ns != NULL)
-           return(ns);
-
-       /*
-       * Fallback to changing the prefix.
-       */    
-    } else if ((resultElem->parent != NULL) &&
-       (resultElem->parent->type == XML_ELEMENT_NODE)) {
-       /*
-       * Try to find a matching ns-decl in the ancestor-axis.
-       *
-       * Check the common case: The parent element of the current
-       * result element is in the same namespace (with an equal ns-prefix).
-       */     
-       if ((resultElem->parent->ns != NULL) &&
-           ((resultElem->parent->ns->prefix == NULL) ==
-            (literalNs->prefix == NULL)))
-       {
-           ns = resultElem->parent->ns;
-           
-           if (literalNs->prefix == NULL) {
-               if (xmlStrEqual(ns->href, literalNs->href))
-                   return(ns);
-           } else if ((ns->prefix[0] == literalNs->prefix[0]) &&
-               xmlStrEqual(ns->prefix, literalNs->prefix) &&
-               xmlStrEqual(ns->href, literalNs->href))
-           {
-               return(ns);
-           }
-       }
-       /*
-       * Lookup the remaining in-scope namespaces.
-       */    
-       ns = xmlSearchNs(resultElem->doc, resultElem->parent,
-           literalNs->prefix);
-       if ((ns != NULL) && xmlStrEqual(ns->href, literalNs->href))
-           return(ns);
-       ns = NULL;
-       /*
-       * Either no matching ns-prefix was found or the namespace is
-       * shadowed.
-       * Create a new ns-decl on the current result element.
-       *
-       * SPEC TODO: Hmm, we could also try to reuse an in-scope
-       *  namespace with a matching ns-name but a different
-       *  ns-prefix.
-       *  What has higher precedence? 
-       *  1) If keeping the prefix: create a new ns-decl.
-       *  2) If reusal: first lookup ns-names; then fallback
-       *     to creation of a new ns-decl.
-       * REVISIT TODO: this currently uses case 2) since this
-       *  is the way it used to be before refactoring.
-       */
-       ns = xmlSearchNsByHref(resultElem->doc, resultElem,
-           literalNs->href);
-       if (ns != NULL)
-           return(ns);
-       /*
-       * Create the ns-decl on the current result element.
-       */
-       ns = xmlNewNs(resultElem, literalNs->href, literalNs->prefix);
-       /* TODO: check errors */
-       return(ns);
-    } else if ((resultElem->parent == NULL) ||
-       (resultElem->parent->type != XML_ELEMENT_NODE))
-    {
-       /*
-       * This is the root of the tree.
-       */
-       ns = xmlNewNs(resultElem, literalNs->href, literalNs->prefix);
-       /* TODO: Check result */
-       return(ns);
-    }
-    /*
-    * Fallback: we need to generate a new prefix and declare the namespace
-    * on the result element.
-    */
-    {
-       xmlChar prefix[30];
-       int counter = 0;
-       
-       /*
-       * Comment copied from xslGetNamespace():
-       *  "For an element node, if we don't find it, or it's the default
-       *  and this element already defines a default (bug 165560), we
-       *  need to create it."
-       */              
-       do {
-           snprintf((char *) prefix, 30, "%s_%d",
-               literalNs->prefix, counter++);
-           ns = xmlSearchNs(resultElem->doc, resultElem, BAD_CAST prefix);
-           if (counter > 1000) {
-               xsltTransformError(ctxt, NULL, cur,
-                   "Internal error in xsltTransLREAcquireInScopeNs(): "                    
-                   "Failed to compute a unique ns-prefix for the "
-                   "result element");
-               return(NULL);
-           }
-       } while (ns != NULL);
-       ns = xmlNewNs(resultElem, literalNs->href, BAD_CAST prefix);
-       /* TODO: Check result */
-       return(ns);
-    }
-    return(NULL);    
-}
-
-#endif /* XSLT_REFACTORED */
-
 /**
  * xsltApplyOneTemplate:
  * @ctxt:  a XSLT process context
@@ -2138,7 +2073,8 @@ xsltApplyOneTemplateInt(xsltTransformContextPtr ctxt, xmlNodePtr node,
 #endif
                /*
                * Copy the raw element-node.
-               * OLD: if ((copy = xsltCopyNode(ctxt, cur, insert)) == NULL)
+               * OLD: if ((copy = xsltShallowCopyElem(ctxt, cur, insert))
+               *     == NULL)
                *   goto error;
                */              
                copy = xmlDocCopyNode(cur, insert->doc, 0);
@@ -2200,43 +2136,34 @@ xsltApplyOneTemplateInt(xsltTransformContextPtr ctxt, xmlNodePtr node,
                    if (cur->ns != NULL) {
                        /*
                        * If there's no such ns-decl in the result tree,
-                       * then xsltGetNamespace() will create a ns-decl
-                       * on the copied node.
-                       */
-                       /*
-                       * REVISIT TODO: Changed to use
-                       *  xsltTransLREAcquireInScopeNs() instead of
-                       *  xsltGetNamespace().
-                       *  OLD: copy->ns = xsltGetNamespace(ctxt, cur,
-                       *                     cur->ns, copy);
-                       */
-                       copy->ns = xsltTransLREAcquireResultInScopeNs(ctxt,
-                           cur, cur->ns, copy);
+                       * then xsltGetSpecialNamespace() will
+                       * create a ns-decl on the copied node.
+                       */                      
+                       copy->ns = xsltGetSpecialNamespace(ctxt, cur,
+                           cur->ns->href, cur->ns->prefix, copy);                          
                    } else {
                        /*
                        * Undeclare the default namespace if needed.
-                       * This can be skipped, if:
-                       * 1) If the result element has no ns-decls, in which
-                       *    case the result element abviously does not
-                       *    declare a default namespace.
-                       * 2) AND there's either no parent, or the parent
-                       *   is in no namespace; this means there's no
-                       *   default namespace is scope to care about.
+                       * This can be skipped, if the result element has
+                       *  no ns-decls, in which case the result element
+                       *  obviously does not declare a default namespace;
+                       *  AND there's either no parent, or the parent
+                       *  element is in no namespace; this means there's no
+                       *  default namespace is scope to care about.
                        *
-                       * REVISIT TODO: This might result in massive
+                       * REVISIT: This might result in massive
                        *  generation of ns-decls if nodes in a default
                        *  namespaces are mixed with nodes in no namespace.
                        *  
                        */
                        if (copy->nsDef ||
-                           ((insert != NULL) && (insert->ns != NULL)))
-                           xsltTransLREUndeclareResultDefaultNs(ctxt,
-                               cur, copy);
-#if 0
-                       defaultNs = xmlSearchNs(insert->doc, insert, NULL);
-                       if ((defaultNs != NULL) && (defaultNs->href != NULL))
-                           xmlNewNs(copy, BAD_CAST "", NULL);
-#endif
+                           ((insert != NULL) &&
+                            (insert->type == XML_ELEMENT_NODE) &&
+                            (insert->ns != NULL)))
+                       {
+                           xsltGetSpecialNamespace(ctxt, cur,
+                               NULL, NULL, copy);
+                       }
                    }
                }
                /*
@@ -2245,118 +2172,11 @@ xsltApplyOneTemplateInt(xsltTransformContextPtr ctxt, xmlNodePtr node,
                *  is processed to produce an attribute for the element in
                *  the result tree."
                * TODO: Refactor this, since it still uses ns-aliasing.
+               * NOTE: See bug #341325.
                */
                if (cur->properties != NULL) {
                    xsltAttrListTemplateProcess(ctxt, copy, cur->properties);
                }
-               /*
-               * OLD-COMMENT: "Add extra namespaces inherited from the
-               *   current template if we are in the first level children
-               *   and this is a "real" template.
-               *
-               * SPEC XSLT 2.0:
-               *  "The following namespaces are designated as excluded
-               *   namespaces:
-               *  - The XSLT namespace URI
-               *      (http://www.w3.org/1999/XSL/Transform)
-               *  - A namespace URI declared as an extension namespace
-               *  - A namespace URI designated by using an
-               *      [xsl:]exclude-result-prefixes
-               *
-               * TODO:
-               *  XSLT 1.0
-               *   1) Supply all in-scope namespaces
-               *   2) Skip excluded namespaces (see above)
-               *   3) Apply namespace aliasing
-               *
-               *  XSLT 2.0 (will generate
-               *            redundant namespaces in some cases):
-               *   1) Supply all in-scope namespaces
-               *   2) Skip excluded namespaces if *not* target-namespace
-               *      of an namespace alias
-               *   3) Apply namespace aliasing
-               *
-               * NOTE: See bug #341325.
-               */
-#if 0          
-               if ((templ != NULL) && (oldInsert == insert) &&
-                   (ctxt->templ != NULL) &&
-                   (ctxt->templ->inheritedNs != NULL)) {
-                   int i;
-                   xmlNsPtr ns, ret;
-                   
-                   for (i = 0; i < ctxt->templ->inheritedNsNr; i++) {
-                       const xmlChar *URI = NULL;
-                       xsltStylesheetPtr style;
-
-                       ns = ctxt->templ->inheritedNs[i];
-                       /*
-                       * Apply namespace aliasing.
-                       *
-                       * TODO: Compute the effective value of namespace
-                       *  aliases at compilation-time in order to avoid
-                       *  the lookup in the import-tree here.
-                       */
-                       style = ctxt->style;
-                       while (style != NULL) {
-                           if (style->nsAliases != NULL)
-                               URI = (const xmlChar *) 
-                                   xmlHashLookup(style->nsAliases, ns->href);
-                           if (URI != NULL)
-                               break;
-                           
-                           style = xsltNextImport(style);
-                       }
-                       if (URI == UNDEFINED_DEFAULT_NS) {
-                           xmlNsPtr defaultNs;
-
-                           defaultNs = xmlSearchNs(cur->doc, cur, NULL);
-                           if (defaultNs == NULL) {
-                               /*
-                               * TODO: Should not happen; i.e., it is
-                               *  an error at compilation-time if there's
-                               *  no default namespace in scope if
-                               *  "#default" is used.
-                               */
-                               continue;
-                           } else
-                               URI = defaultNs->href;
-                       }
-                       
-                       if (URI == NULL) {
-                           /*
-                           * There was no matching namespace-alias, so
-                           * just create a matching ns-decl if not
-                           * already in scope.
-                           */
-                           ret = xmlSearchNs(copy->doc, copy, ns->prefix);
-                           if ((ret == NULL) ||
-                               (!xmlStrEqual(ret->href, ns->href)))
-                               xmlNewNs(copy, ns->href, ns->prefix);
-                       } else if (!xmlStrEqual(URI, XSLT_NAMESPACE)) {
-                           ret = xmlSearchNs(copy->doc, copy, ns->prefix);
-                           if ((ret == NULL) ||
-                               (!xmlStrEqual(ret->href, URI))) {
-                               /*
-                               * Here we create a namespace
-                               * declaration with the literal namespace
-                               * prefix and with the target namespace name.
-                               * TODO: We should consider to fix this and
-                               *  use the *target* namespace prefix, not the
-                               *  literal one (see bug #341325).
-                               */
-                               xmlNewNs(copy, URI, ns->prefix);
-                           }
-                       }
-                   }
-                   if (copy->ns != NULL) {
-                       /*
-                       * Fix the node namespace if needed
-                       */
-                       copy->ns = xsltGetNamespace(ctxt, copy, copy->ns, copy);
-                   }
-               }
-#endif
            } else if (IS_XSLT_ELEM_FAST(cur)) {
                /*
                * XSLT instructions
@@ -2512,8 +2332,8 @@ xsltApplyOneTemplateInt(xsltTransformContextPtr ctxt, xmlNodePtr node,
                     ctxt->insert = insert;
                     if (!xsltApplyFallbacks(ctxt, node, cur)) {
                         xsltGenericError(xsltGenericErrorContext,
-                                         "xsltApplyOneTemplate: %s was not compiled\n",
-                                         cur->name);
+                           "xsltApplyOneTemplate: %s was not compiled\n",
+                           cur->name);
                     }
                     ctxt->insert = oldInsert;
                 }
@@ -2547,8 +2367,8 @@ xsltApplyOneTemplateInt(xsltTransformContextPtr ctxt, xmlNodePtr node,
                 xsltMessage(ctxt, node, cur);
             } else {
                 xsltGenericError(xsltGenericErrorContext,
-                                 "xsltApplyOneTemplate: problem with xsl:%s\n",
-                                 cur->name);
+                   "xsltApplyOneTemplate: problem with xsl:%s\n",
+                   cur->name);
             }
             goto skip_children;
         } else if ((cur->type == XML_TEXT_NODE) ||
@@ -2635,15 +2455,8 @@ xsltApplyOneTemplateInt(xsltTransformContextPtr ctxt, xmlNodePtr node,
                              "xsltApplyOneTemplate: copy node %s\n",
                              cur->name));
 #endif
-            if ((copy = xsltCopyNode(ctxt, cur, insert)) == NULL)
-               goto error;
-            /*
-             * all the attributes are directly inherited
-             */
-            if (cur->properties != NULL) {
-                xsltAttrListTemplateProcess(ctxt, copy,
-                                           cur->properties);
-            }
+            if ((copy = xsltShallowCopyElem(ctxt, cur, insert, 1)) == NULL)
+               goto error;            
             /*
              * Add extra namespaces inherited from the current template
              * if we are in the first level children and this is a
@@ -2657,36 +2470,36 @@ xsltApplyOneTemplateInt(xsltTransformContextPtr ctxt, xmlNodePtr node,
                 for (i = 0; i < ctxt->templ->inheritedNsNr; i++) {
                    const xmlChar *URI = NULL;
                    xsltStylesheetPtr style;
-                    ns = ctxt->templ->inheritedNs[i];
+                    ns = ctxt->templ->inheritedNs[i];              
+                   
+                   /* Note that the XSLT namespace was already excluded
+                   * in xsltGetInheritedNsList().
+                   */
+#if 0
+                   if (xmlStrEqual(ns->href, XSLT_NAMESPACE))
+                       continue;
+#endif
                    style = ctxt->style;
                    while (style != NULL) {
-                     if (style->nsAliases != NULL)
-                       URI = (const xmlChar *) 
-                         xmlHashLookup(style->nsAliases, ns->href);
-                     if (URI != NULL)
-                       break;
-                     
-                     style = xsltNextImport(style);
-                   }
-                                   
-                   if (URI == UNDEFINED_DEFAULT_NS) {
-                     xmlNsPtr dflt;
-                     dflt = xmlSearchNs(cur->doc, cur, NULL);
-                     if (dflt == NULL)
-                       continue;
-                     else
-                       URI = dflt->href;
+                       if (style->nsAliases != NULL)
+                           URI = (const xmlChar *) 
+                               xmlHashLookup(style->nsAliases, ns->href);
+                       if (URI != NULL)
+                           break;
+                       
+                       style = xsltNextImport(style);
                    }
-
-                   if (URI == NULL) {
-                     ret = xmlSearchNs(copy->doc, copy, ns->prefix);
-                     if ((ret == NULL) ||
-                         (!xmlStrEqual(ret->href, ns->href)))
-                       xmlNewNs(copy, ns->href, ns->prefix);
-                   } else if (!xmlStrEqual(URI, XSLT_NAMESPACE)) {
-                     ret = xmlSearchNs(copy->doc, copy, ns->prefix);
-                     if ((ret == NULL) ||
-                         (!xmlStrEqual(ret->href, URI)))
+                   if (URI == UNDEFINED_DEFAULT_NS)
+                       continue;
+                   if (URI == NULL)
+                       URI = ns->href;
+                   /*
+                   * TODO: The following will still be buggy for the
+                   * non-refactored code.
+                   */
+                   ret = xmlSearchNs(copy->doc, copy, ns->prefix);
+                   if ((ret == NULL) || (!xmlStrEqual(ret->href, URI)))
+                   {
                        xmlNewNs(copy, URI, ns->prefix);
                    }
                 }
@@ -2694,9 +2507,15 @@ xsltApplyOneTemplateInt(xsltTransformContextPtr ctxt, xmlNodePtr node,
                    /*
                     * Fix the node namespace if needed
                     */
-                   copy->ns = xsltGetNamespace(ctxt, copy, copy->ns, copy);
+                   copy->ns = xsltGetNamespace(ctxt, cur, copy->ns, copy);
                }
             }
+           /*
+             * all the attributes are directly inherited
+             */
+            if (cur->properties != NULL) {
+                xsltAttrListTemplateProcess(ctxt, copy, cur->properties);
+            }
         }
 #endif /* else of XSLT_REFACTORED */
 
@@ -3334,16 +3153,17 @@ xsltSort(xsltTransformContextPtr ctxt,
 
 /**
  * xsltCopy:
- * @ctxt:  a XSLT process context
- * @node:  the node in the source tree.
- * @inst:  the xslt copy node
- * @comp:  precomputed information
+ * @ctxt:  an XSLT process context
+ * @node:  the node in the source tree
+ * @inst:  the element node of the XSLT-copy instruction
+ * @comp:  computed information of the XSLT-copy instruction
  *
- * Execute the xsl:copy instruction on the source node.
+ * Execute the XSLT-copy instruction on the source node.
  */
 void
 xsltCopy(xsltTransformContextPtr ctxt, xmlNodePtr node,
-                  xmlNodePtr inst, xsltStylePreCompPtr castedComp) {
+        xmlNodePtr inst, xsltStylePreCompPtr castedComp)
+{
 #ifdef XSLT_REFACTORED
     xsltStyleItemCopyPtr comp = (xsltStyleItemCopyPtr) castedComp;
 #else
@@ -3377,8 +3197,8 @@ xsltCopy(xsltTransformContextPtr ctxt, xmlNodePtr node,
                break;
            case XML_ELEMENT_NODE:
                /*
-               * NOTE: The "fake" is a doc-node, not an element node.
-               * OLD:
+               * REVISIT NOTE: The "fake" is a doc-node, not an element node.
+               * REMOVED:
                *   if (xmlStrEqual(node->name, BAD_CAST " fake node libxslt"))
                *    return;
                */              
@@ -3387,7 +3207,7 @@ xsltCopy(xsltTransformContextPtr ctxt, xmlNodePtr node,
                XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
                                 "xsltCopy: node %s\n", node->name));
 #endif
-               copy = xsltCopyNode(ctxt, node, ctxt->insert);
+               copy = xsltShallowCopyElem(ctxt, node, ctxt->insert, 0);
                ctxt->insert = copy;
                if (comp->use != NULL) {
                    xsltApplyAttributeSet(ctxt, node, inst, comp->use);
@@ -3398,62 +3218,13 @@ xsltCopy(xsltTransformContextPtr ctxt, xmlNodePtr node,
                XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
                                 "xsltCopy: attribute %s\n", node->name));
 #endif
-               if (ctxt->insert->type == XML_ELEMENT_NODE) {
-                   xmlAttrPtr attr = (xmlAttrPtr) node, ret = NULL, cur;
-
-                   if (attr->ns != NULL) {
-                       if (!xmlStrEqual(attr->ns->href, XSLT_NAMESPACE)) {
-                           ret = xmlCopyProp(ctxt->insert, attr);
-                           ret->ns = xsltGetNamespace(ctxt, node, attr->ns,
-                                                      ctxt->insert);
-                       } 
-                   } else
-                       ret = xmlCopyProp(ctxt->insert, attr);
-
-                   if (ret != NULL) {
-                       cur = ctxt->insert->properties;
-                       if (cur != NULL) {
-                           /*
-                            * Avoid duplicates and insert at the end
-                            * of the attribute list
-                            */
-                           while (cur->next != NULL) {
-                               if ((xmlStrEqual(cur->name, ret->name)) &&
-                                    (((cur->ns == NULL) && (ret->ns == NULL)) ||
-                                    ((cur->ns != NULL) && (ret->ns != NULL) &&
-                                     (xmlStrEqual(cur->ns->href,
-                                                  ret->ns->href))))) {
-                                   xmlFreeProp(ret);
-                                   return;
-                               }
-                               cur = cur->next;
-                           }
-                           if ((xmlStrEqual(cur->name, ret->name)) &&
-                               (((cur->ns == NULL) && (ret->ns == NULL)) ||
-                                ((cur->ns != NULL) && (ret->ns != NULL) &&
-                                 (xmlStrEqual(cur->ns->href,
-                                              ret->ns->href))))) {
-                               xmlNodePtr tmp;
-
-                               /*
-                                * Attribute already exists,
-                                * update it with the new value
-                                */
-                               tmp = cur->children;
-                               cur->children = ret->children;
-                               ret->children = tmp;
-                               tmp = cur->last;
-                               cur->last = ret->last;
-                               ret->last = tmp;
-                               xmlFreeProp(ret);
-                               return;
-                           }
-                           cur->next = ret;
-                           ret->prev = cur;
-                       } else
-                           ctxt->insert->properties = ret;
-                   }
-               }
+               /*
+               * REVISIT: We could also raise an error if the parent is not
+               * an element node.
+               * OPTIMIZE TODO: Can we set the value/children of the
+               * attribute without an intermediate copy of the string value?
+               */
+               xsltShallowCopyAttr(ctxt, inst, ctxt->insert, (xmlAttrPtr) node);               
                break;
            }
            case XML_PI_NODE:
@@ -3477,8 +3248,8 @@ xsltCopy(xsltTransformContextPtr ctxt, xmlNodePtr node,
 #ifdef WITH_XSLT_DEBUG_PROCESS
                XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
                                 "xsltCopy: namespace declaration\n"));
-#endif
-                xsltCopyNamespace(ctxt, ctxt->insert, (xmlNsPtr)node);
+#endif         
+               xsltShallowCopyNsNode(ctxt, inst, ctxt->insert, (xmlNsPtr)node);                     
                break;
            default:
                break;
@@ -3553,20 +3324,20 @@ xsltElement(xsltTransformContextPtr ctxt, xmlNodePtr node,
 #else
     xsltStylePreCompPtr comp = castedComp;
 #endif
-    xmlChar *prop = NULL, *attributes = NULL, *namespace;
-    const xmlChar *name;
-    const xmlChar *prefix;
-    xmlNsPtr ns = NULL, oldns = NULL;
+    xmlChar *prop = NULL;
+    const xmlChar *name, *prefix = NULL, *nsName = NULL;    
     xmlNodePtr copy;
     xmlNodePtr oldInsert;
-    int generateDefault = 0;
-
 
     if (ctxt->insert == NULL)
        return;
-    if (!comp->has_name) {
-       return;
-    }
+
+    /* 
+    * A comp->has_name == 0 indicates that we need to skip this instruction,
+    * since it was evaluated to be invalid already during compilation.
+    */
+    if (!comp->has_name)
+        return;
 
     /*
      * stack and saves
@@ -3574,24 +3345,42 @@ xsltElement(xsltTransformContextPtr ctxt, xmlNodePtr node,
     oldInsert = ctxt->insert;
 
     if (comp->name == NULL) {
-       prop = xsltEvalAttrValueTemplate(ctxt, inst,
-                     (const xmlChar *)"name", NULL);
-       if (prop == NULL) {
-           xsltTransformError(ctxt, NULL, inst,
-                "xsl:element : name is missing\n");
-           return;
-       }
+       /* TODO: fix attr acquisition wrt to the XSLT namespace */
+        prop = xsltEvalAttrValueTemplate(ctxt, inst,
+           (const xmlChar *) "name", XSLT_NAMESPACE);
+        if (prop == NULL) {
+            xsltTransformError(ctxt, NULL, inst,
+               "xsl:element: The attribute 'name' is missing.\n");
+            goto error;
+        }
        if (xmlValidateQName(prop, 0)) {
            xsltTransformError(ctxt, NULL, inst,
-                   "xsl:element : invalid name\n");
-           /* we fall through to catch any other errors if possible */
+               "xsl:element: The effective name '%s' is not a "
+               "valid QName.\n", prop);
+           /* we fall through to catch any further errors, if possible */
        }
        name = xsltSplitQName(ctxt->dict, prop, &prefix);
        xmlFree(prop);
+       if ((prefix != NULL) &&
+           (!xmlStrncasecmp(prefix, (xmlChar *)"xml", 3)))
+       {
+           /*
+           * TODO: Should we really disallow an "xml" prefix?
+           */
+           goto error;
+       }
     } else {
+       /*
+       * The "name" value was static.
+       */
+#ifdef XSLT_REFACTORED
+       prefix = comp->nsPrefix;
+       name = comp->name;
+#else  
        name = xsltSplitQName(ctxt->dict, comp->name, &prefix);
+#endif
     }
-
+    
     /*
      * Create the new element
      */
@@ -3605,79 +3394,105 @@ xsltElement(xsltTransformContextPtr ctxt, xmlNodePtr node,
            "xsl:element : creation of %s failed\n", name);
        return;
     }
-    xmlAddChild(ctxt->insert, copy);
-    ctxt->insert = copy;
+    xmlAddChild(ctxt->insert, copy);    
 
-    if ((comp->ns == NULL) && (comp->has_ns)) {
-       namespace = xsltEvalAttrValueTemplate(ctxt, inst,
-               (const xmlChar *)"namespace", NULL);
-       if (namespace != NULL) {
-           ns = xsltGetSpecialNamespace(ctxt, inst, namespace, prefix,
-                                        ctxt->insert);
-           xmlFree(namespace);
-       }
-    } else if ((comp->ns != NULL) && (prefix == NULL) && (comp->has_ns)) {
-       generateDefault = 1;
-    } else if (comp->ns != NULL) {
-       ns = xsltGetSpecialNamespace(ctxt, inst, comp->ns, prefix,
-                                    ctxt->insert);
-    }
-    if ((ns == NULL) && (prefix != NULL)) {
-       if (!xmlStrncasecmp(prefix, (xmlChar *)"xml", 3)) {
-#ifdef WITH_XSLT_DEBUG_PARSING
-           xsltGenericDebug(xsltGenericDebugContext,
-                "xsltElement: xml prefix forbidden\n");
-#endif
-           return;
-       }
-       oldns = xmlSearchNs(inst->doc, inst, prefix);
-       if (oldns == NULL) {
-           xsltTransformError(ctxt, NULL, inst,
-               "xsl:element : no namespace bound to prefix %s\n", prefix);
+    /*
+    * Namespace
+    * ---------
+    */
+    if (comp->has_ns) {         
+       if (comp->ns != NULL) {
+           /*
+           * No AVT; just plain text for the namespace name.
+           */
+           if (comp->ns[0] != 0)
+               nsName = comp->ns;
        } else {
-           ns = xsltGetNamespace(ctxt, inst, oldns, ctxt->insert);
-       }
+           xmlChar *tmpNsName;
+           /*
+           * Eval the AVT.
+           */
+           /* TODO: check attr acquisition wrt to the XSLT namespace */
+           tmpNsName = xsltEvalAttrValueTemplate(ctxt, inst,
+               (const xmlChar *) "namespace", XSLT_NAMESPACE); 
+           /*
+           * SPEC XSLT 1.0:
+           *  "If the string is empty, then the expanded-name of the
+           *  attribute has a null namespace URI."
+           */
+           if ((tmpNsName != NULL) && (tmpNsName[0] != 0))
+               nsName = xmlDictLookup(ctxt->dict, BAD_CAST tmpNsName, -1);
+           xmlFree(tmpNsName);         
+       };          
+    } else {
+       xmlNsPtr ns;
+       /*
+       * SPEC XSLT 1.0:
+       *  "If the namespace attribute is not present, then the QName is
+       *  expanded into an expanded-name using the namespace declarations
+       *  in effect for the xsl:element element, including any default
+       *  namespace declaration.
+       */      
+       ns = xmlSearchNs(inst->doc, inst, prefix);
+       if (ns == NULL) {
+           /*
+           * TODO: Check this in the compilation layer in case it's a
+           * static value.
+           */
+           if (prefix != NULL) {
+               xsltTransformError(ctxt, NULL, inst,
+                   "xsl:element: The QName '%s:%s' has no "
+                   "namespace binding in scope in the stylesheet; "
+                   "this is an error, since the namespace was not "
+                   "specified by the instruction itself.\n", prefix, name);
+           }
+       } else
+           nsName = ns->href;  
+    }
+    /*
+    * Find/create a matching ns-decl in the result tree.
+    */
+    if (nsName != NULL) {
+       copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, prefix, copy);
+    } else if ((copy->parent != NULL) &&
+       (copy->parent->type == XML_ELEMENT_NODE) &&
+       (copy->parent->ns != NULL))
+    {
+       /*
+       * "Undeclare" the default namespace.
+       */
+       xsltGetSpecialNamespace(ctxt, inst, NULL, NULL, copy);
     }
 
-    if (generateDefault == 1) {
-       xmlNsPtr defaultNs = NULL;
-
-       if ((oldInsert != NULL) && (oldInsert->type == XML_ELEMENT_NODE))
-           defaultNs = xmlSearchNs(oldInsert->doc, oldInsert, NULL);
-       if ((defaultNs == NULL) || (!xmlStrEqual(defaultNs->href, comp->ns))) {
-           ns = xmlNewNs(ctxt->insert, comp->ns, NULL);
-           ctxt->insert->ns = ns;
-       } else {
-           ctxt->insert->ns = defaultNs;
-       }
-    } else if ((ns == NULL) && (oldns != NULL)) {
-       /* very specific case xsltGetNamespace failed */
-        ns = xmlNewNs(ctxt->insert, oldns->href, oldns->prefix);
-       ctxt->insert->ns = ns;
-    } else
-        ctxt->insert->ns = ns;
-
+    ctxt->insert = copy;
 
     if (comp->has_use) {
        if (comp->use != NULL) {
            xsltApplyAttributeSet(ctxt, node, inst, comp->use);
        } else {
+           xmlChar *attrSets = NULL;
            /*
            * BUG TODO: use-attribute-sets is not a value template.
            *  use-attribute-sets = qnames
            */
-           attributes = xsltEvalAttrValueTemplate(ctxt, inst,
-                      (const xmlChar *)"use-attribute-sets", NULL);
-           if (attributes != NULL) {
-               xsltApplyAttributeSet(ctxt, node, inst, attributes);
-               xmlFree(attributes);
+           attrSets = xsltEvalAttrValueTemplate(ctxt, inst,
+               (const xmlChar *)"use-attribute-sets", NULL);
+           if (attrSets != NULL) {
+               xsltApplyAttributeSet(ctxt, node, inst, attrSets);
+               xmlFree(attrSets);
            }
        }
     }
-    
-    xsltApplyOneTemplateInt(ctxt, ctxt->node, inst->children, NULL, NULL, 0);
+    /*
+    * Instantiate the sequence constructor.
+    */
+    if (inst->children != NULL)
+       xsltApplyOneTemplateInt(ctxt, ctxt->node, inst->children,
+           NULL, NULL, 0);
 
+error:
     ctxt->insert = oldInsert;
+    return;    
 }
 
 
@@ -3857,7 +3672,7 @@ xsltCopyOf(xsltTransformContextPtr ctxt, xmlNodePtr node,
 #ifdef XSLT_REFACTORED
     if (comp->inScopeNs != NULL) {
        ctxt->xpathCtxt->namespaces = comp->inScopeNs->list;
-       ctxt->xpathCtxt->nsNr = comp->inScopeNs->number;
+       ctxt->xpathCtxt->nsNr = comp->inScopeNs->xpathNumber;
     } else {
        ctxt->xpathCtxt->namespaces = NULL;
        ctxt->xpathCtxt->nsNr = 0;
@@ -3902,17 +3717,20 @@ xsltCopyOf(xsltTransformContextPtr ctxt, xmlNodePtr node,
                    if ((cur->type == XML_DOCUMENT_NODE) ||
                        (cur->type == XML_HTML_DOCUMENT_NODE))
                    {
-                       xsltCopyTreeList(ctxt, cur->children, ctxt->insert, 0);
+                       xsltCopyTreeList(ctxt, inst,
+                           cur->children, ctxt->insert, 0, 0);
                    } else if (cur->type == XML_ATTRIBUTE_NODE) {
-                       xsltCopyProp(ctxt, ctxt->insert, (xmlAttrPtr) cur);
+                       xsltShallowCopyAttr(ctxt, inst,
+                           ctxt->insert, (xmlAttrPtr) cur);
                    } else {
-                       xsltCopyTree(ctxt, cur, ctxt->insert, 0);
+                       xsltCopyTreeInternal(ctxt, inst,
+                           cur, ctxt->insert, 0, 0);
                    }
                }
            }
        } else if (res->type == XPATH_XSLT_TREE) {
            /*
-           * Result tree fragment
+           * Result tree fragment (e.g. via <xsl:variable ...><foo/></xsl:variable>)
            * --------------------
            */
 #ifdef WITH_XSLT_DEBUG_PROCESS
@@ -3927,8 +3745,8 @@ xsltCopyOf(xsltTransformContextPtr ctxt, xmlNodePtr node,
                (list->nodeTab[0] != NULL) &&
                (IS_XSLT_REAL_NODE(list->nodeTab[0])))
            {
-               xsltCopyTreeList(ctxt, list->nodeTab[0]->children,
-                                ctxt->insert, 0);
+               xsltCopyTreeList(ctxt, inst,
+                   list->nodeTab[0]->children, ctxt->insert, 0, 0);
            }
        } else {
            /* Convert to a string. */
@@ -3995,7 +3813,7 @@ xsltValueOf(xsltTransformContextPtr ctxt, xmlNodePtr node,
 #ifdef XSLT_REFACTORED
     if (comp->inScopeNs != NULL) {
        ctxt->xpathCtxt->namespaces = comp->inScopeNs->list;
-       ctxt->xpathCtxt->nsNr = comp->inScopeNs->number;
+       ctxt->xpathCtxt->nsNr = comp->inScopeNs->xpathNumber;
     } else {
        ctxt->xpathCtxt->namespaces = NULL;
        ctxt->xpathCtxt->nsNr = 0;
@@ -4279,7 +4097,7 @@ xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node,
 #ifdef XSLT_REFACTORED
        if (comp->inScopeNs != NULL) {
            ctxt->xpathCtxt->namespaces = comp->inScopeNs->list;
-           ctxt->xpathCtxt->nsNr = comp->inScopeNs->number;
+           ctxt->xpathCtxt->nsNr = comp->inScopeNs->xpathNumber;
        } else {
            ctxt->xpathCtxt->namespaces = NULL;
            ctxt->xpathCtxt->nsNr = 0;
@@ -4618,7 +4436,7 @@ xsltChoose(xsltTransformContextPtr ctxt, xmlNodePtr node,
 #ifdef XSLT_REFACTORED
        if (wcomp->inScopeNs != NULL) {
            ctxt->xpathCtxt->namespaces = wcomp->inScopeNs->list;
-           ctxt->xpathCtxt->nsNr = wcomp->inScopeNs->number;
+           ctxt->xpathCtxt->nsNr = wcomp->inScopeNs->xpathNumber;
        } else {
            ctxt->xpathCtxt->namespaces = NULL;
            ctxt->xpathCtxt->nsNr = 0;
@@ -4745,7 +4563,7 @@ xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr node,
 #ifdef XSLT_REFACTORED
     if (comp->inScopeNs != NULL) {
        ctxt->xpathCtxt->namespaces = comp->inScopeNs->list;
-       ctxt->xpathCtxt->nsNr = comp->inScopeNs->number;
+       ctxt->xpathCtxt->nsNr = comp->inScopeNs->xpathNumber;
     } else {
        ctxt->xpathCtxt->namespaces = NULL;
        ctxt->xpathCtxt->nsNr = 0;
@@ -4754,6 +4572,10 @@ xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr node,
     ctxt->xpathCtxt->namespaces = comp->nsList;
     ctxt->xpathCtxt->nsNr = comp->nsNr;
 #endif
+    /*
+    * OPTIMIZE TODO: Use a specialized function, which returns only
+    *  true/false.
+    */
     res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);
     ctxt->xpathCtxt->contextSize = oldContextSize;
     ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
@@ -4840,7 +4662,7 @@ xsltForEach(xsltTransformContextPtr ctxt, xmlNodePtr node,
 #ifdef XSLT_REFACTORED
     if (comp->inScopeNs != NULL) {
        ctxt->xpathCtxt->namespaces = comp->inScopeNs->list;
-       ctxt->xpathCtxt->nsNr = comp->inScopeNs->number;
+       ctxt->xpathCtxt->nsNr = comp->inScopeNs->xpathNumber;
     } else {
        ctxt->xpathCtxt->namespaces = NULL;
        ctxt->xpathCtxt->nsNr = 0;
index 93635b4..124f02a 100644 (file)
@@ -481,7 +481,7 @@ xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr elem,
 #ifdef XSLT_REFACTORED
            if (precomp->inScopeNs != NULL) {
                ctxt->xpathCtxt->namespaces = precomp->inScopeNs->list;
-               ctxt->xpathCtxt->nsNr = precomp->inScopeNs->number;
+               ctxt->xpathCtxt->nsNr = precomp->inScopeNs->xpathNumber;
            } else {
                ctxt->xpathCtxt->namespaces = NULL;
                ctxt->xpathCtxt->nsNr = 0;
@@ -650,7 +650,7 @@ xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt)
 #ifdef XSLT_REFACTORED
            if (precomp->inScopeNs != NULL) {
                ctxt->xpathCtxt->namespaces = precomp->inScopeNs->list;
-               ctxt->xpathCtxt->nsNr = precomp->inScopeNs->number;
+               ctxt->xpathCtxt->nsNr = precomp->inScopeNs->xpathNumber;
            } else {
                ctxt->xpathCtxt->namespaces = NULL;
                ctxt->xpathCtxt->nsNr = 0;
index a643d0a..96141c6 100644 (file)
@@ -75,6 +75,12 @@ const xmlChar *xsltLiteralResultMarker =
 */
 const xmlChar *xsltXSLTTextMarker = (const xmlChar *) "XSLT Text Element";
 
+/*
+* xsltXSLTAttrMarker:
+* Marker for XSLT attribute on Literal Result Elements.
+*/
+const xmlChar *xsltXSLTAttrMarker = (const xmlChar *) "LRE XSLT Attr";
+
 #endif
 
 /*
@@ -1151,6 +1157,9 @@ xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur)
             xmlFree(style->methodURI);
         style->methodURI = NULL;
 
+       /*
+       * TODO: Don't use xsltGetQNameURI().
+       */
        URI = xsltGetQNameURI(cur, &prop);
        if (prop == NULL) {
            if (style != NULL) style->errors++;
@@ -1260,6 +1269,9 @@ xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur)
                } else {
                    const xmlChar *URI;
 
+                   /*
+                   * TODO: Don't use xsltGetQNameURI().
+                   */
                    URI = xsltGetQNameURI(cur, &element);
                    if (element == NULL) {
                        /*
@@ -1470,6 +1482,9 @@ xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
            } else {
                const xmlChar *URI;
 
+               /*
+               * TODO: Don't use xsltGetQNameURI().
+               */
                 URI = xsltGetQNameURI(cur, &element);
 
                xmlHashAddEntry2(style->stripSpaces, element, URI,
@@ -1606,6 +1621,9 @@ xsltParseStylesheetStripSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
            } else {
                const xmlChar *URI;
 
+               /*
+               * TODO: Don't use xsltGetQNameURI().
+               */
                 URI = xsltGetQNameURI(cur, &element);
 
                xmlHashAddEntry2(style->stripSpaces, element, URI,
@@ -1994,7 +2012,7 @@ xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt,
     extElemNs = cctxt->inode->extElemNs;
     exclResultNs = cctxt->inode->exclResultNs;
 
-    for (i = 0; i < item->inScopeNs->number; i++) {
+    for (i = 0; i < item->inScopeNs->totalNumber; i++) {
        ns = item->inScopeNs->list[i];
        /*
        * Skip namespaces designated as excluded namespaces
@@ -2064,7 +2082,14 @@ xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt,
                    * Recognized as an namespace alias; convert it to
                    * the target namespace.
                    */
-                   ns = alias->literalNs;
+                   if (alias->targetNs != NULL)
+                       ns = alias->literalNs;
+                   else {
+                       /*
+                       * The target is the NULL namespace.
+                       */
+                       goto skip_ns;
+                   }
                    break;
                }
                alias = alias->next;
@@ -2354,7 +2379,8 @@ static xsltNsListContainerPtr
 xsltCompilerBuildInScopeNsList(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
 {
     xsltNsListContainerPtr nsi = NULL;
-    xmlNsPtr *list = NULL;
+    xmlNsPtr *list = NULL, ns;
+    int i, maxns = 5;
     /*
     * Create a new ns-list for this position in the node-tree.
     * xmlGetNsList() will return NULL, if there are no ns-decls in the
@@ -2362,26 +2388,75 @@ xsltCompilerBuildInScopeNsList(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
     * to the resulting list; the XPath module handles the XML namespace
     * internally.
     */
-    list = xmlGetNsList(node->doc, node);
-    if (list == NULL)
+    while (node != NULL) {
+        if (node->type == XML_ELEMENT_NODE) {
+            ns = node->nsDef;
+            while (ns != NULL) {
+                if (nsi == NULL) {
+                   nsi = (xsltNsListContainerPtr)
+                       xmlMalloc(sizeof(xsltNsListContainer));
+                   if (nsi == NULL) {
+                       xsltTransformError(NULL, cctxt->style, NULL,
+                           "xsltCompilerBuildInScopeNsList: "
+                           "malloc failed!\n");
+                       goto internal_err;
+                   }
+                   memset(nsi, 0, sizeof(xsltNsListContainer));
+                    nsi->list =
+                        (xmlNsPtr *) xmlMalloc(maxns * sizeof(xmlNsPtr));
+                    if (nsi->list == NULL) {
+                       xsltTransformError(NULL, cctxt->style, NULL,
+                           "xsltCompilerBuildInScopeNsList: "
+                           "malloc failed!\n");
+                       goto internal_err;
+                    }
+                    nsi->list[0] = NULL;
+                }
+               /*
+               * Skip shadowed namespace bindings.
+               */
+                for (i = 0; i < nsi->totalNumber; i++) {
+                    if ((ns->prefix == nsi->list[i]->prefix) ||
+                        (xmlStrEqual(ns->prefix, nsi->list[i]->prefix)))
+                   break;
+                }
+                if (i >= nsi->totalNumber) {
+                    if (nsi->totalNumber >= maxns) {
+                        maxns *= 2;
+                       nsi->list =
+                           (xmlNsPtr *) xmlRealloc(nsi->list,
+                               maxns * sizeof(xmlNsPtr));
+                        if (nsi->list == NULL) {
+                            xsltTransformError(NULL, cctxt->style, NULL,
+                               "xsltCompilerBuildInScopeNsList: "
+                               "realloc failed!\n");
+                               goto internal_err;
+                        }
+                    }
+                    nsi->list[nsi->totalNumber++] = ns;
+                    nsi->list[nsi->totalNumber] = NULL;
+                }
+
+                ns = ns->next;
+            }
+        }
+        node = node->parent;
+    }
+    if (nsi == NULL)
        return(NULL);
     /*
-    * Create the info-structure.
+    * Move the default namespace to last position.
     */
-    nsi = (xsltNsListContainerPtr) xmlMalloc(sizeof(xsltNsListContainer));
-    if (nsi == NULL) { 
-       xsltTransformError(NULL, cctxt->style, NULL,
-           "xsltCompilerBuildInScopeNsList: malloc failed.\n");
-       goto internal_err;
+    nsi->xpathNumber = nsi->totalNumber;
+    for (i = 0; i < nsi->totalNumber; i++) {
+       if (nsi->list[i]->prefix == NULL) {
+           ns = nsi->list[i];
+           nsi->list[i] = nsi->list[nsi->totalNumber-1];
+           nsi->list[nsi->totalNumber-1] = ns;
+           nsi->xpathNumber--;
+           break;
+       }
     }
-    memset(nsi, 0, sizeof(xsltNsListContainer));
-    nsi->list = list;
-    /*
-    * Eval the number of ns-decls; this is used to speed up
-    * XPath-context initialization.
-    */
-    while (list[nsi->number] != NULL)
-       nsi->number++;
     /*
     * Store the ns-list in the stylesheet.
     */
@@ -2551,19 +2626,36 @@ xsltParseExclResultPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
                            int instrCategory)
 {    
     xsltPointerListPtr list = NULL;
-    xmlChar *value = NULL;
+    xmlChar *value;
+    xmlAttrPtr attr;
 
     if ((cctxt == NULL) || (node == NULL))
        return(NULL);
-    
+
     if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
-       value = xmlGetNsProp(node, BAD_CAST "exclude-result-prefixes", NULL);
+       attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes", NULL);
     else
-       value = xmlGetNsProp(node, BAD_CAST "exclude-result-prefixes",
+       attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes",
            XSLT_NAMESPACE);
+    if (attr == NULL)  
+       return(def);
 
-    if (value == NULL)
+    if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
+       /*
+       * Mark the XSLT attr.
+       */
+       attr->psvi = (void *) xsltXSLTAttrMarker;
+    }
+
+    if ((attr->children != NULL) &&    
+       (attr->children->content != NULL))
+       value = attr->children->content;
+    else {
+       xsltTransformError(NULL, cctxt->style, node,
+           "Attribute 'exclude-result-prefixes': Invalid value.\n");
+       cctxt->style->errors++;
        return(def);
+    }        
 
     if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,
        BAD_CAST value) != 0)
@@ -2592,9 +2684,7 @@ xsltParseExclResultPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
     if (cctxt->inode != NULL)
        cctxt->inode->nsChanged = 1;
 
-exit:
-    if (value != NULL)
-       xmlFree(value);
+exit:    
     if (list != NULL)
        return(list);
     else
@@ -2632,6 +2722,13 @@ xsltParseExtElemPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
     if (attr == NULL)  
        return(def);
 
+    if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
+       /*
+       * Mark the XSLT attr.
+       */
+       attr->psvi = (void *) xsltXSLTAttrMarker;
+    }
+
     if ((attr->children != NULL) &&    
        (attr->children->content != NULL))
        value = attr->children->content;
@@ -2677,21 +2774,13 @@ xsltParseExtElemPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
     if (cctxt->inode != NULL)
        cctxt->inode->nsChanged = 1;
 
-exit:
-    if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
-       /*
-       * Remove the XSLT attribute from the literal result element.
-       */
-       xmlUnlinkNode((xmlNodePtr) attr);
-       xmlFreeProp(attr);
-    }
+exit:    
     if (list != NULL)
        return(list);
     else
        return(def);
 }
 
-
 /*
 * xsltParseAttrXSLTVersion:
 *
@@ -2722,6 +2811,8 @@ xsltParseAttrXSLTVersion(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
     if (attr == NULL)  
        return(0);
 
+    attr->psvi = (void *) xsltXSLTAttrMarker;
+
     if ((attr->children != NULL) &&    
        (attr->children->content != NULL))
        value = attr->children->content;
@@ -2758,35 +2849,13 @@ xsltParseAttrXSLTVersion(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
 
     if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
        /*
-       * Remove the XSLT attribute from the literal result element.
+       * Set a marker on XSLT attributes.
        */
-       xmlUnlinkNode((xmlNodePtr) attr);
-       xmlFreeProp(attr);
+       attr->psvi = (void *) xsltXSLTAttrMarker;
     }
     return(1);
 }
 
-#if 0
-static int
-xsltParseRemoveXSLTAttrs(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
-{
-    if (node->properties == NULL)
-       return(0);
-    else {
-       xmlAttrPtr tmpattr, attr = node->properties;
-       do {        
-           if (IS_XSLT_ATTR_FAST(attr)) {
-               tmpattr = attr;
-               attr = attr->next;
-               xmlUnlinkNode((xmlNodePtr) tmpattr);
-               xmlFreeProp(tmpattr);
-           } else
-               attr = attr->next;
-       } while (attr != NULL);
-    }
-}
-#endif
-
 static int
 xsltParsePreprocessStylesheetTree(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
 {
@@ -4358,6 +4427,7 @@ xsltParseSequenceConstructor(xsltCompilerCtxtPtr cctxt, xmlNodePtr cur)
                    cur->psvi = NULL;
                    cctxt->inode->category = XSLT_ELEMENT_CATEGORY_LRE;
                    if (cur->properties != NULL) {
+                       xmlAttrPtr attr = cur->properties;
                        /*
                        * Attribute "xsl:exclude-result-prefixes".
                        */
@@ -4371,24 +4441,35 @@ xsltParseSequenceConstructor(xsltCompilerCtxtPtr cctxt, xmlNodePtr cur)
                        xsltParseAttrXSLTVersion(cctxt, cur,
                            XSLT_ELEMENT_CATEGORY_LRE);
                        /*
-                       * Report invalid XSLT attributes.
+                       * Report invalid XSLT attributes.                       
+                       * For XSLT 1.0 only xsl:use-attribute-sets is allowed
+                       * next to xsl:version, xsl:exclude-result-prefixes and
+                       * xsl:extension-element-prefixes.
+                       *
+                       * Mark all XSLT attributes, in order to skip such
+                       * attributes when instantiating the LRE.
                        */
-                       if (cur->properties) {
-                           xmlAttrPtr attr = cur->properties;
-
-                           do {
-                               if (IS_XSLT_ATTR_FAST(attr) &&
-                                   (! xmlStrEqual(attr->name,
-                                       BAD_CAST "use-attribute-sets")))
+                       do {
+                           if ((attr->psvi != xsltXSLTAttrMarker) &&
+                               IS_XSLT_ATTR_FAST(attr))
+                           {                               
+                               if (! xmlStrEqual(attr->name,
+                                   BAD_CAST "use-attribute-sets"))
                                {                               
-                                   xsltTransformError(NULL, cctxt->style, cur,
+                                   xsltTransformError(NULL, cctxt->style,
+                                       cur,
                                        "Unknown XSLT attribute '%s'.\n",
-                                       attr->name);                            
-                                    cctxt->style->errors++;
+                                       attr->name);
+                                   cctxt->style->errors++;
+                               } else {
+                                   /*
+                                   * XSLT attr marker.
+                                   */
+                                   attr->psvi = (void *) xsltXSLTAttrMarker;
                                }
-                               attr = attr->next;
-                           } while (attr != NULL);                         
-                       }
+                           }
+                           attr = attr->next;
+                       } while (attr != NULL);
                    }
                    /*
                    * Create/reuse info for the literal result element.
@@ -4732,6 +4813,9 @@ xsltParseStylesheetKey(xsltStylesheetPtr style, xmlNodePtr key) {
     if (prop != NULL) {
         const xmlChar *URI;
 
+       /*
+       * TODO: Don't use xsltGetQNameURI().
+       */
        URI = xsltGetQNameURI(key, &prop);
        if (prop == NULL) {
            if (style != NULL) style->errors++;
@@ -4826,69 +4910,7 @@ xsltParseXSLTTemplate(xsltCompilerCtxtPtr cctxt, xmlNodePtr templNode) {
 
     templ->next = cctxt->style->templates;
     cctxt->style->templates = templ;
-    templ->style = cctxt->style;
-   
-
-    /*
-    * Get inherited namespaces.
-    */
-    if (cctxt->inode->inScopeNs != NULL) {
-       int i, j;
-       xmlNsPtr ns;
-       xsltPointerListPtr extElemNs = cctxt->inode->extElemNs;
-       xsltPointerListPtr exclResultNs = cctxt->inode->exclResultNs;
-       xsltNsListContainerPtr inScopeNs = cctxt->inode->inScopeNs;
-
-       for (i = 0; i < inScopeNs->number; i++) {
-           ns = inScopeNs->list[i];
-           /*
-           * Exclude the XSLT namespace.
-           */
-           if (xmlStrEqual(ns->href, XSLT_NAMESPACE))
-               goto skip_ns;
-           /*
-           * Exclude excluded result namespaces.
-           */
-           if (exclResultNs) {
-               for (j = 0; j < exclResultNs->number; j++)
-                   if (xmlStrEqual(ns->href, BAD_CAST exclResultNs->items[j]))
-                       goto skip_ns;           
-           }
-           /*
-           * Exclude extension-element namespaces.
-           */
-           if (extElemNs) {
-               for (j = 0; j < extElemNs->number; j++)
-                   if (xmlStrEqual(ns->href, BAD_CAST extElemNs->items[j]))
-                       goto skip_ns;
-           }
-           /*
-           * Add the xmlNs item.
-           */
-           if (templ->inheritedNs == NULL) {
-               templ->inheritedNs = (xmlNsPtr *) xmlMalloc(
-                   inScopeNs->number * sizeof(xmlNsPtr));
-               if (templ->inheritedNs == NULL) {
-                   xmlGenericError(xmlGenericErrorContext,
-                       "xsltGetInheritedNsList : out of memory!\n");
-                   cctxt->style->errors++;
-                   goto error;
-               }
-               memset(templ->inheritedNs, 0,
-                   inScopeNs->number * sizeof(xmlNsPtr));
-           }
-           templ->inheritedNs[templ->inheritedNsNr++] = ns;
-skip_ns:
-           {}
-       }       
-#ifdef WITH_XSLT_DEBUG_PARSING
-       if (templ->inheritedNsNr != 0) {
-           xsltGenericDebug(xsltGenericDebugContext,
-               "xsl:template has %d inherited namespaces\n",
-               templ->inheritedNsNr);
-       }
-#endif
-    }
+    templ->style = cctxt->style;  
 
     /*
     * Attribute "mode".
@@ -4900,6 +4922,8 @@ skip_ns:
        /*
        * TODO: We need a standardized function for extraction
        *  of namespace names and local names from QNames.
+       *  Don't use xsltGetQNameURI() as it cannot channeƶ
+       *  reports through the context.
        */
        modeURI = xsltGetQNameURI(templNode, &prop);
        if (prop == NULL) {
@@ -4949,6 +4973,9 @@ skip_ns:
         const xmlChar *nameURI;
        xsltTemplatePtr curTempl;
        
+       /*
+       * TODO: Don't use xsltGetQNameURI().
+       */
        nameURI = xsltGetQNameURI(templNode, &prop);
        if (prop == NULL) {
            cctxt->style->errors++;
@@ -5056,6 +5083,9 @@ xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) {
     if (prop != NULL) {
         const xmlChar *URI;
 
+       /*
+       * TODO: Don't use xsltGetQNameURI().
+       */
        URI = xsltGetQNameURI(template, &prop);
        if (prop == NULL) {
            if (style != NULL) style->errors++;
@@ -5092,6 +5122,9 @@ xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) {
         const xmlChar *URI;
        xsltTemplatePtr cur;
        
+       /*
+       * TODO: Don't use xsltGetQNameURI().
+       */
        URI = xsltGetQNameURI(template, &prop);
        if (prop == NULL) {
            if (style != NULL) style->errors++;
index e76f170..89c068b 100644 (file)
@@ -70,6 +70,9 @@ extern const xmlChar *xsltDocFragFake;
 /* ==================================================================== */
 
 #ifdef XSLT_REFACTORED
+
+extern const xmlChar *xsltXSLTAttrMarker;
+
 /* TODO: REMOVE: #define XSLT_REFACTORED_EXCLRESNS */
 
 /* TODO: REMOVE: #define XSLT_REFACTORED_NSALIAS */
@@ -80,7 +83,7 @@ extern const xmlChar *xsltDocFragFake;
  * Internal define to enable the pointer-comparison of
  * namespaces of XSLT elements. 
  */
-#define XSLT_REFACTORED_XSLT_NSCOMP
+/* #define XSLT_REFACTORED_XSLT_NSCOMP */
 
 /**
  * XSLT_REFACTORED_XPATHCOMP
@@ -466,7 +469,8 @@ typedef struct _xsltNsListContainer xsltNsListContainer;
 typedef xsltNsListContainer *xsltNsListContainerPtr;
 struct _xsltNsListContainer {
     xmlNsPtr *list;
-    int number;
+    int totalNumber;
+    int xpathNumber;    
 };
 
 /**
@@ -590,13 +594,13 @@ typedef xsltStyleItemElement *xsltStyleItemElementPtr;
 struct _xsltStyleItemElement {
     XSLT_ITEM_COMMON_FIELDS 
 
-    const xmlChar *use;                /* copy, element */
-    int      has_use;          /* copy, element */
-    const xmlChar *name;       /* element, attribute, pi */
-    int      has_name;         /* element, attribute, pi */
-    const xmlChar *ns;         /* element */
-    int      has_ns;           /* element */
-
+    const xmlChar *use;
+    int      has_use;
+    const xmlChar *name;    
+    int      has_name;
+    const xmlChar *ns;
+    const xmlChar *nsPrefix;
+    int      has_ns;
 };
 
 /**
@@ -614,10 +618,11 @@ typedef xsltStyleItemAttribute *xsltStyleItemAttributePtr;
 
 struct _xsltStyleItemAttribute {
     XSLT_ITEM_COMMON_FIELDS
-    const xmlChar *name;       /* element, attribute, pi */
-    int      has_name;         /* element, attribute, pi */
-    const xmlChar *ns;         /* element  attribute */
-    int      has_ns;           /* element  attribute */
+    const xmlChar *name;
+    int      has_name;
+    const xmlChar *ns;
+    const xmlChar *nsPrefix;
+    int      has_ns;
 };
 
 /**
@@ -689,7 +694,7 @@ typedef struct _xsltStyleItemApplyTemplates xsltStyleItemApplyTemplates;
 typedef xsltStyleItemApplyTemplates *xsltStyleItemApplyTemplatesPtr;
 
 struct _xsltStyleItemApplyTemplates {
-   XSLT_ITEM_COMMON_FIELDS
+    XSLT_ITEM_COMMON_FIELDS
 
     const xmlChar *mode;       /* apply-templates */
     const xmlChar *modeURI;    /* apply-templates */
index d9b094e..ed3aeb2 100644 (file)
@@ -995,7 +995,7 @@ xsltComputeSortResult(xsltTransformContextPtr ctxt, xmlNodePtr sort) {
 #ifdef XSLT_REFACTORED
        if (comp->inScopeNs != NULL) {
            ctxt->xpathCtxt->namespaces = comp->inScopeNs->list;
-           ctxt->xpathCtxt->nsNr = comp->inScopeNs->number;
+           ctxt->xpathCtxt->nsNr = comp->inScopeNs->xpathNumber;
        } else {
            ctxt->xpathCtxt->namespaces = NULL;
            ctxt->xpathCtxt->nsNr = 0;