root/third_party/libxslt/libxslt/templates.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. xsltEvalXPathPredicate
  2. xsltEvalXPathStringNs
  3. xsltEvalXPathString
  4. xsltEvalTemplateString
  5. xsltAttrTemplateValueProcessNode
  6. xsltAttrTemplateValueProcess
  7. xsltEvalAttrValueTemplate
  8. xsltEvalStaticAttrValueTemplate
  9. xsltAttrTemplateProcess
  10. xsltAttrListTemplateProcess
  11. xsltTemplateProcess

/*
 * templates.c: Implementation of the template processing
 *
 * Reference:
 *   http://www.w3.org/TR/1999/REC-xslt-19991116
 *
 * See Copyright for the status of this software.
 *
 * daniel@veillard.com
 */

#define IN_LIBXSLT
#include "libxslt.h"

#include <string.h>

#include <libxml/xmlmemory.h>
#include <libxml/globals.h>
#include <libxml/xmlerror.h>
#include <libxml/tree.h>
#include <libxml/dict.h>
#include <libxml/xpathInternals.h>
#include <libxml/parserInternals.h>
#include "xslt.h"
#include "xsltInternals.h"
#include "xsltutils.h"
#include "variables.h"
#include "functions.h"
#include "templates.h"
#include "transform.h"
#include "namespaces.h"
#include "attributes.h"

#ifdef WITH_XSLT_DEBUG
#define WITH_XSLT_DEBUG_TEMPLATES
#endif

/************************************************************************
 *                                                                      *
 *                      Module interfaces                               *
 *                                                                      *
 ************************************************************************/
 
/**
 * xsltEvalXPathPredicate:
 * @ctxt:  the XSLT transformation context
 * @comp:  the XPath compiled expression
 * @nsList:  the namespaces in scope
 * @nsNr:  the number of namespaces in scope
 *
 * Process the expression using XPath and evaluate the result as
 * an XPath predicate
 *
 * Returns 1 is the predicate was true, 0 otherwise
 */
int
xsltEvalXPathPredicate(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp,
                       xmlNsPtr *nsList, int nsNr) {
    int ret;
    xmlXPathObjectPtr res;
    int oldNsNr;
    xmlNsPtr *oldNamespaces;
    xmlNodePtr oldInst;
    int oldProximityPosition, oldContextSize;

    oldContextSize = ctxt->xpathCtxt->contextSize;
    oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
    oldNsNr = ctxt->xpathCtxt->nsNr;
    oldNamespaces = ctxt->xpathCtxt->namespaces;
    oldInst = ctxt->inst;

    ctxt->xpathCtxt->node = ctxt->node;
    ctxt->xpathCtxt->namespaces = nsList;
    ctxt->xpathCtxt->nsNr = nsNr;

    res = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);

    if (res != NULL) {
        ret = xmlXPathEvalPredicate(ctxt->xpathCtxt, res);
        xmlXPathFreeObject(res);
#ifdef WITH_XSLT_DEBUG_TEMPLATES
        XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
             "xsltEvalXPathPredicate: returns %d\n", ret));
#endif
    } else {
#ifdef WITH_XSLT_DEBUG_TEMPLATES
        XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
             "xsltEvalXPathPredicate: failed\n"));
#endif
        ctxt->state = XSLT_STATE_STOPPED;
        ret = 0;
    }
    ctxt->xpathCtxt->nsNr = oldNsNr;

    ctxt->xpathCtxt->namespaces = oldNamespaces;
    ctxt->inst = oldInst;
    ctxt->xpathCtxt->contextSize = oldContextSize;
    ctxt->xpathCtxt->proximityPosition = oldProximityPosition;

    return(ret);
}

/**
 * xsltEvalXPathStringNs:
 * @ctxt:  the XSLT transformation context
 * @comp:  the compiled XPath expression
 * @nsNr:  the number of namespaces in the list
 * @nsList:  the list of in-scope namespaces to use
 *
 * Process the expression using XPath, allowing to pass a namespace mapping
 * context and get a string
 *
 * Returns the computed string value or NULL, must be deallocated by the
 *    caller.
 */
xmlChar *
xsltEvalXPathStringNs(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp,
                      int nsNr, xmlNsPtr *nsList) {
    xmlChar *ret = NULL;
    xmlXPathObjectPtr res;
    xmlNodePtr oldInst;
    xmlNodePtr oldNode;
    int oldPos, oldSize;
    int oldNsNr;
    xmlNsPtr *oldNamespaces;

    oldInst = ctxt->inst;
    oldNode = ctxt->node;
    oldPos = ctxt->xpathCtxt->proximityPosition;
    oldSize = ctxt->xpathCtxt->contextSize;
    oldNsNr = ctxt->xpathCtxt->nsNr;
    oldNamespaces = ctxt->xpathCtxt->namespaces;

    ctxt->xpathCtxt->node = ctxt->node;
    /* TODO: do we need to propagate the namespaces here ? */
    ctxt->xpathCtxt->namespaces = nsList;
    ctxt->xpathCtxt->nsNr = nsNr;
    res = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
    if (res != NULL) {
        if (res->type != XPATH_STRING)
            res = xmlXPathConvertString(res);
        if (res->type == XPATH_STRING) {
            ret = res->stringval;
            res->stringval = NULL;
        } else {
            xsltTransformError(ctxt, NULL, NULL,
                 "xpath : string() function didn't return a String\n");
        }
        xmlXPathFreeObject(res);
    } else {
        ctxt->state = XSLT_STATE_STOPPED;
    }
#ifdef WITH_XSLT_DEBUG_TEMPLATES
    XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
         "xsltEvalXPathString: returns %s\n", ret));
#endif
    ctxt->inst = oldInst;
    ctxt->node = oldNode;
    ctxt->xpathCtxt->contextSize = oldSize;
    ctxt->xpathCtxt->proximityPosition = oldPos;
    ctxt->xpathCtxt->nsNr = oldNsNr;
    ctxt->xpathCtxt->namespaces = oldNamespaces;
    return(ret);
}

/**
 * xsltEvalXPathString:
 * @ctxt:  the XSLT transformation context
 * @comp:  the compiled XPath expression
 *
 * Process the expression using XPath and get a string
 *
 * Returns the computed string value or NULL, must be deallocated by the
 *    caller.
 */
xmlChar *
xsltEvalXPathString(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp) {
    return(xsltEvalXPathStringNs(ctxt, comp, 0, NULL));
}

/**
 * xsltEvalTemplateString:
 * @ctxt:  the XSLT transformation context
 * @contextNode:  the current node in the source tree
 * @inst:  the XSLT instruction (xsl:comment, xsl:processing-instruction)
 *
 * Processes the sequence constructor of the given instruction on
 * @contextNode and converts the resulting tree to a string.
 * This is needed by e.g. xsl:comment and xsl:processing-instruction.
 *
 * Returns the computed string value or NULL; it's up to the caller to
 *         free the result.
 */
xmlChar *
xsltEvalTemplateString(xsltTransformContextPtr ctxt,
                       xmlNodePtr contextNode,
                       xmlNodePtr inst)
{
    xmlNodePtr oldInsert, insert = NULL;
    xmlChar *ret;

    if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL))
        return(NULL);

    if (inst->children == NULL)
        return(NULL);

    /*
    * This creates a temporary element-node to add the resulting
    * text content to.
    * OPTIMIZE TODO: Keep such an element-node in the transformation
    *  context to avoid creating it every time.
    */
    insert = xmlNewDocNode(ctxt->output, NULL,
                           (const xmlChar *)"fake", NULL);
    if (insert == NULL) {
        xsltTransformError(ctxt, NULL, contextNode,
                "Failed to create temporary node\n");
        return(NULL);
    }
    oldInsert = ctxt->insert;
    ctxt->insert = insert;
    /*
    * OPTIMIZE TODO: if inst->children consists only of text-nodes.
    */
    xsltApplyOneTemplate(ctxt, contextNode, inst->children, NULL, NULL);

    ctxt->insert = oldInsert;

    ret = xmlNodeGetContent(insert);
    if (insert != NULL)
        xmlFreeNode(insert);
    return(ret);
}

/**
 * xsltAttrTemplateValueProcessNode:
 * @ctxt:  the XSLT transformation context
 * @str:  the attribute template node value
 * @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 inst)
{
    xmlChar *ret = NULL;
    const xmlChar *cur;
    xmlChar *expr, *val;
    xmlNsPtr *nsList = NULL;
    int nsNr = 0;

    if (str == NULL) return(NULL);
    if (*str == 0)
        return(xmlStrndup((xmlChar *)"", 0));

    cur = str;
    while (*cur != 0) {
        if (*cur == '{') {
            if (*(cur+1) == '{') {      /* escaped '{' */
                cur++;
                ret = xmlStrncat(ret, str, cur - str);
                cur++;
                str = cur;
                continue;
            }
            ret = xmlStrncat(ret, str, cur - str);
            str = cur;
            cur++;
            while ((*cur != 0) && (*cur != '}')) cur++;
            if (*cur == 0) {
                xsltTransformError(ctxt, NULL, inst,
                        "xsltAttrTemplateValueProcessNode: unmatched '{'\n");
                ret = xmlStrncat(ret, str, cur - str);
                return(ret);
            }
            str++;
            expr = xmlStrndup(str, cur - str);
            if (expr == NULL)
                return(ret);
            else if (*expr == '{') {
                ret = xmlStrcat(ret, expr);
                xmlFree(expr);
            } else {
                xmlXPathCompExprPtr comp;
                /*
                 * TODO: keep precompiled form around
                 */
                if ((nsList == NULL) && (inst != NULL)) {
                    int i = 0;

                    nsList = xmlGetNsList(inst->doc, inst);
                    if (nsList != NULL) {
                        while (nsList[i] != NULL)
                            i++;
                        nsNr = i;
                    }
                }
                comp = xmlXPathCompile(expr);
                val = xsltEvalXPathStringNs(ctxt, comp, nsNr, nsList);
                xmlXPathFreeCompExpr(comp);
                xmlFree(expr);
                if (val != NULL) {
                    ret = xmlStrcat(ret, val);
                    xmlFree(val);
                }
            }
            cur++;
            str = cur;
        } else if (*cur == '}') {
            cur++;
            if (*cur == '}') {  /* escaped '}' */
                ret = xmlStrncat(ret, str, cur - str);
                cur++;
                str = cur;
                continue;
            } else {
                xsltTransformError(ctxt, NULL, inst,
                     "xsltAttrTemplateValueProcessNode: unmatched '}'\n");
            }
        } else
            cur++;
    }
    if (cur != str) {
        ret = xmlStrncat(ret, str, cur - str);
    }

    if (nsList != NULL)
        xmlFree(nsList);

    return(ret);
}

/**
 * xsltAttrTemplateValueProcess:
 * @ctxt:  the XSLT transformation context
 * @str:  the attribute template node value
 *
 * Process the given node and return the new string value.
 *
 * Returns the computed string value or NULL, must be deallocated by the
 *    caller.
 */
xmlChar *
xsltAttrTemplateValueProcess(xsltTransformContextPtr ctxt, const xmlChar *str) {
    return(xsltAttrTemplateValueProcessNode(ctxt, str, NULL));
}

/**
 * xsltEvalAttrValueTemplate:
 * @ctxt:  the XSLT transformation context
 * @inst:  the instruction (or LRE) in the stylesheet holding the
 *         attribute with an AVT
 * @name:  the attribute QName
 * @ns:  the attribute namespace URI
 *
 * Evaluate a attribute value template, i.e. the attribute value can
 * contain expressions contained in curly braces ({}) and those are
 * substituted by they computed value.
 *
 * Returns the computed string value or NULL, must be deallocated by the
 *    caller.
 */
xmlChar *
xsltEvalAttrValueTemplate(xsltTransformContextPtr ctxt, xmlNodePtr inst,
                          const xmlChar *name, const xmlChar *ns)
{
    xmlChar *ret;
    xmlChar *expr;

    if ((ctxt == NULL) || (inst == NULL) || (name == NULL))
        return(NULL);

    expr = xsltGetNsProp(inst, name, ns);
    if (expr == NULL)
        return(NULL);

    /*
     * TODO: though now {} is detected ahead, it would still be good to
     *       optimize both functions to keep the splitted value if the
     *       attribute content and the XPath precompiled expressions around
     */

    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));
#endif
    if (expr != NULL)
        xmlFree(expr);
    return(ret);
}

/**
 * xsltEvalStaticAttrValueTemplate:
 * @style:  the XSLT stylesheet
 * @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
 *
 * Check if an attribute value template has a static value, i.e. the
 * attribute value does not contain expressions contained in curly braces ({})
 *
 * Returns the static string value or NULL, must be deallocated by the
 *    caller.
 */
const xmlChar *
xsltEvalStaticAttrValueTemplate(xsltStylesheetPtr style, xmlNodePtr inst,
                        const xmlChar *name, const xmlChar *ns, int *found) {
    const xmlChar *ret;
    xmlChar *expr;

    if ((style == NULL) || (inst == NULL) || (name == NULL))
        return(NULL);

    expr = xsltGetNsProp(inst, name, ns);
    if (expr == NULL) {
        *found = 0;
        return(NULL);
    }
    *found = 1;

    ret = xmlStrchr(expr, '{');
    if (ret != NULL) {
        xmlFree(expr);
        return(NULL);
    }
    ret = xmlDictLookup(style->dict, expr, -1);
    xmlFree(expr);
    return(ret);
}

/**
 * xsltAttrTemplateProcess:
 * @ctxt:  the XSLT transformation context
 * @target:  the element where the attribute will be grafted
 * @attr:  the attribute node of a literal result element
 *
 * 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 generated attribute node.
 */
xmlAttrPtr
xsltAttrTemplateProcess(xsltTransformContextPtr ctxt, xmlNodePtr target,
                        xmlAttrPtr attr)
{
    const xmlChar *value;
    xmlAttrPtr ret;

    if ((ctxt == NULL) || (attr == NULL) || (target == NULL))
        return(NULL);
    
    if (attr->type != XML_ATTRIBUTE_NODE)
        return(NULL);

    /*
    * 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 (((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) {  
        /* 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 (attr->ns != NULL)
            ret = xmlNewNsProp(target,
                xsltGetNamespace(ctxt, attr->parent, attr->ns, target),
                    attr->name, NULL);
        else
            ret = xmlNewNsProp(target, NULL, attr->name, NULL); 
    }
    /*
    * Set the value.
    */
    if (ret != NULL) {
        xmlNodePtr text;

        text = xmlNewText(NULL);
        if (text != NULL) {
            ret->last = ret->children = text;
            text->parent = (xmlNodePtr) ret;
            text->doc = ret->doc;

            if (attr->psvi != NULL) {
                /*
                * Evaluate the Attribute Value Template.
                */
                xmlChar *val;
                val = xsltEvalAVT(ctxt, attr->psvi, attr->parent);
                if (val == 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 "");
                } else {
                    text->content = val;
                }
            } else if ((ctxt->internalized) && (target != NULL) &&
                       (target->doc != NULL) &&
                       (target->doc->dict == ctxt->dict) &&
                       xmlDictOwns(ctxt->dict, value)) {
                text->content = (xmlChar *) value;
            } else {
                text->content = xmlStrdup(value);
            }
        }
    } else {
        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);
}


/**
 * xsltAttrListTemplateProcess:
 * @ctxt:  the XSLT transformation context
 * @target:  the element where the attributes will be grafted
 * @attrs:  the first attribute
 *
 * 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.
 *
 * Called by xsltApplySequenceConstructor() (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 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;        

    /*
    * 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;
        }
        /*
        * 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) &&
                xmlDictOwns(ctxt->dict, value))
            {
                text->content = (xmlChar *) value;
            } else {
                text->content = xmlStrdup(value);
            }
            if ((copy != NULL) && (text != NULL) &&
                (xmlIsID(copy->doc, copy->parent, copy)))
                xmlAddID(NULL, copy->doc, text->content, copy);
        }

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(target->properties);

error:
    ctxt->insert = oldInsert;
    return(NULL);
}


/**
 * xsltTemplateProcess:
 * @ctxt:  the XSLT transformation context
 * @node:  the attribute template node
 *
 * Obsolete. Don't use it.
 *
 * Returns NULL.
 */
xmlNodePtr *
xsltTemplateProcess(xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, xmlNodePtr node) {
    if (node == NULL)
        return(NULL);
    
    return(0);
}



/* [<][>][^][v][top][bottom][index][help] */