Beispiel #1
0
void mxslt_transform_header(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst, xsltElemPreCompPtr comp) {
  mxslt_doc_t * document=mxslt_get_state()->document;
  char * header, * value;
  char * cur, * store;

#ifdef MXSLT_FALLBACK_WRAPAROUND 
  xmlNodePtr tmp, tofree;
#endif

  mxslt_doc_debug_print(document, MXSLT_DBG_LIBXML | MXSLT_DBG_DEBUG | MXSLT_DBG_VERBOSE0, 
		    "%s: <modxslt:header-set called\n", mxslt_debug_string(document->localfile));

    /* Check input parameters */
  if(ctxt == NULL || node == NULL || inst == NULL)
    return; 

    /* Check type is correct */
  if(inst->type != XML_ELEMENT_NODE)
    return;

    /* Verify we have some attribute */
  if(inst->properties == NULL || inst->properties->type != XML_ATTRIBUTE_NODE ||
     !inst->properties->children || inst->properties->children->type != XML_TEXT_NODE ||
     !inst->properties->children->content) {
    xsltTransformError(ctxt, ctxt->style, inst, "<modxslt:header-set name='... no valid attribute specifyed!");
    return;
  }

    /* Get attribute value */
  if(!xmlStrEqual(inst->properties->name, (xmlChar *)"name")) {
    xsltTransformError(ctxt, ctxt->style, inst, "<modxslt:header-set %s='... unknown attribute!", inst->properties->name);
    return;
  }

    /* Warn if we were provided more
     * attributes than expected */
  if(inst->properties->next) 
    xsltTransformError(ctxt, ctxt->style, inst, "<modxslt:header-set %s='... unknown additional attribute!", 
		       inst->properties->next->name);

  header=(char *)inst->properties->children->content;

#ifdef MXSLT_FALLBACK_WRAPAROUND 
    /* Ugly hack: is there a better way to do this? */
    /* Problem: for some reason, if there is a `fallback' node
     *   xsltApplyOneTemplate reports an error. I suspect the fact that
     *   precompiled info is missing for this node (precompilation
     *   stops at unknown node modxslt:header)... However, couldn't i
     *   find a better way to handle this. I believe it is a libxml
     *   bug (didn't get any answer when reported). */
  for(tmp=inst->children; tmp != NULL;) {
    if(tmp->name && xmlStrEqual(tmp->name, (xmlChar *)"fallback")) {
      tofree=tmp;
      tmp=tmp->next;
      xmlUnlinkNode(tofree);
      xmlFreeNode(tofree); 
    } else {
      tmp=tmp->next;
    }
  }
#endif 

    /* Look for text value */
  value=(char *)xsltEvalTemplateString(ctxt, node, inst);
  mxslt_doc_debug_print(document, MXSLT_DBG_LIBXML, "requesting header '%s' to be set to value '%s'\n", 
		    mxslt_debug_string(header), mxslt_debug_string(value));

    /* Shrink spaces in value, only if needed */
  if(!value)
    value="";
  else {
    if(xsltFindElemSpaceHandling(ctxt, inst) == 1) {
        /* Remove \n, \r, \t from output - probably the uglyest
	 * construct in the whole source */
      for(cur=store=value; *cur != '\0'; cur++)
        switch(*cur) { 
    	  case '\n':
          case '\r':
	  case '\t':
	  case ' ':
	    for(; *cur == ' ' || *cur == '\t' || *cur == '\n' || *cur == '\r'; cur++)
	      ;
	    *store++=' ';

	  default:
	    *store++=*cur;
	    break;
        }
      *store='\0';
    }
  }
  mxslt_doc_debug_print(document, MXSLT_DBG_LIBXML | MXSLT_DBG_DEBUG, "reply header '%s' has been shrinked to '%s'\n", 
		    mxslt_debug_string(header), mxslt_debug_string(value));

    /* Now, let's do it... */
    /* XXX: do we need to call xmlStringDecodeEntities? */
  document->header_set(header, value, document->header_data);

  xmlFree(value);

  return;
}
Beispiel #2
0
/**
 * xsltAttribute:
 * @ctxt:  a XSLT process context
 * @node:  the current node in the source tree
 * @inst:  the xsl:attribute element
 * @comp:  precomputed information
 *
 * Process the xslt attribute node on the source node
 */
void
xsltAttribute(xsltTransformContextPtr ctxt,
	      xmlNodePtr contextNode,
              xmlNodePtr inst,
	      xsltStylePreCompPtr castedComp)
{
#ifdef XSLT_REFACTORED
    xsltStyleItemAttributePtr comp =
	(xsltStyleItemAttributePtr) castedComp;
#else
    xsltStylePreCompPtr comp = castedComp;
#endif
    xmlNodePtr targetElem;
    xmlChar *prop = NULL;
    const xmlChar *name = NULL, *prefix = NULL, *nsName = NULL;
    xmlChar *value = NULL;
    xmlNsPtr ns = NULL;
    xmlAttrPtr attr;

    if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL) ||
        (inst->type != XML_ELEMENT_NODE) )
        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
    *  xsltGetNamespace(), but since both are not appropriate, we
    *  will process namespace lookup here to avoid adding yet another
    *  ns-lookup function to namespaces.c.
    */
    /*
    * SPEC XSLT 1.0: Error cases:
    * - Creating nodes other than text nodes during the instantiation of
    *   the content of the xsl:attribute element; implementations may
    *   either signal the error or ignore the offending nodes."
    */

    if (comp == NULL) {
        xsltTransformError(ctxt, NULL, inst,
	    "Internal error in xsltAttribute(): "
	    "The XSLT 'attribute' instruction was not compiled.\n");
        return;
    }
    /*
    * TODO: Shouldn't ctxt->insert == NULL be treated as an internal error?
    *   So report an internal error?
    */
    if (ctxt->insert == NULL)
        return;
    /*
    * SPEC XSLT 1.0:
    *  "Adding an attribute to a node that is not an element;
    *  implementations may either signal the error or ignore the attribute."
    *
    * TODO: I think we should signal such errors in the future, and maybe
    *  provide an option to ignore such errors.
    */
    targetElem = ctxt->insert;
    if (targetElem->type != XML_ELEMENT_NODE)
	return;

    /*
    * SPEC XSLT 1.0:
    * "Adding an attribute to an element after children have been added
    *  to it; implementations may either signal the error or ignore the
    *  attribute."
    *
    * TODO: We should decide whether not to report such errors or
    *  to ignore them; note that we *ignore* if the parent is not an
    *  element, but here we report an error.
    */
    if (targetElem->children != NULL) {
	/*
	* NOTE: Ah! This seems to be intended to support streamed
	*  result generation!.
	*/
        xsltTransformError(ctxt, NULL, inst,
	    "xsl:attribute: Cannot add attributes to an "
	    "element if children have been already added "
	    "to the element.\n");
        return;
    }

    /*
    * Process the name
    * ----------------
    */

#ifdef WITH_DEBUGGER
    if (ctxt->debugStatus != XSLT_DEBUG_NONE)
        xslHandleDebugger(inst, contextNode, NULL, ctxt);
#endif

    if (comp->name == NULL) {
	/* 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:attribute: The attribute 'name' is missing.\n");
            goto error;
        }
	if (xmlValidateQName(prop, 0)) {
	    xsltTransformError(ctxt, NULL, inst,
		"xsl:attribute: The effective name '%s' is not a "
		"valid QName.\n", prop);
	    /* we fall through to catch any further errors, if possible */
	}

	/*
	* Reject a name of "xmlns".
	*/
	if (xmlStrEqual(prop, BAD_CAST "xmlns")) {
            xsltTransformError(ctxt, NULL, inst,
                "xsl:attribute: The effective name 'xmlns' is not allowed.\n");
	    xmlFree(prop);
	    goto error;
	}

	name = xsltSplitQName(ctxt->dict, prop, &prefix);
	xmlFree(prop);
    } else {
	/*
	* The "name" value was static.
	*/
#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) {
	/*
	* 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 {
	    xmlChar *tmpNsName;
	    /*
	    * Eval the AVT.
	    */
	    /* TODO: check attr acquisition wrt to the XSLT namespace */
	    tmpNsName = xsltEvalAttrValueTemplate(ctxt, inst,
		(const xmlChar *) "namespace", XSLT_NAMESPACE);
	    /*
	    * This fixes bug #302020: The AVT might also evaluate to the
	    * empty string; this means that the empty string also indicates
	    * "no 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);
	}

        if (xmlStrEqual(nsName, BAD_CAST "http://www.w3.org/2000/xmlns/")) {
            xsltTransformError(ctxt, NULL, inst,
                "xsl:attribute: Namespace http://www.w3.org/2000/xmlns/ "
                "forbidden.\n");
            goto error;
        }
        if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
            prefix = BAD_CAST "xml";
        } else if (xmlStrEqual(prefix, BAD_CAST "xml")) {
            prefix = NULL;
        }
    } else if (prefix != NULL) {
	/*
	* 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:attribute element, *not* including any
	*  default namespace declaration."
	*/
	ns = xmlSearchNs(inst->doc, inst, prefix);
	if (ns == NULL) {
	    /*
	    * Note that this is treated as an error now (checked with
	    *  Saxon, Xalan-J and MSXML).
	    */
	    xsltTransformError(ctxt, NULL, inst,
		"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, name);
	} else
	    nsName = ns->href;
    }

    /*
    * 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 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
	* ns-decl, but just store it in the dummy-doc of the result
	* tree fragment.
	*/
	if (nsName != NULL) {
	    /*
	    * TODO: Get the doc of @targetElem.
	    */
	    ns = xsltTreeAcquireStoredNs(some doc, nsName, prefix);
	}
    }
#endif

    if (nsName != NULL) {
	/*
	* 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"
	*/
	/*
	* xsl:attribute can produce a scenario where the prefix is NULL,
	* so generate a prefix.
	*/
	if ((prefix == NULL) || xmlStrEqual(prefix, BAD_CAST "xmlns")) {
	    xmlChar *pref = xmlStrdup(BAD_CAST "ns_1");

	    ns = xsltGetSpecialNamespace(ctxt, inst, nsName, 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 for the generated attribute '{%s}%s'.\n",
		nsName, name);
	    goto error;
	}
    }
    /*
    * Construction of the value
    * -------------------------
    */
    if (inst->children == NULL) {
	/*
	* No content.
	* TODO: Do we need to put the empty string in ?
	*/
	attr = xmlSetNsProp(ctxt->insert, ns, name, (const xmlChar *) "");
    } else if ((inst->children->next == NULL) &&
	    ((inst->children->type == XML_TEXT_NODE) ||
	     (inst->children->type == XML_CDATA_SECTION_NODE)))
    {
	xmlNodePtr copyTxt;

	/*
	* xmlSetNsProp() will take care of duplicates.
	*/
	attr = xmlSetNsProp(ctxt->insert, ns, name, NULL);
	if (attr == NULL) /* TODO: report error ? */
	    goto error;
	/*
	* This was taken over from xsltCopyText() (transform.c).
	*/
	if (ctxt->internalized &&
	    (ctxt->insert->doc != NULL) &&
	    (ctxt->insert->doc->dict == ctxt->dict))
	{
	    copyTxt = xmlNewText(NULL);
	    if (copyTxt == NULL) /* TODO: report error */
		goto error;
	    /*
	    * This is a safe scenario where we don't need to lookup
	    * the dict.
	    */
	    copyTxt->content = inst->children->content;
	    /*
	    * Copy "disable-output-escaping" information.
	    * TODO: Does this have any effect for attribute values
	    *  anyway?
	    */
	    if (inst->children->name == xmlStringTextNoenc)
		copyTxt->name = xmlStringTextNoenc;
	} else {
	    /*
	    * Copy the value.
	    */
	    copyTxt = xmlNewText(inst->children->content);
	    if (copyTxt == NULL) /* TODO: report error */
		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;

        /*
         * since we create the attribute without content IDness must be
         * asserted as a second step
         */
        if ((copyTxt->content != NULL) &&
            (xmlIsID(attr->doc, attr->parent, attr)))
            xmlAddID(NULL, attr->doc, copyTxt->content, attr);
    } else {
	/*
	* The sequence constructor might be complex, so instantiate it.
	*/
	value = xsltEvalTemplateString(ctxt, contextNode, 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 *) "");
	}
    }

error:
    return;
}
/**
 * xsltAttributeInternal:
 * @ctxt:  a XSLT process context
 * @node:  the node in the source tree.
 * @inst:  the xsl:attribute element
 * @comp:  precomputed information
 * @fromAttributeSet:  the attribute comes from an attribute-set
 *
 * Process the xslt attribute node on the source node
 */
static void
xsltAttributeInternal(xsltTransformContextPtr ctxt, xmlNodePtr node,
                      xmlNodePtr inst,
		      xsltStylePreCompPtr castedComp,
                      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)
    */
#else
    xsltStylePreCompPtr comp = castedComp;
#endif
    xmlNodePtr targetElem;
    xmlChar *prop = NULL;    
    const xmlChar *name = NULL, *prefix = NULL, *nsName = NULL;
    xmlChar *value = NULL;
    xmlNsPtr ns = NULL;
    xmlAttrPtr attr;    

    if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
        return;
    /*
    * BIG NOTE: This previously used xsltGetSpecialNamespace() and
    *  xsltGetNamespace(), but since both are not appropriate, we
    *  will process namespace lookup here to avoid adding yet another
    *  ns-lookup function to namespaces.c.
    */
    /*
    * SPEC XSLT 1.0: Error cases:
    * - Creating nodes other than text nodes during the instantiation of
    *   the content of the xsl:attribute element; implementations may
    *   either signal the error or ignore the offending nodes."
    */

    if (comp == NULL) {
        xsltTransformError(ctxt, NULL, inst,
	    "Internal error in xsltAttributeInternal(): "
	    "The instruction was no compiled.\n");
        return;
    }    
    /*
    * TODO: Shouldn't ctxt->insert == NULL be treated as an internal error?
    *   So report an internal error?
    */
    if (ctxt->insert == NULL)
        return;    
    /*
    * SPEC XSLT 1.0:
    *  "Adding an attribute to a node that is not an element;
    *  implementations may either signal the error or ignore the attribute."
    *
    * TODO: I think we should signal such errors in the future, and maybe
    *  provide an option to ignore such errors.
    */
    targetElem = ctxt->insert;
    if (targetElem->type != XML_ELEMENT_NODE)
	return;
    
    /*
    * SPEC XSLT 1.0:
    * "Adding an attribute to an element after children have been added
    *  to it; implementations may either signal the error or ignore the
    *  attribute."
    *
    * TODO: We should decide whether not to report such errors or
    *  to ignore them; note that we *ignore* if the parent is not an
    *  element, but here we report an error.
    */
    if (targetElem->children != NULL) {
	/*
	* NOTE: Ah! This seems to be intended to support streamed
	*  result generation!.
	*/
        xsltTransformError(ctxt, NULL, inst,
	    "xsl:attribute: Cannot add attributes to an "
	    "element if children have been already added "
	    "to the element.\n");
        return;
    }

    /*
    * 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);
#endif

    if (comp->name == NULL) {
	/* 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:attribute: The attribute 'name' is missing.\n");
            goto error;
        }
	if (xmlValidateQName(prop, 0)) {
	    xsltTransformError(ctxt, NULL, inst,
		"xsl:attribute: 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);
    } else {
	name = xsltSplitQName(ctxt->dict, comp->name, &prefix);
    }

    if (!xmlStrncasecmp(prefix, (xmlChar *) "xmlns", 5)) {
#ifdef WITH_XSLT_DEBUG_PARSING
        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;
    }
    /*
    * Process namespace semantics
    * ---------------------------
    *
    * Evaluate the namespace name.
    */
    if (comp->has_ns) {	 
	if (comp->ns != NULL) {
	    if (comp->ns[0] != 0)
		nsName = comp->ns;
	} else {
	    xmlChar *tmpNsName;
	    /*
	    * Eval the AVT.
	    */
	    /* TODO: check attr acquisition wrt to the XSLT namespace */
	    tmpNsName = xsltEvalAttrValueTemplate(ctxt, inst,
		(const xmlChar *) "namespace", XSLT_NAMESPACE);	
	    /*
	    * This fixes bug #302020: The AVT might also evaluate to the 
	    * empty string; this means that the empty string also indicates
	    * "no 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 if (prefix != NULL) {
	/*
	* 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:attribute element, *not* including any
	*  default namespace declaration."
	*/	
	ns = xmlSearchNs(inst->doc, inst, prefix);
	if (ns == NULL) {
	    /*
	    * Note that this is treated as an error now (checked with
	    *  Saxon, Xalan-J and MSXML).
	    */
	    xsltTransformError(ctxt, NULL, inst,
		"xsl:attribute: The effective prefix '%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);
	} else
	    nsName = ns->href;	
    }

    if (fromAttributeSet) {
	/*
	* I think 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).
	*/
	attr = xmlHasNsProp(targetElem, name, nsName);
	if (attr != NULL)
	    return;
    }

    /*
    * 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?
	*
	* 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
	* ns-decl, but just store it in the dummy-doc of the result
	* tree fragment.
	*/
	if (nsName != NULL) {
	    ns = xsltTreeAcquireStoredNs(ctxt->document->doc, nsName,
		prefix);
	}
    }
#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;
	}
	/*
	* 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 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.
	*/
	{
	    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);
	}

namespace_finished:

	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",
		nsName, name);
	    /*
	    * TODO: Should we just stop here?
	    */
	}
    }
    /*
    * Construction of the value
    * -------------------------
    */
    if (inst->children == NULL) {
	/*
	* No content.
	* TODO: Do we need to put the empty string in ?
	*/
	attr = xmlSetNsProp(ctxt->insert, ns, name, (const xmlChar *) "");
    } else if ((inst->children->next == NULL) && 
	    ((inst->children->type == XML_TEXT_NODE) ||
	     (inst->children->type == XML_CDATA_SECTION_NODE)))
    {
	xmlNodePtr origTxt = inst->children, 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.
	*/
	attr = xmlSetNsProp(ctxt->insert, ns, name, NULL);
	if (attr == NULL) /* TODO: report error ? */
	    goto error;
	/*
	* This was taken over from xsltCopyText() (transform.c).
	*/
	if (ctxt->internalized &&
	    (ctxt->insert->doc != NULL) &&
	    (ctxt->insert->doc->dict == ctxt->dict))
	{
	    copyTxt = xmlNewText(NULL);
	    if (copyTxt == NULL) /* TODO: report error */
		goto error;
	    /*
	    * This is a safe scenario where we don't need to lookup
	    * the dict.
	    */
	    copyTxt->content = origTxt->content;
	    /*
	    * Copy "disable-output-escaping" information.
	    * TODO: Does this have any effect for attribute values
	    *  anyway?
	    */
	    if (origTxt->name == xmlStringTextNoenc)
		copyTxt->name = xmlStringTextNoenc;
	} else {
	    /*
	    * Copy the value.
	    */
	    copyTxt = xmlNewText(origTxt->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);
	}
    } else {
	/*
	* The sequence constructor might be complex, so instantiate it.
	*/
	value = xsltEvalTemplateString(ctxt, node, 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?
	    */
	    attr = xmlSetNsProp(ctxt->insert, ns, name,
		(const xmlChar *) "");
	}
    }

error:
    return;    
}