/** * 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); }
/** * xsltAttrTemplateProcess: * @ctxt: the XSLT transformation context * @target: the result node * @cur: the attribute template node * * Process the given attribute and return the new processed copy. * * Returns the attribute replacement. */ xmlAttrPtr xsltAttrTemplateProcess(xsltTransformContextPtr ctxt, xmlNodePtr target, xmlAttrPtr cur) { const xmlChar *value; xmlNsPtr ns; xmlAttrPtr ret; if ((ctxt == NULL) || (cur == NULL) || (target == NULL)) return(NULL); if (cur->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); } return(NULL); } 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; } } ret = ret->next; } if (ret != NULL) { /* free the existing value */ xmlFreeNodeList(ret->children); ret->children = ret->last = NULL; } else { /* create a new attribute */ if (cur->ns != NULL) ns = xsltGetPlainNamespace(ctxt, cur->parent, cur->ns, target); else ns = NULL; ret = xmlNewNsProp(target, ns, cur->name, NULL); } 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 (cur->psvi != NULL) { xmlChar *val; val = xsltEvalAVT(ctxt, cur->psvi, cur->parent); if (val == NULL) { text->content = xmlStrdup(BAD_CAST "runtime error"); } else { text->content = val; } } else if ((ctxt->internalized) && (target != NULL) && (target->doc != NULL) && (target->doc->dict == ctxt->dict)) { text->content = (xmlChar *) value; } else { text->content = xmlStrdup(value); } } } else { xsltTransformError(ctxt, NULL, cur->parent, "Failed to create attribute %s\n", cur->name); } return(ret); }