123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873 |
- /*
- * 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;
- if ((ctxt == NULL) || (ctxt->inst == NULL)) {
- xsltTransformError(ctxt, NULL, NULL,
- "xsltEvalXPathPredicate: No context or instruction\n");
- return(0);
- }
- 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;
- if ((ctxt == NULL) || (ctxt->inst == NULL)) {
- xsltTransformError(ctxt, NULL, NULL,
- "xsltEvalXPathStringNs: No context or instruction\n");
- return(0);
- }
- 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;
- const xmlChar *oldLastText;
- int oldLastTextSize, oldLastTextUse;
- if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL) ||
- (inst->type != XML_ELEMENT_NODE))
- 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;
- oldLastText = ctxt->lasttext;
- oldLastTextSize = ctxt->lasttsize;
- oldLastTextUse = ctxt->lasttuse;
- /*
- * OPTIMIZE TODO: if inst->children consists only of text-nodes.
- */
- xsltApplyOneTemplate(ctxt, contextNode, inst->children, NULL, NULL);
- ctxt->insert = oldInsert;
- ctxt->lasttext = oldLastText;
- ctxt->lasttsize = oldLastTextSize;
- ctxt->lasttuse = oldLastTextUse;
- 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 != '}')) {
- /* Need to check for literal (bug539741) */
- if ((*cur == '\'') || (*cur == '"')) {
- char delim = *(cur++);
- while ((*cur != 0) && (*cur != delim))
- cur++;
- if (*cur != 0)
- cur++; /* skip the ending delimiter */
- } else
- cur++;
- }
- if (*cur == 0) {
- xsltTransformError(ctxt, NULL, inst,
- "xsltAttrTemplateValueProcessNode: unmatched '{'\n");
- ret = xmlStrncat(ret, str, cur - str);
- goto exit;
- }
- str++;
- expr = xmlStrndup(str, cur - str);
- if (expr == NULL)
- goto exit;
- 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 = xmlXPathCtxtCompile(ctxt->xpathCtxt, 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);
- }
- exit:
- 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) ||
- (inst->type != XML_ELEMENT_NODE))
- 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) ||
- (inst->type != XML_ELEMENT_NODE))
- 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) ||
- (target->type != XML_ELEMENT_NODE))
- 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 = NULL;
- xmlNodePtr oldInsert, text;
- xmlNsPtr origNs = NULL, copyNs = NULL;
- const xmlChar *value;
- xmlChar *valueAVT;
- int hasAttr = 0;
- if ((ctxt == NULL) || (target == NULL) || (attrs == NULL) ||
- (target->type != XML_ELEMENT_NODE))
- return(NULL);
- oldInsert = ctxt->insert;
- ctxt->insert = target;
- /*
- * Apply attribute-sets.
- */
- 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);
- if (target->properties != NULL) {
- hasAttr = 1;
- }
- /*
- * Instantiate LRE-attributes.
- */
- 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);
- /*
- * Get 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;
- }
- /*
- * Create a new attribute.
- */
- if (hasAttr) {
- copy = xmlSetNsProp(target, copyNs, attr->name, NULL);
- } else {
- /*
- * Avoid checking for duplicate attributes if there aren't
- * any attribute sets.
- */
- copy = xmlNewDocProp(target->doc, attr->name, NULL);
- if (copy != NULL) {
- copy->ns = copyNs;
- /*
- * 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;
- }
- }
- }
- 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;
- }
- /*
- * 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);
- 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);
- }
|