/* * xmlCreateEntity: * * internal routine doing the entity node strutures allocations */ static xmlEntityPtr xmlCreateEntity(xmlDictPtr dict, const xmlChar *name, int type, const xmlChar *ExternalID, const xmlChar *SystemID, const xmlChar *content) { xmlEntityPtr ret; ret = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity)); if (ret == NULL) { xmlEntitiesErrMemory("xmlCreateEntity: malloc failed"); return(NULL); } memset(ret, 0, sizeof(xmlEntity)); ret->type = XML_ENTITY_DECL; ret->checked = 0; /* * fill the structure. */ ret->etype = (xmlEntityType) type; if (dict == NULL) { ret->name = xmlStrdup(name); if (ExternalID != NULL) ret->ExternalID = xmlStrdup(ExternalID); if (SystemID != NULL) ret->SystemID = xmlStrdup(SystemID); } else { ret->name = xmlDictLookup(dict, name, -1); if (ExternalID != NULL) ret->ExternalID = xmlDictLookup(dict, ExternalID, -1); if (SystemID != NULL) ret->SystemID = xmlDictLookup(dict, SystemID, -1); } if (content != NULL) { ret->length = xmlStrlen(content); if ((dict != NULL) && (ret->length < 5)) ret->content = (xmlChar *) xmlDictLookup(dict, content, ret->length); else ret->content = xmlStrndup(content, ret->length); } else { ret->length = 0; ret->content = NULL; } ret->URI = NULL; /* to be computed by the layer knowing the defining entity */ ret->orig = NULL; ret->owner = 0; 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); }
/** * xmlSchematronNewParserCtxt: * @URL: the location of the schema * * Create an XML Schematrons parse context for that file/resource expected * to contain an XML Schematrons file. * * Returns the parser context or NULL in case of error */ xmlSchematronParserCtxtPtr xmlSchematronNewParserCtxt(const char *URL) { xmlSchematronParserCtxtPtr ret; if (URL == NULL) return (NULL); ret = (xmlSchematronParserCtxtPtr) xmlMalloc(sizeof(xmlSchematronParserCtxt)); if (ret == NULL) { xmlSchematronPErrMemory(NULL, "allocating schema parser context", NULL); return (NULL); } memset(ret, 0, sizeof(xmlSchematronParserCtxt)); ret->type = XML_STRON_CTXT_PARSER; ret->dict = xmlDictCreate(); ret->URL = xmlDictLookup(ret->dict, (const xmlChar *) URL, -1); ret->includes = NULL; ret->xctxt = xmlXPathNewContext(NULL); if (ret->xctxt == NULL) { xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context", NULL); xmlSchematronFreeParserCtxt(ret); return (NULL); } ret->xctxt->flags = XML_XPATH_CHECKNS; return (ret); }
void xsltApplyAttributeSet(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst ATTRIBUTE_UNUSED, const xmlChar * attributes) { const xmlChar *ncname = NULL; const xmlChar *prefix = NULL; const xmlChar *attrib, *endattr; xsltAttrElemPtr values; xsltStylesheetPtr style; if (attributes == NULL) { return; } attrib = attributes; while (*attrib != 0) { while (IS_BLANK(*attrib)) attrib++; if (*attrib == 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 xsltGenericDebug(xsltGenericDebugContext, "apply attribute set %s\n", attrib); #endif ncname = xsltSplitQName(ctxt->dict, attrib, &prefix); style = ctxt->style; #ifdef WITH_DEBUGGER if ((style != NULL) && (style->attributeSets != NULL) && (ctxt->debugStatus != XSLT_DEBUG_NONE)) { values = xmlHashLookup2(style->attributeSets, ncname, prefix); if ((values != NULL) && (values->attr != NULL)) xslHandleDebugger(values->attr->parent, node, NULL, ctxt); } #endif while (style != NULL) { values = xmlHashLookup2(style->attributeSets, ncname, prefix); while (values != NULL) { if (values->attr != NULL) { xsltAttributeInternal(ctxt, node, values->attr, values->attr->psvi, 1); } values = values->next; } style = xsltNextImport(style); } } attrib = endattr; } }
/** * xmlSchematronAddNamespace: * @ctxt: the schema parser context * @prefix: the namespace prefix * @ns: the namespace name * * Add a namespace definition in the context */ static void xmlSchematronAddNamespace(xmlSchematronParserCtxtPtr ctxt, const xmlChar *prefix, const xmlChar *ns) { if (ctxt->namespaces == NULL) { ctxt->maxNamespaces = 10; ctxt->namespaces = (const xmlChar **) xmlMalloc(ctxt->maxNamespaces * 2 * sizeof(const xmlChar *)); if (ctxt->namespaces == NULL) { xmlSchematronPErrMemory(NULL, "allocating parser namespaces", NULL); return; } ctxt->nbNamespaces = 0; } else if (ctxt->nbNamespaces + 2 >= ctxt->maxNamespaces) { const xmlChar **tmp; tmp = (const xmlChar **) xmlRealloc((xmlChar **) ctxt->namespaces, ctxt->maxNamespaces * 4 * sizeof(const xmlChar *)); if (tmp == NULL) { xmlSchematronPErrMemory(NULL, "allocating parser namespaces", NULL); return; } ctxt->namespaces = tmp; ctxt->maxNamespaces *= 2; } ctxt->namespaces[2 * ctxt->nbNamespaces] = xmlDictLookup(ctxt->dict, ns, -1); ctxt->namespaces[2 * ctxt->nbNamespaces + 1] = xmlDictLookup(ctxt->dict, prefix, -1); ctxt->nbNamespaces++; ctxt->namespaces[2 * ctxt->nbNamespaces] = NULL; ctxt->namespaces[2 * ctxt->nbNamespaces + 1] = NULL; }
void xsltParseStylesheetAttributeSet(xsltStylesheetPtr style, xmlNodePtr cur) { const xmlChar *ncname; const xmlChar *prefix; const xmlChar *nsUri = NULL; xmlChar *value; xmlNodePtr child; xsltAttrSetPtr set; if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE)) return; value = xmlGetNsProp(cur, (const xmlChar *)"name", NULL); if ((value == NULL) || (*value == 0)) { xsltGenericError(xsltGenericErrorContext, "xsl:attribute-set : name is missing\n"); if (value) xmlFree(value); return; } if (xmlValidateQName(value, 0)) { xsltTransformError(NULL, style, cur, "xsl:attribute-set : The name '%s' is not a valid QName.\n", value); style->errors++; xmlFree(value); return; } ncname = xsltSplitQName(style->dict, value, &prefix); xmlFree(value); value = NULL; if (prefix != NULL) { xmlNsPtr ns = xmlSearchNs(style->doc, cur, prefix); if (ns == NULL) { xsltTransformError(NULL, style, cur, "xsl:attribute-set : No namespace found for QName '%s:%s'\n", prefix, ncname); style->errors++; return; } nsUri = ns->href; } if (style->attributeSets == NULL) { #ifdef WITH_XSLT_DEBUG_ATTRIBUTES xsltGenericDebug(xsltGenericDebugContext, "creating attribute set table\n"); #endif style->attributeSets = xmlHashCreate(10); } if (style->attributeSets == NULL) return; set = xmlHashLookup2(style->attributeSets, ncname, nsUri); if (set == NULL) { set = xsltNewAttrSet(); if (set == NULL) return; xmlHashAddEntry2(style->attributeSets, ncname, nsUri, set); } /* * Parse the content. Only xsl:attribute elements are allowed. */ child = cur->children; while (child != NULL) { /* * Report invalid nodes. */ if ((child->type != XML_ELEMENT_NODE) || (child->ns == NULL) || (! IS_XSLT_ELEM(child))) { if (child->type == XML_ELEMENT_NODE) xsltTransformError(NULL, style, child, "xsl:attribute-set : unexpected child %s\n", child->name); else xsltTransformError(NULL, style, child, "xsl:attribute-set : child of unexpected type\n"); } else if (!IS_XSLT_NAME(child, "attribute")) { xsltTransformError(NULL, style, child, "xsl:attribute-set : unexpected child xsl:%s\n", child->name); } else { #ifdef WITH_XSLT_DEBUG_ATTRIBUTES xsltGenericDebug(xsltGenericDebugContext, "add attribute to list %s\n", ncname); #endif if (child->psvi == NULL) { xsltTransformError(NULL, style, child, "xsl:attribute-set : internal error, attribute %s not " "compiled\n", child->name); } else { set->attrs = xsltAddAttrElemList(set->attrs, child); } } child = child->next; } /* * Process attribute "use-attribute-sets". */ value = xmlGetNsProp(cur, BAD_CAST "use-attribute-sets", NULL); if (value != NULL) { const xmlChar *curval, *endval; curval = value; while (*curval != 0) { while (IS_BLANK(*curval)) curval++; if (*curval == 0) break; endval = curval; while ((*endval != 0) && (!IS_BLANK(*endval))) endval++; curval = xmlDictLookup(style->dict, curval, endval - curval); if (curval) { const xmlChar *ncname2 = NULL; const xmlChar *prefix2 = NULL; const xmlChar *nsUri2 = NULL; #ifdef WITH_XSLT_DEBUG_ATTRIBUTES xsltGenericDebug(xsltGenericDebugContext, "xsl:attribute-set : %s adds use %s\n", ncname, curval); #endif if (xmlValidateQName(curval, 0)) { xsltTransformError(NULL, style, cur, "xsl:attribute-set : The name '%s' in " "use-attribute-sets is not a valid QName.\n", curval); style->errors++; xmlFree(value); return; } ncname2 = xsltSplitQName(style->dict, curval, &prefix2); if (prefix2 != NULL) { xmlNsPtr ns2 = xmlSearchNs(style->doc, cur, prefix2); if (ns2 == NULL) { xsltTransformError(NULL, style, cur, "xsl:attribute-set : No namespace found for QName " "'%s:%s' in use-attribute-sets\n", prefix2, ncname2); style->errors++; xmlFree(value); return; } nsUri2 = ns2->href; } set->useAttrSets = xsltAddUseAttrSetList(set->useAttrSets, ncname2, nsUri2); } curval = endval; } xmlFree(value); value = NULL; } #ifdef WITH_XSLT_DEBUG_ATTRIBUTES xsltGenericDebug(xsltGenericDebugContext, "updated attribute list %s\n", ncname); #endif }
/** * xmlSchematronParse: * @ctxt: a schema validation context * * parse a schema definition resource and build an internal * XML Shema struture which can be used to validate instances. * * Returns the internal XML Schematron structure built from the resource or * NULL in case of error */ xmlSchematronPtr xmlSchematronParse(xmlSchematronParserCtxtPtr ctxt) { xmlSchematronPtr ret = NULL; xmlDocPtr doc; xmlNodePtr root, cur; int preserve = 0; if (ctxt == NULL) return (NULL); ctxt->nberrors = 0; /* * First step is to parse the input document into an DOM/Infoset */ if (ctxt->URL != NULL) { doc = xmlReadFile((const char *) ctxt->URL, NULL, SCHEMATRON_PARSE_OPTIONS); if (doc == NULL) { xmlSchematronPErr(ctxt, NULL, XML_SCHEMAP_FAILED_LOAD, "xmlSchematronParse: could not load '%s'.\n", ctxt->URL, NULL); return (NULL); } ctxt->preserve = 0; } else if (ctxt->buffer != NULL) { doc = xmlReadMemory(ctxt->buffer, ctxt->size, NULL, NULL, SCHEMATRON_PARSE_OPTIONS); if (doc == NULL) { xmlSchematronPErr(ctxt, NULL, XML_SCHEMAP_FAILED_PARSE, "xmlSchematronParse: could not parse.\n", NULL, NULL); return (NULL); } doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer"); ctxt->URL = xmlDictLookup(ctxt->dict, BAD_CAST "in_memory_buffer", -1); ctxt->preserve = 0; } else if (ctxt->doc != NULL) { doc = ctxt->doc; preserve = 1; ctxt->preserve = 1; } else { xmlSchematronPErr(ctxt, NULL, XML_SCHEMAP_NOTHING_TO_PARSE, "xmlSchematronParse: could not parse.\n", NULL, NULL); return (NULL); } /* * Then extract the root and Schematron parse it */ root = xmlDocGetRootElement(doc); if (root == NULL) { xmlSchematronPErr(ctxt, (xmlNodePtr) doc, XML_SCHEMAP_NOROOT, "The schema has no document element.\n", NULL, NULL); if (!preserve) { xmlFreeDoc(doc); } return (NULL); } if (!IS_SCHEMATRON(root, "schema")) { xmlSchematronPErr(ctxt, root, XML_SCHEMAP_NOROOT, "The XML document '%s' is not a XML schematron document", ctxt->URL, NULL); goto exit; } ret = xmlSchematronNewSchematron(ctxt); if (ret == NULL) goto exit; ctxt->schema = ret; /* * scan the schema elements */ cur = root->children; NEXT_SCHEMATRON(cur); if (IS_SCHEMATRON(cur, "title")) { xmlChar *title = xmlNodeGetContent(cur); if (title != NULL) { ret->title = xmlDictLookup(ret->dict, title, -1); xmlFree(title); } cur = cur->next; NEXT_SCHEMATRON(cur); } while (IS_SCHEMATRON(cur, "ns")) { xmlChar *prefix = xmlGetNoNsProp(cur, BAD_CAST "prefix"); xmlChar *uri = xmlGetNoNsProp(cur, BAD_CAST "uri"); if ((uri == NULL) || (uri[0] == 0)) { xmlSchematronPErr(ctxt, cur, XML_SCHEMAP_NOROOT, "ns element has no uri", NULL, NULL); } if ((prefix == NULL) || (prefix[0] == 0)) { xmlSchematronPErr(ctxt, cur, XML_SCHEMAP_NOROOT, "ns element has no prefix", NULL, NULL); } if ((prefix) && (uri)) { xmlXPathRegisterNs(ctxt->xctxt, prefix, uri); xmlSchematronAddNamespace(ctxt, prefix, uri); ret->nbNs++; } if (uri) xmlFree(uri); if (prefix) xmlFree(prefix); cur = cur->next; NEXT_SCHEMATRON(cur); } while (cur != NULL) { if (IS_SCHEMATRON(cur, "pattern")) { xmlSchematronParsePattern(ctxt, cur); ret->nbPattern++; } else { xmlSchematronPErr(ctxt, cur, XML_SCHEMAP_NOROOT, "Expecting a pattern element instead of %s", cur->name, NULL); } cur = cur->next; NEXT_SCHEMATRON(cur); } if (ret->nbPattern == 0) { xmlSchematronPErr(ctxt, root, XML_SCHEMAP_NOROOT, "The schematron document '%s' has no pattern", ctxt->URL, NULL); goto exit; } /* the original document must be kept for reporting */ ret->doc = doc; if (preserve) { ret->preserve = 1; } preserve = 1; exit: if (!preserve) { xmlFreeDoc(doc); } if (ret != NULL) { if (ctxt->nberrors != 0) { xmlSchematronFree(ret); ret = NULL; } else { ret->namespaces = ctxt->namespaces; ret->nbNamespaces = ctxt->nbNamespaces; ctxt->namespaces = NULL; } } return (ret); }
/** * xmlDictQLookup: * @dict: the dictionary * @prefix: the prefix * @name: the name * * Add the QName @prefix:@name to the hash @dict if not present. * * Returns the internal copy of the QName or NULL in case of internal error */ const xmlChar * xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) { unsigned long okey, key, nbi = 0; xmlDictEntryPtr entry; xmlDictEntryPtr insert; const xmlChar *ret; unsigned int len, plen, l; if ((dict == NULL) || (name == NULL)) return(NULL); if (prefix == NULL) return(xmlDictLookup(dict, name, -1)); l = len = strlen((const char *) name); plen = strlen((const char *) prefix); len += 1 + plen; /* * Check for duplicate and insertion location. */ okey = xmlDictComputeQKey(dict, prefix, plen, name, l); key = okey % dict->size; if (dict->dict[key].valid == 0) { insert = NULL; } else { for (insert = &(dict->dict[key]); insert->next != NULL; insert = insert->next) { if ((insert->okey == okey) && (insert->len == len) && (xmlStrQEqual(prefix, name, insert->name))) return(insert->name); nbi++; } if ((insert->okey == okey) && (insert->len == len) && (xmlStrQEqual(prefix, name, insert->name))) return(insert->name); } if (dict->subdict) { unsigned long skey; /* we cannot always reuse the same okey for the subdict */ if (((dict->size == MIN_DICT_SIZE) && (dict->subdict->size != MIN_DICT_SIZE)) || ((dict->size != MIN_DICT_SIZE) && (dict->subdict->size == MIN_DICT_SIZE))) skey = xmlDictComputeQKey(dict->subdict, prefix, plen, name, l); else skey = okey; key = skey % dict->subdict->size; if (dict->subdict->dict[key].valid != 0) { xmlDictEntryPtr tmp; for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL; tmp = tmp->next) { if ((tmp->okey == skey) && (tmp->len == len) && (xmlStrQEqual(prefix, name, tmp->name))) return(tmp->name); nbi++; } if ((tmp->okey == skey) && (tmp->len == len) && (xmlStrQEqual(prefix, name, tmp->name))) return(tmp->name); } key = okey % dict->size; } ret = xmlDictAddQString(dict, prefix, plen, name, l); if (ret == NULL) return(NULL); if (insert == NULL) { entry = &(dict->dict[key]); } else { entry = xmlMalloc(sizeof(xmlDictEntry)); if (entry == NULL) return(NULL); } entry->name = ret; entry->len = len; entry->next = NULL; entry->valid = 1; entry->okey = okey; if (insert != NULL) insert->next = entry; dict->nbElems++; if ((nbi > MAX_HASH_LEN) && (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size); /* Note that entry may have been freed at this point by xmlDictGrow */ 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); }
/** * 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); }
int xslDbgShellSetVariable(xsltTransformContextPtr styleCtxt, xmlChar * arg) { int result = 0, showUsage = 0; xmlChar *name, *nameURI, *selectExpr, *opts[3]; if (!styleCtxt) { xsldbgGenericErrorFunc(i18n("Error: Stylesheet is not valid.\n")); return result; } if (!arg) { #ifdef WITH_XSLDBG_DEBUG_PROCESS xsltGenericError(xsltGenericErrorContext, "Error: NULL argument provided\n"); #endif return result; } if (xmlStrLen(arg) > 1) { if (splitString(arg, 2, opts) == 2) { nameURI = NULL; /* ignore any "$" prefix as user probably didn't mean that "$" is part of variable name*/ if (*opts[0] =='$'){ opts[0] = opts[0] + 1; } name = xmlSplitQName2(opts[0], &nameURI); if (name == NULL) name = xmlStrdup(opts[0]); selectExpr = xmlStrdup(opts[1]); if (name && selectExpr) { xsltStackElemPtr def = NULL; if (styleCtxt->varsNr && styleCtxt->varsTab) { /* try finding varaible in stack */ for (int i = styleCtxt->varsNr; i > styleCtxt->varsBase; i--) { xsltStackElemPtr item = styleCtxt->varsTab[i-1]; while (item) { if ((xmlStrCmp(name, item->name) == 0) && (item->nameURI == NULL || (xmlStrCmp(name, item->nameURI) == 0))) { def = item; break; } item = item->next; } } } if (def == NULL) def = (xsltStackElemPtr) xmlHashLookup2(styleCtxt->globalVars, name, nameURI); if (def != NULL) { if (def->select) { def->select = xmlDictLookup(styleCtxt->dict, selectExpr, -1); def->tree = NULL; /* maybe a memory leak, but play it safe */ def->computed = 1; if (def->comp->comp) xmlXPathFreeCompExpr(def->comp->comp); def->comp->comp = xmlXPathCompile(def->select); if (def->value) xmlXPathFreeObject(def->value); def->value = xmlXPathEval(def->select, styleCtxt->xpathCtxt); result = 1; } else { xmlFree(selectExpr); xsldbgGenericErrorFunc(i18n("Error: Cannot change a variable that does not use the select attribute.\n")); } } else xsldbgGenericErrorFunc(i18n("Error: Variable %1 was not found.\n").arg(xsldbgText(name))); xmlFree(name); } else xsldbgGenericErrorFunc(i18n("Error: Out of memory.\n")); } else { showUsage = 1; } if (showUsage == 1) xsldbgGenericErrorFunc(i18n("Error: Invalid arguments to command %1.\n").arg("set")); } return result; }
/* * Test a single dictionary */ static int run_test1(void) { int i, j; xmlDictPtr dict; int ret = 0; xmlChar prefix[40]; xmlChar *cur, *pref; const xmlChar *tmp; dict = xmlDictCreate(); if (dict == NULL) { fprintf(stderr, "Out of memory while creating dictionary\n"); exit(1); } memset(test1, 0, sizeof(test1)); /* * Fill in NB_STRINGS_MIN, at this point the dictionary should not grow * and we allocate all those doing the fast key computations */ for (i = 0;i < NB_STRINGS_MIN;i++) { test1[i] = xmlDictLookup(dict, strings1[i], -1); if (test1[i] == NULL) { fprintf(stderr, "Failed lookup for '%s'\n", strings1[i]); ret = 1; nbErrors++; } } j = NB_STRINGS_MAX - NB_STRINGS_NS; /* ":foo" like strings1 */ for (i = 0;i < NB_STRINGS_MIN;i++, j++) { test1[j] = xmlDictLookup(dict, strings1[j], xmlStrlen(strings1[j])); if (test1[j] == NULL) { fprintf(stderr, "Failed lookup for '%s'\n", strings1[j]); ret = 1; nbErrors++; } } /* "a:foo" like strings1 */ j = NB_STRINGS_MAX - NB_STRINGS_MIN; for (i = 0;i < NB_STRINGS_MIN;i++, j++) { test1[j] = xmlDictLookup(dict, strings1[j], xmlStrlen(strings1[j])); if (test1[j] == NULL) { fprintf(stderr, "Failed lookup for '%s'\n", strings1[j]); ret = 1; nbErrors++; } } /* * At this point allocate all the strings * the dictionary will grow in the process, reallocate more string tables * and switch to the better key generator */ for (i = 0;i < NB_STRINGS_MAX;i++) { if (test1[i] != NULL) continue; test1[i] = xmlDictLookup(dict, strings1[i], -1); if (test1[i] == NULL) { fprintf(stderr, "Failed lookup for '%s'\n", strings1[i]); ret = 1; nbErrors++; } } /* * Now we can start to test things, first that all strings1 belongs to * the dict */ for (i = 0;i < NB_STRINGS_MAX;i++) { if (!xmlDictOwns(dict, test1[i])) { fprintf(stderr, "Failed ownership failure for '%s'\n", strings1[i]); ret = 1; nbErrors++; } } /* * Then that another lookup to the string will return the same */ for (i = 0;i < NB_STRINGS_MAX;i++) { if (xmlDictLookup(dict, strings1[i], -1) != test1[i]) { fprintf(stderr, "Failed re-lookup check for %d, '%s'\n", i, strings1[i]); ret = 1; nbErrors++; } } /* * More complex, check the QName lookups */ for (i = NB_STRINGS_MAX - NB_STRINGS_NS;i < NB_STRINGS_MAX;i++) { cur = strings1[i]; pref = &prefix[0]; while (*cur != ':') *pref++ = *cur++; cur++; *pref = 0; tmp = xmlDictQLookup(dict, &prefix[0], cur); if (tmp != test1[i]) { fprintf(stderr, "Failed lookup check for '%s':'%s'\n", &prefix[0], cur); ret = 1; nbErrors++; } } run_test2(dict); xmlDictFree(dict); return(ret); }
/* * This tests the sub-dictionary support */ static int run_test2(xmlDictPtr parent) { int i, j; xmlDictPtr dict; int ret = 0; xmlChar prefix[40]; xmlChar *cur, *pref; const xmlChar *tmp; dict = xmlDictCreateSub(parent); if (dict == NULL) { fprintf(stderr, "Out of memory while creating sub-dictionary\n"); exit(1); } memset(test2, 0, sizeof(test2)); /* * Fill in NB_STRINGS_MIN, at this point the dictionary should not grow * and we allocate all those doing the fast key computations * All the strings are based on a different seeds subset so we know * they are allocated in the main dictionary, not coming from the parent */ for (i = 0;i < NB_STRINGS_MIN;i++) { test2[i] = xmlDictLookup(dict, strings2[i], -1); if (test2[i] == NULL) { fprintf(stderr, "Failed lookup for '%s'\n", strings2[i]); ret = 1; nbErrors++; } } j = NB_STRINGS_MAX - NB_STRINGS_NS; /* ":foo" like strings2 */ for (i = 0;i < NB_STRINGS_MIN;i++, j++) { test2[j] = xmlDictLookup(dict, strings2[j], xmlStrlen(strings2[j])); if (test2[j] == NULL) { fprintf(stderr, "Failed lookup for '%s'\n", strings2[j]); ret = 1; nbErrors++; } } /* "a:foo" like strings2 */ j = NB_STRINGS_MAX - NB_STRINGS_MIN; for (i = 0;i < NB_STRINGS_MIN;i++, j++) { test2[j] = xmlDictLookup(dict, strings2[j], xmlStrlen(strings2[j])); if (test2[j] == NULL) { fprintf(stderr, "Failed lookup for '%s'\n", strings2[j]); ret = 1; nbErrors++; } } /* * At this point allocate all the strings * the dictionary will grow in the process, reallocate more string tables * and switch to the better key generator */ for (i = 0;i < NB_STRINGS_MAX;i++) { if (test2[i] != NULL) continue; test2[i] = xmlDictLookup(dict, strings2[i], -1); if (test2[i] == NULL) { fprintf(stderr, "Failed lookup for '%s'\n", strings2[i]); ret = 1; nbErrors++; } } /* * Now we can start to test things, first that all strings2 belongs to * the dict, and that none of them was actually allocated in the parent */ for (i = 0;i < NB_STRINGS_MAX;i++) { if (!xmlDictOwns(dict, test2[i])) { fprintf(stderr, "Failed ownership failure for '%s'\n", strings2[i]); ret = 1; nbErrors++; } if (xmlDictOwns(parent, test2[i])) { fprintf(stderr, "Failed parent ownership failure for '%s'\n", strings2[i]); ret = 1; nbErrors++; } } /* * Also verify that all strings from the parent are seen from the subdict */ for (i = 0;i < NB_STRINGS_MAX;i++) { if (!xmlDictOwns(dict, test1[i])) { fprintf(stderr, "Failed sub-ownership failure for '%s'\n", strings1[i]); ret = 1; nbErrors++; } } /* * Then that another lookup to the string in sub will return the same */ for (i = 0;i < NB_STRINGS_MAX;i++) { if (xmlDictLookup(dict, strings2[i], -1) != test2[i]) { fprintf(stderr, "Failed re-lookup check for %d, '%s'\n", i, strings2[i]); ret = 1; nbErrors++; } } /* * But also that any lookup for a string in the parent will be provided * as in the parent */ for (i = 0;i < NB_STRINGS_MAX;i++) { if (xmlDictLookup(dict, strings1[i], -1) != test1[i]) { fprintf(stderr, "Failed parent string lookup check for %d, '%s'\n", i, strings1[i]); ret = 1; nbErrors++; } } /* * check the QName lookups */ for (i = NB_STRINGS_MAX - NB_STRINGS_NS;i < NB_STRINGS_MAX;i++) { cur = strings2[i]; pref = &prefix[0]; while (*cur != ':') *pref++ = *cur++; cur++; *pref = 0; tmp = xmlDictQLookup(dict, &prefix[0], cur); if (tmp != test2[i]) { fprintf(stderr, "Failed lookup check for '%s':'%s'\n", &prefix[0], cur); ret = 1; nbErrors++; } } /* * check the QName lookups for strings from the parent */ for (i = NB_STRINGS_MAX - NB_STRINGS_NS;i < NB_STRINGS_MAX;i++) { cur = strings1[i]; pref = &prefix[0]; while (*cur != ':') *pref++ = *cur++; cur++; *pref = 0; tmp = xmlDictQLookup(dict, &prefix[0], cur); if (xmlDictQLookup(dict, &prefix[0], cur) != test1[i]) { fprintf(stderr, "Failed parent lookup check for '%s':'%s'\n", &prefix[0], cur); ret = 1; nbErrors++; } } xmlDictFree(dict); return(ret); }
/** * 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; }
/** * xsltApplyAttributeSet: * @ctxt: the XSLT stylesheet * @node: the node in the source tree. * @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. * 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, const xmlChar *attrSets) { const xmlChar *ncname = NULL; const xmlChar *prefix = NULL; const xmlChar *curstr, *endstr; xsltAttrSetPtr set; xsltStylesheetPtr style; 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; } } } /* * Parse/apply the list of QNames. */ curstr = attrSets; while (*curstr != 0) { while (IS_BLANK(*curstr)) curstr++; if (*curstr == 0) break; endstr = curstr; while ((*endstr != 0) && (!IS_BLANK(*endstr))) endstr++; curstr = xmlDictLookup(ctxt->dict, curstr, endstr - curstr); if (curstr) { xmlNsPtr ns; const xmlChar *nsUri = NULL; #ifdef WITH_XSLT_DEBUG_ATTRIBUTES xsltGenericDebug(xsltGenericDebugContext, "apply attribute set %s\n", curstr); #endif if (xmlValidateQName(curstr, 0)) { xsltTransformError(ctxt, NULL, inst, "The name '%s' in use-attribute-sets is not a valid " "QName.\n", curstr); return; } ncname = xsltSplitQName(ctxt->dict, curstr, &prefix); if (prefix != NULL) { ns = xmlSearchNs(inst->doc, inst, prefix); if (ns == NULL) { xsltTransformError(ctxt, NULL, inst, "use-attribute-set : No namespace found for QName " "'%s:%s'\n", prefix, ncname); return; } nsUri = ns->href; } style = ctxt->style; #ifdef WITH_DEBUGGER if ((style != NULL) && (style->attributeSets != NULL) && (ctxt->debugStatus != XSLT_DEBUG_NONE)) { set = xmlHashLookup2(style->attributeSets, ncname, nsUri); if ((set != NULL) && (set->attrs != NULL) && (set->attrs->attr != NULL)) xslHandleDebugger(set->attrs->attr->parent, node, NULL, ctxt); } #endif /* * Lookup the referenced attribute-set. All attribute sets were * moved to the top stylesheet so there's no need to iterate * imported stylesheets */ set = xmlHashLookup2(style->attributeSets, ncname, nsUri); if (set != NULL) { xsltAttrElemPtr cur = set->attrs; while (cur != NULL) { if (cur->attr != NULL) { xsltAttribute(ctxt, node, cur->attr, cur->attr->psvi); } cur = cur->next; } } } curstr = endstr; } }
void xsltParseStylesheetAttributeSet(xsltStylesheetPtr style, xmlNodePtr cur) { const xmlChar *ncname; const xmlChar *prefix; xmlChar *value; xmlNodePtr child; xsltAttrElemPtr attrItems; if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE)) return; value = xmlGetNsProp(cur, (const xmlChar *)"name", NULL); if ((value == NULL) || (*value == 0)) { xsltGenericError(xsltGenericErrorContext, "xsl:attribute-set : name is missing\n"); if (value) xmlFree(value); return; } ncname = xsltSplitQName(style->dict, value, &prefix); xmlFree(value); value = NULL; if (style->attributeSets == NULL) { #ifdef WITH_XSLT_DEBUG_ATTRIBUTES xsltGenericDebug(xsltGenericDebugContext, "creating attribute set table\n"); #endif style->attributeSets = xmlHashCreate(10); } if (style->attributeSets == NULL) return; attrItems = xmlHashLookup2(style->attributeSets, ncname, prefix); /* * Parse the content. Only xsl:attribute elements are allowed. */ child = cur->children; while (child != NULL) { /* * Report invalid nodes. */ if ((child->type != XML_ELEMENT_NODE) || (child->ns == NULL) || (! IS_XSLT_ELEM(child))) { if (child->type == XML_ELEMENT_NODE) xsltTransformError(NULL, style, child, "xsl:attribute-set : unexpected child %s\n", child->name); else xsltTransformError(NULL, style, child, "xsl:attribute-set : child of unexpected type\n"); } else if (!IS_XSLT_NAME(child, "attribute")) { xsltTransformError(NULL, style, child, "xsl:attribute-set : unexpected child xsl:%s\n", child->name); } else { #ifdef XSLT_REFACTORED xsltAttrElemPtr nextAttr, curAttr; /* * Process xsl:attribute * --------------------- */ #ifdef WITH_XSLT_DEBUG_ATTRIBUTES xsltGenericDebug(xsltGenericDebugContext, "add attribute to list %s\n", ncname); #endif /* * The following was taken over from * xsltAddAttrElemList(). */ if (attrItems == NULL) { attrItems = xsltNewAttrElem(child); } else { curAttr = attrItems; while (curAttr != NULL) { nextAttr = curAttr->next; if (curAttr->attr == child) { /* * URGENT TODO: Can somebody explain * why attrItems is set to curAttr * here? Is this somehow related to * avoidance of recursions? */ attrItems = curAttr; goto next_child; } if (curAttr->next == NULL) curAttr->next = xsltNewAttrElem(child); curAttr = nextAttr; } } /* * Parse the xsl:attribute and its content. */ xsltParseAnyXSLTElem(XSLT_CCTXT(style), child); #else #ifdef WITH_XSLT_DEBUG_ATTRIBUTES xsltGenericDebug(xsltGenericDebugContext, "add attribute to list %s\n", ncname); #endif /* * OLD behaviour: */ attrItems = xsltAddAttrElemList(attrItems, child); #endif } #ifdef XSLT_REFACTORED next_child: #endif child = child->next; } /* * Process attribue "use-attribute-sets". */ /* TODO check recursion */ value = xmlGetNsProp(cur, (const xmlChar *)"use-attribute-sets", NULL); if (value != NULL) { const xmlChar *curval, *endval; curval = value; while (*curval != 0) { while (IS_BLANK(*curval)) curval++; if (*curval == 0) break; endval = curval; while ((*endval != 0) && (!IS_BLANK(*endval))) endval++; curval = xmlDictLookup(style->dict, curval, endval - curval); if (curval) { const xmlChar *ncname2 = NULL; const xmlChar *prefix2 = NULL; xsltAttrElemPtr refAttrItems; #ifdef WITH_XSLT_DEBUG_ATTRIBUTES xsltGenericDebug(xsltGenericDebugContext, "xsl:attribute-set : %s adds use %s\n", ncname, curval); #endif ncname2 = xsltSplitQName(style->dict, curval, &prefix2); refAttrItems = xsltNewAttrElem(NULL); if (refAttrItems != NULL) { refAttrItems->set = ncname2; refAttrItems->ns = prefix2; attrItems = xsltMergeAttrElemList(style, attrItems, refAttrItems); xsltFreeAttrElem(refAttrItems); } } curval = endval; } xmlFree(value); value = NULL; } /* * Update the value */ /* * TODO: Why is this dummy entry needed.? */ if (attrItems == NULL) attrItems = xsltNewAttrElem(NULL); xmlHashUpdateEntry2(style->attributeSets, ncname, prefix, attrItems, NULL); #ifdef WITH_XSLT_DEBUG_ATTRIBUTES xsltGenericDebug(xsltGenericDebugContext, "updated attribute list %s\n", ncname); #endif }
/** * xsltMergeAttrElemList: * @list: an XSLT AttrElem list * @old: another XSLT AttrElem list * * Add all the attributes from list @old to list @list, * but drop redefinition of existing values. * * Returns the new list pointer */ static xsltAttrElemPtr xsltMergeAttrElemList(xsltStylesheetPtr style, xsltAttrElemPtr list, xsltAttrElemPtr old) { xsltAttrElemPtr cur; int add; while (old != NULL) { if ((old->attr == NULL) && (old->set == NULL)) { old = old->next; continue; } /* * Check that the attribute is not yet in the list */ cur = list; add = 1; while (cur != NULL) { if ((cur->attr == NULL) && (cur->set == NULL)) { if (cur->next == NULL) break; cur = cur->next; continue; } if ((cur->set != NULL) && (cur->set == old->set)) { add = 0; break; } if (cur->set != NULL) { if (cur->next == NULL) break; cur = cur->next; continue; } if (old->set != NULL) { if (cur->next == NULL) break; cur = cur->next; continue; } if (cur->attr == old->attr) { xsltGenericError(xsltGenericErrorContext, "xsl:attribute-set : use-attribute-sets recursion detected\n"); return(list); } if (cur->next == NULL) break; cur = cur->next; } if (add == 1) { /* * Changed to use the string-dict, rather than duplicating * @set and @ns; this fixes bug #340400. */ if (cur == NULL) { list = xsltNewAttrElem(old->attr); if (old->set != NULL) { list->set = xmlDictLookup(style->dict, old->set, -1); if (old->ns != NULL) list->ns = xmlDictLookup(style->dict, old->ns, -1); } } else if (add) { cur->next = xsltNewAttrElem(old->attr); if (old->set != NULL) { cur->next->set = xmlDictLookup(style->dict, old->set, -1); if (old->ns != NULL) cur->next->ns = xmlDictLookup(style->dict, old->ns, -1); } } } old = old->next; } return(list); }
/** * xsltApplyAttributeSet: * @ctxt: the XSLT stylesheet * @node: the node in the source tree. * @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. * 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, const xmlChar *attrSets) { const xmlChar *ncname = NULL; const xmlChar *prefix = NULL; const xmlChar *curstr, *endstr; xsltAttrElemPtr attrs; xsltStylesheetPtr style; 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; } } } /* * Parse/apply the list of QNames. */ curstr = attrSets; while (*curstr != 0) { while (IS_BLANK(*curstr)) curstr++; if (*curstr == 0) break; 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 curstrute set %s\n", curstr); #endif ncname = xsltSplitQName(ctxt->dict, curstr, &prefix); style = ctxt->style; #ifdef WITH_DEBUGGER if ((style != NULL) && (style->attributeSets != NULL) && (ctxt->debugStatus != XSLT_DEBUG_NONE)) { attrs = xmlHashLookup2(style->attributeSets, ncname, prefix); if ((attrs != NULL) && (attrs->attr != NULL)) xslHandleDebugger(attrs->attr->parent, node, NULL, ctxt); } #endif /* * Lookup the referenced curstrute-set. */ while (style != NULL) { attrs = xmlHashLookup2(style->attributeSets, ncname, prefix); while (attrs != NULL) { if (attrs->attr != NULL) { xsltAttributeInternal(ctxt, node, attrs->attr, attrs->attr->psvi, 1); } attrs = attrs->next; } style = xsltNextImport(style); } } curstr = endstr; } }
/** * 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); }
/* * xmlAddEntity : register a new entity for an entities table. */ static xmlEntityPtr xmlAddEntity(xmlDtdPtr dtd, const xmlChar *name, int type, const xmlChar *ExternalID, const xmlChar *SystemID, const xmlChar *content) { xmlDictPtr dict = NULL; xmlEntitiesTablePtr table = NULL; xmlEntityPtr ret; if (name == NULL) return(NULL); if (dtd == NULL) return(NULL); if (dtd->doc != NULL) dict = dtd->doc->dict; switch (type) { case XML_INTERNAL_GENERAL_ENTITY: case XML_EXTERNAL_GENERAL_PARSED_ENTITY: case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: if (dtd->entities == NULL) dtd->entities = xmlHashCreateDict(0, dict); table = dtd->entities; break; case XML_INTERNAL_PARAMETER_ENTITY: case XML_EXTERNAL_PARAMETER_ENTITY: if (dtd->pentities == NULL) dtd->pentities = xmlHashCreateDict(0, dict); table = dtd->pentities; break; case XML_INTERNAL_PREDEFINED_ENTITY: return(NULL); } if (table == NULL) return(NULL); ret = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity)); if (ret == NULL) { xmlEntitiesErrMemory("xmlAddEntity:: malloc failed"); return(NULL); } memset(ret, 0, sizeof(xmlEntity)); ret->type = XML_ENTITY_DECL; /* * fill the structure. */ ret->etype = (xmlEntityType) type; if (dict == NULL) { ret->name = xmlStrdup(name); if (ExternalID != NULL) ret->ExternalID = xmlStrdup(ExternalID); if (SystemID != NULL) ret->SystemID = xmlStrdup(SystemID); } else { ret->name = xmlDictLookup(dict, name, -1); if (ExternalID != NULL) ret->ExternalID = xmlDictLookup(dict, ExternalID, -1); if (SystemID != NULL) ret->SystemID = xmlDictLookup(dict, SystemID, -1); } if (content != NULL) { ret->length = xmlStrlen(content); if ((dict != NULL) && (ret->length < 5)) ret->content = (xmlChar *) xmlDictLookup(dict, content, ret->length); else ret->content = xmlStrndup(content, ret->length); } else { ret->length = 0; ret->content = NULL; } ret->URI = NULL; /* to be computed by the layer knowing the defining entity */ ret->orig = NULL; ret->owner = 0; ret->doc = dtd->doc; if (xmlHashAddEntry(table, name, ret)) { /* * entity was already defined at another level. */ xmlFreeEntity(ret); return(NULL); } return(ret); }
/** * 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; }