+Mon Jun 19 13:33:50 CEST 2006 Kasimier Buchcik <libxml2-cvs@cazic.net>
+
+ * libxslt/attributes.c libxslt/attrvt.c libxslt/namespaces.c
+ libxslt/namespaces.h libxslt/preproc.c libxslt/templates.c
+ libxslt/transform.c libxslt/variables.c libxslt/xslt.c
+ libxslt/xsltInternals.h libxslt/xsltutils.c:
+ Merged all the namespace lookup/create/disable functions
+ into xsltGetSpecialNamespace(). Changed xsltGetNamespace()
+ and xsltGetPlainNamespace() to call xsltGetSpecialNamespace(),
+ but kept the ns-aliasing mechanism; the ns-aliasing needs
+ to be removed when we move to the refactored code, which
+ applies ns-alias only at compilaton time.
+ Refactored xsltElementComp() (preproc.c); enhanced error reports.
+ Fixed: if the "namespace" attribute was not given, then this
+ performed incorrectly only a lookup for a default namespace;
+ i.e., without taking any prefix on the "name" attribute into
+ account.
+ Refactored xsltElement() (transform.c); enhanced error reports.
+ Refactored xsltAttributeComp() (preproc.c). Added namespace
+ lookup as in xsltElementComp(). Enhanced error reports.
+ Refactored xsltAttribute() (transform.c); enhanced error reports.
+ xsltCopyTreeInternal(): eliminated the need to call xmlGetNsList()
+ for every element in the tree; this needs to be done only for
+ the top-most elements. For subsequent elements reconcile only
+ the ns-declarations. Disallowed setting of ns-declarations if
+ children have been already added to an element.
+ Removed ns-aliasing code where necessary.
+ xsltCopyProp(): disallowed setting of attribute nodes if
+ children have been already added to an element.
+ xsltCopy(): removed the incorrect skipping of attributes in the
+ XSLT namespace. Removed the incorrect ns-aliasing for attributes.
+ Changed to use the introduced function xsltShallowCopyAttr().
+ xsltShallowCopyAttr(): Centralized all attribute-copy related
+ code in this function. It will now be called by
+ xsltCopyTreeInternal(), xsltCopyOf() and xsltCopy().
+ xsltCopyAttrListNoOverwrite(): Renamed. Refactored. Optimized to
+ use xsltGetSpecialNamespace() and xmlNewDocProp().
+ Further substitution of various scattered namespace-lookup
+ related code for the use of xsltGetSpecialNamespace().
+ xsltAttrTemplateProcess(): Refactored. Removed the incorrect
+ processing of attribute-sets. Attribute sets need to be applied
+ before adding any normal attribute of the literal result element;
+ this is now done in xsltAttrListTemplateProcess(). Fixed to
+ ensure that the ns-prefix of the overwriting attribute is used.
+ xsltAttrListTemplateProcess(): Refactored. Moved semantics from
+ xsltAttrTemplateProcess() over to this function in order to
+ optimize processing of multiple attributes. This does not call
+ xsltAttrTemplateProcess() anymore.
+ Fixed: do not exclude the XSLT namespace after ns-aliasing have
+ beed applied.
+ The IFDEFed-out refactored code fixes the following issues:
+ - #313711: namespace collision with namespace-alias (reported
+ by by Oleg Paraschenko)
+ - #338214: Incorrect scope for exclude-result-prefixes
+ - #341392: Excluding namespace declarations of literal result
+ elements.
+ - #341325: Namespace aliasing and resulting namespace prefixes
+ Already enabled fixes:
+ - #344183: xsl:copy misses to copy attributes in the XSLT namespace
+ - #341463: Namespace-alias using #default for result-prefix with no
+ default namespace in scope
+ - #313890: namespace collision with xsl:element and xsl:attribute,
+ reported by Oleg Paraschenko
+ - #344176: xsl:copy misses to set an element's namespace-URI in
+ some cases
+ - #305739: the "name" QName of xsl:element is incorrectly always
+ resolved to the default namespace
+
Mon Jun 12 16:34:15 CEST 2006 Daniel Veillard <daniel@veillard.com>
* doc/xsltproc.1 doc/xsltproc.xml: more info about --output
/**
* xsltAttributeInternal:
* @ctxt: a XSLT process context
- * @node: the node in the source tree.
+ * @node: the current 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,
+xsltAttributeInternal(xsltTransformContextPtr ctxt,
+ xmlNodePtr currentNode,
xmlNodePtr inst,
xsltStylePreCompPtr castedComp,
- int fromAttributeSet) {
+ 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)
- */
+ (xsltStyleItemAttributePtr) castedComp;
#else
xsltStylePreCompPtr comp = castedComp;
#endif
xmlNsPtr ns = NULL;
xmlAttrPtr attr;
- if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
+ if ((ctxt == NULL) || (currentNode == NULL) || (inst == NULL))
+ 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
/*
* 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);
+ xslHandleDebugger(inst, currentNode, NULL, ctxt);
#endif
if (comp->name == NULL) {
}
name = xsltSplitQName(ctxt->dict, prop, &prefix);
xmlFree(prop);
- } else {
- name = xsltSplitQName(ctxt->dict, comp->name, &prefix);
- }
- if (!xmlStrncasecmp(prefix, (xmlChar *) "xmlns", 5)) {
+ /*
+ * Reject a prefix of "xmlns".
+ */
+ if ((prefix != NULL) &&
+ (!xmlStrncasecmp(prefix, (xmlChar *) "xmlns", 5)))
+ {
#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltAttribute: xmlns prefix forbidden\n");
+ 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;
+ }
+
+ } else {
/*
- * 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.
+ * The "name" value was static.
*/
- goto error;
+#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) {
+ 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 {
* Saxon, Xalan-J and MSXML).
*/
xsltTransformError(ctxt, NULL, inst,
- "xsl:attribute: The effective prefix '%s', has no "
+ "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);
+ "specified by the instruction itself.\n", prefix, name);
} else
nsName = ns->href;
}
if (fromAttributeSet) {
/*
- * I think this tries to ensure that xsl:attribute(s) coming
+ * 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).
+ * URGENT TODO: This might be buggy, since it will miss to
+ * overwrite two equal attributes both from attribute sets.
*/
attr = xmlHasNsProp(targetElem, name, nsName);
if (attr != 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"
- */
- /*
* 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?
+ * 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
}
}
#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;
- }
+
+ if (nsName != NULL) {
/*
- * OK, we need to declare the namespace on the target element.
+ * 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"
*/
- 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.
+ * xsl:attribute can produce a scenario where the prefix is NULL,
+ * so generate a 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);
- }
+ if (prefix == NULL) {
+ xmlChar *pref = xmlStrdup(BAD_CAST "ns_1");
-namespace_finished:
+ ns = xsltGetSpecialNamespace(ctxt, inst, nsName, BAD_CAST 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 of the generated attribute '{%s}%s'.\n",
+ "namespace binding for the generated attribute '{%s}%s'.\n",
nsName, name);
- /*
- * TODO: Should we just stop here?
- */
+ goto error;
}
}
/*
((inst->children->type == XML_TEXT_NODE) ||
(inst->children->type == XML_CDATA_SECTION_NODE)))
{
- xmlNodePtr origTxt = inst->children, copyTxt;
+ xmlNodePtr 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.
+ * xmlSetNsProp() will take care of duplicates.
*/
attr = xmlSetNsProp(ctxt->insert, ns, name, NULL);
if (attr == NULL) /* TODO: report error ? */
* This is a safe scenario where we don't need to lookup
* the dict.
*/
- copyTxt->content = origTxt->content;
+ copyTxt->content = inst->children->content;
/*
* Copy "disable-output-escaping" information.
* TODO: Does this have any effect for attribute values
* anyway?
*/
- if (origTxt->name == xmlStringTextNoenc)
+ if (inst->children->name == xmlStringTextNoenc)
copyTxt->name = xmlStringTextNoenc;
} else {
/*
* Copy the value.
*/
- copyTxt = xmlNewText(origTxt->content);
+ copyTxt = xmlNewText(inst->children->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);
+ 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;
+
} else {
/*
* The sequence constructor might be complex, so instantiate it.
*/
- value = xsltEvalTemplateString(ctxt, node, inst);
+ value = xsltEvalTemplateString(ctxt, currentNode, 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 *) "");
* xsltApplyAttributeSet:
* @ctxt: the XSLT stylesheet
* @node: the node in the source tree.
- * @inst: the xslt attribute node
- * @attributes: the set list.
+ * @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
+ * 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 ATTRIBUTE_UNUSED,
- const xmlChar * attributes)
+ xmlNodePtr inst,
+ const xmlChar *attrSets)
{
const xmlChar *ncname = NULL;
- const xmlChar *prefix = NULL;
- const xmlChar *attrib, *endattr;
- xsltAttrElemPtr values;
- xsltStylesheetPtr style;
+ const xmlChar *prefix = NULL;
+ const xmlChar *curstr, *endstr;
+ xsltAttrElemPtr attrs;
+ xsltStylesheetPtr style;
- if (attributes == NULL) {
- return;
+ 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;
+ }
+ }
}
-
- attrib = attributes;
- while (*attrib != 0) {
- while (IS_BLANK(*attrib))
- attrib++;
- if (*attrib == 0)
+ /*
+ * Parse/apply the list of QNames.
+ */
+ curstr = attrSets;
+ while (*curstr != 0) {
+ while (IS_BLANK(*curstr))
+ curstr++;
+ if (*curstr == 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
+ 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 attribute set %s\n", attrib);
+ "apply curstrute set %s\n", curstr);
#endif
- ncname = xsltSplitQName(ctxt->dict, attrib, &prefix);
+ ncname = xsltSplitQName(ctxt->dict, curstr, &prefix);
style = ctxt->style;
+
#ifdef WITH_DEBUGGER
- if ((style != NULL) && (style->attributeSets != NULL) &&
- (ctxt->debugStatus != XSLT_DEBUG_NONE)) {
- values =
+ if ((style != NULL) &&
+ (style->attributeSets != NULL) &&
+ (ctxt->debugStatus != XSLT_DEBUG_NONE))
+ {
+ attrs =
xmlHashLookup2(style->attributeSets, ncname, prefix);
- if ((values != NULL) && (values->attr != NULL))
- xslHandleDebugger(values->attr->parent, node, NULL,
- ctxt);
+ if ((attrs != NULL) && (attrs->attr != NULL))
+ xslHandleDebugger(attrs->attr->parent, node, NULL,
+ ctxt);
}
#endif
+ /*
+ * Lookup the referenced curstrute-set.
+ */
while (style != NULL) {
- values =
+ attrs =
xmlHashLookup2(style->attributeSets, ncname, prefix);
- while (values != NULL) {
- if (values->attr != NULL) {
- xsltAttributeInternal(ctxt, node, values->attr,
- values->attr->psvi, 1);
+ while (attrs != NULL) {
+ if (attrs->attr != NULL) {
+ xsltAttributeInternal(ctxt, node, attrs->attr,
+ attrs->attr->psvi, 1);
}
- values = values->next;
+ attrs = attrs->next;
}
style = xsltNextImport(style);
}
}
- attrib = endattr;
+ curstr = endstr;
}
}
if ((attr->children->type != XML_TEXT_NODE) ||
(attr->children->next != NULL)) {
xsltTransformError(NULL, style, attr->parent,
- "Attribute %s content is not a text node\n", attr->name);
+ "Attribute '%s': The content is expected to be a single text "
+ "node when compiling an AVT.\n", attr->name);
style->errors++;
return;
}
#endif
return;
}
+ /*
+ * Create a new AVT object.
+ */
avt = xsltNewAttrVT(style);
- if (avt == NULL) return;
+ if (avt == NULL)
+ return;
attr->psvi = avt;
avt->nsList = xmlGetNsList(attr->doc, attr->parent);
}
if (*(cur+1) == '}') { /* skip empty AVT */
ret = xmlStrncat(ret, str, cur - str);
- cur+=2;
+ cur += 2;
str = cur;
continue;
}
str = cur;
if (avt->nb_seg == 0)
avt->strstart = 1;
- if ((avt=xsltSetAttrVTsegment(avt, (void *) ret)) == NULL)
+ if ((avt = xsltSetAttrVTsegment(avt, (void *) ret)) == NULL)
goto error;
ret = NULL;
lastavt = 0;
while ((*cur != 0) && (*cur != '}')) cur++;
if (*cur == 0) {
xsltTransformError(NULL, style, attr->parent,
- "Attribute template %s: unmatched '{'\n", attr->name);
+ "Attribute '%s': The AVT has an unmatched '{'.\n",
+ attr->name);
style->errors++;
goto error;
}
str++;
expr = xmlStrndup(str, cur - str);
if (expr == NULL) {
+ /*
+ * TODO: What needs to be done here?
+ */
XSLT_TODO
goto error;
} else {
comp = xsltXPathCompile(style, expr);
if (comp == NULL) {
xsltTransformError(NULL, style, attr->parent,
- "Attribute template %s: failed to compile %s\n",
- attr->name, expr);
+ "Attribute '%s': Failed to compile the expression "
+ "'%s' in the AVT.\n", attr->name, expr);
style->errors++;
goto error;
}
if (avt->nb_seg == 0)
avt->strstart = 0;
if (lastavt == 1) {
- if ((avt=xsltSetAttrVTsegment(avt, NULL)) == NULL)
+ if ((avt = xsltSetAttrVTsegment(avt, NULL)) == NULL)
goto error;
}
- if ((avt=xsltSetAttrVTsegment(avt, (void *) comp))==NULL)
+ if ((avt = xsltSetAttrVTsegment(avt, (void *) comp)) == NULL)
goto error;
lastavt = 1;
xmlFree(expr);
continue;
} else {
xsltTransformError(NULL, style, attr->parent,
- "Attribute template %s: unmatched '}'\n", attr->name);
+ "Attribute '%s': The AVT has an unmatched '}'.\n",
+ attr->name);
goto error;
}
} else
str = cur;
if (avt->nb_seg == 0)
avt->strstart = 1;
- if ((avt=xsltSetAttrVTsegment(avt, (void *) ret)) == NULL)
+ if ((avt = xsltSetAttrVTsegment(avt, (void *) ret)) == NULL)
goto error;
ret = NULL;
}
*/
- /*
- * Store the ns-node in the alias-object.
- */
- alias = xsltNewNsAlias(XSLT_CCTXT(style));
- if (alias == NULL)
- return;
- alias->literalNs = literalNs;
- alias->targetNs = targetNs;
- XSLT_CCTXT(style)->hasNsAliases = 1;
+ /*
+ * Store the ns-node in the alias-object.
+ */
+ alias = xsltNewNsAlias(XSLT_CCTXT(style));
+ if (alias == NULL)
+ return;
+ alias->literalNs = literalNs;
+ alias->targetNs = targetNs;
+ XSLT_CCTXT(style)->hasNsAliases = 1;
#else /* XSLT_REFACTORED */
}
/**
- * xsltNsInScope:
- * @doc: the document
- * @node: the current node
- * @ancestor: the ancestor carrying the namespace
- * @prefix: the namespace prefix
- *
- * Copy of xmlNsInScope which is not public ...
- *
- * Returns 1 if true, 0 if false and -1 in case of error.
- */
-static int
-xsltNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
- xmlNodePtr ancestor, const xmlChar * prefix)
-{
- xmlNsPtr tst;
-
- while ((node != NULL) && (node != ancestor)) {
- if ((node->type == XML_ENTITY_REF_NODE) ||
- (node->type == XML_ENTITY_NODE) ||
- (node->type == XML_ENTITY_DECL))
- return (-1);
- if (node->type == XML_ELEMENT_NODE) {
- tst = node->nsDef;
- while (tst != NULL) {
- if ((tst->prefix == NULL)
- && (prefix == NULL))
- return (0);
- if ((tst->prefix != NULL)
- && (prefix != NULL)
- && (xmlStrEqual(tst->prefix, prefix)))
- return (0);
- tst = tst->next;
- }
- }
- node = node->parent;
- }
- if (node != ancestor)
- return (-1);
- return (1);
-}
-
-/**
- * xsltSearchPlainNsByHref:
- * @doc: the document
- * @node: the current node
- * @href: the namespace value
- *
- * Search a Ns aliasing a given URI and without a NULL prefix.
- * Recurse on the parents until it finds
- * the defined namespace or return NULL otherwise.
- * Returns the namespace pointer or NULL.
- */
-static xmlNsPtr
-xsltSearchPlainNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
-{
- xmlNsPtr cur;
- xmlNodePtr orig = node;
-
- if ((node == NULL) || (href == NULL))
- return (NULL);
-
- while (node != NULL) {
- if ((node->type == XML_ENTITY_REF_NODE) ||
- (node->type == XML_ENTITY_NODE) ||
- (node->type == XML_ENTITY_DECL))
- return (NULL);
- if (node->type == XML_ELEMENT_NODE) {
- cur = node->nsDef;
- while (cur != NULL) {
- if ((cur->href != NULL) && (cur->prefix != NULL) &&
- (href != NULL) && (xmlStrEqual(cur->href, href))) {
- if (xsltNsInScope(doc, orig, node, cur->href) == 1)
- return (cur);
- }
- cur = cur->next;
- }
- if (orig != node) {
- cur = node->ns;
- if (cur != NULL) {
- if ((cur->href != NULL) && (cur->prefix != NULL) &&
- (href != NULL) && (xmlStrEqual(cur->href, href))) {
- if (xsltNsInScope(doc, orig, node, cur->href) == 1)
- return (cur);
- }
- }
- }
- }
- node = node->parent;
- }
- return (NULL);
-}
-
-/**
- * xsltGetPlainNamespace:
- * @ctxt: a transformation context
- * @cur: the input node
- * @ns: the namespace
- * @out: the output node (or its parent)
+ * xsltGetSpecialNamespace:
+ * @ctxt: the transformation context
+ * @invocNode: the invoking node; e.g. a literal result element/attr;
+ * only used for error reports
+ * @nsName: the namespace name (or NULL)
+ * @nsPrefix: the suggested namespace prefix (or NULL)
+ * @target: the result element on which to anchor a namespace
*
- * Find the right namespace value for this prefix, if needed create
- * and add a new namespace decalaration on the node
- * Handle namespace aliases and make sure the prefix is not NULL, this
- * is needed for attributes.
- * Called from:
- * xsltAttrTemplateProcess() (templates.c)
- * xsltCopyProp() (transform.c)
+ * Find a matching (prefix and ns-name) ns-declaration
+ * for the requested @nsName and @nsPrefix in the result tree.
+ * If none is found then a new ns-declaration will be
+ * added to @resultElem. If, in this case, the given prefix is
+ * already in use, then a ns-declaration with a modified ns-prefix
+ * be we created. Note that this function's priority is to
+ * preserve ns-prefixes; it will only change a prefix if there's
+ * a namespace clash.
+ * If both @nsName and @nsPrefix are NULL, then this will try to
+ * "undeclare" a default namespace by declaring an xmlns="".
*
- * Returns the namespace node to use or NULL
+ * Returns a namespace declaration or NULL.
*/
xmlNsPtr
-xsltGetPlainNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur,
- xmlNsPtr ns, xmlNodePtr out) {
- xmlNsPtr ret;
- const xmlChar *URI = NULL; /* the replacement URI */
+xsltGetSpecialNamespace(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
+ const xmlChar *nsName, const xmlChar *nsPrefix,
+ xmlNodePtr target)
+{
+ xmlNsPtr ns;
+ int prefixOccupied = 0;
- if ((ctxt == NULL) || (cur == NULL) || (out == NULL) || (ns == NULL))
+ if ((ctxt == NULL) || (target == NULL) ||
+ (target->type != XML_ELEMENT_NODE))
return(NULL);
-#ifdef XSLT_REFACTORED
/*
- * Namespace exclusion and ns-aliasing is performed at
- * compilation-time in the refactored code.
+ * NOTE: Namespace exclusion and ns-aliasing is performed at
+ * compilation-time in the refactored code; so this need not be done
+ * here (it was in the old code).
+ * NOTE: @invocNode was named @cur in the old code and was documented to
+ * be an input node; since it was only used to anchor an error report
+ * somewhere, we can safely change this to @invocNode, which now
+ * will be the XSLT instruction (also a literal result element/attribute),
+ * which was responsible for this call.
*/
- URI = ns->href;
-#else
- {
- xsltStylesheetPtr style;
- style = ctxt->style;
- while (style != NULL) {
- if (style->nsAliases != NULL)
- URI = (const xmlChar *) xmlHashLookup(style->nsAliases, ns->href);
- if (URI != NULL)
- break;
+ /*
+ * OPTIMIZE TODO: This all could be optimized by keeping track of
+ * the ns-decls currently in-scope via a specialized context.
+ */
+ if ((nsPrefix == NULL) && ((nsName == NULL) || (nsName[0] == 0))) {
+ /*
+ * NOTE: the "undeclaration" of the default namespace was
+ * part of the logic of the old xsltGetSpecialNamespace() code,
+ * so we'll keep that mechanism.
+ * Related to the old code: bug #302020:
+ */
+ /*
+ * OPTIMIZE TODO: This all could be optimized by keeping track of
+ * the ns-decls currently in-scope via a specialized context.
+ */
+ /*
+ * Search on the result element itself.
+ */
+ if (target->nsDef != NULL) {
+ ns = target->nsDef;
+ do {
+ if (ns->prefix == NULL) {
+ if ((ns->href != NULL) && (ns->href[0] != 0)) {
+ /*
+ * Raise a namespace normalization error.
+ */
+ xsltTransformError(ctxt, NULL, invocNode,
+ "Namespace normalization error: Cannot undeclare "
+ "the default namespace, since the default namespace "
+ "'%s' is already declared on the result element "
+ "'%s'.\n", ns->href, target->name);
+ return(NULL);
+ } else {
+ /*
+ * The default namespace was undeclared on the
+ * result element.
+ */
+ return(NULL);
+ }
+ break;
+ }
+ ns = ns->next;
+ } while (ns != NULL);
+ }
+ if ((target->parent != NULL) &&
+ (target->parent->type == XML_ELEMENT_NODE))
+ {
+ /*
+ * The parent element is in no namespace, so assume
+ * that there is no default namespace in scope.
+ */
+ if (target->parent->ns == NULL)
+ return(NULL);
- style = xsltNextImport(style);
+ ns = xmlSearchNs(target->doc, target->parent,
+ NULL);
+ /*
+ * Fine if there's no default ns is scope, or if the
+ * default ns was undeclared.
+ */
+ if ((ns == NULL) || (ns->href == NULL) || (ns->href[0] == 0))
+ return(NULL);
+
+ /*
+ * Undeclare the default namespace.
+ */
+ xmlNewNs(target, BAD_CAST "", NULL);
+ /* TODO: Check result */
+ return(NULL);
}
+ return(NULL);
}
-
- if (URI == UNDEFINED_DEFAULT_NS) {
- xmlNsPtr dflt;
- dflt = xmlSearchNs(cur->doc, cur, NULL);
- if (dflt == NULL)
- return NULL;
- else
- URI = dflt->href;
+ /*
+ * Handle the XML namespace.
+ * QUESTION: Is this faster than using xmlStrEqual() anyway?
+ */
+ if ((nsPrefix != NULL) &&
+ (nsPrefix[0] == 'x') && (nsPrefix[1] == 'm') &&
+ (nsPrefix[2] == 'l') && (nsPrefix[3] == 0))
+ {
+ return(xmlSearchNs(target->doc, target, nsPrefix));
}
-
- if (URI == NULL)
- URI = ns->href;
-#endif
-
- if ((out->parent != NULL) &&
- (out->parent->type == XML_ELEMENT_NODE) &&
- (out->parent->ns != NULL) &&
- (out->parent->ns->prefix != NULL) &&
- (xmlStrEqual(out->parent->ns->href, URI)))
- ret = out->parent->ns;
- else {
- if (ns->prefix != NULL) {
- ret = xmlSearchNs(out->doc, out, ns->prefix);
- if ((ret == NULL) || (!xmlStrEqual(ret->href, URI)) ||
- (ret->prefix == NULL)) {
- ret = xsltSearchPlainNsByHref(out->doc, out, URI);
+ /*
+ * First: search on the result element itself.
+ */
+ if (target->nsDef != NULL) {
+ ns = target->nsDef;
+ do {
+ if ((ns->prefix == NULL) == (nsPrefix == NULL)) {
+ if (ns->prefix == nsPrefix) {
+ if (xmlStrEqual(ns->href, nsName))
+ return(ns);
+ prefixOccupied = 1;
+ break;
+ } else if (xmlStrEqual(ns->prefix, nsPrefix)) {
+ if (xmlStrEqual(ns->href, nsName))
+ return(ns);
+ prefixOccupied = 1;
+ break;
+ }
}
- } else {
- ret = xsltSearchPlainNsByHref(out->doc, out, URI);
- }
- }
-
- if (ret == NULL) {
- if (out->type == XML_ELEMENT_NODE)
- ret = xmlNewNs(out, URI, ns->prefix);
+ ns = ns->next;
+ } while (ns != NULL);
}
- return(ret);
-}
-
-/**
- * xsltGetSpecialNamespace:
- * @ctxt: a transformation context
- * @cur: the input node
- * @URI: the namespace URI
- * @prefix: the suggested prefix
- * @out: the output node (or its parent)
- *
- * Find the right namespace value for this URI, if needed create
- * and add a new namespace decalaration on the node
- *
- * Returns the namespace node to use or NULL
- */
-xmlNsPtr
-xsltGetSpecialNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur,
- const xmlChar *URI, const xmlChar *prefix, xmlNodePtr out) {
- xmlNsPtr ret;
- static int prefixno = 1;
- char nprefix[10];
-
- if ((ctxt == NULL) || (cur == NULL) || (out == NULL) || (URI == NULL))
- return(NULL);
-
- if ((prefix == NULL) && (URI[0] == 0)) {
+ if (prefixOccupied) {
/*
- * This tries to "undeclare" a default namespace.
- * This fixes a part of bug #302020:
- * 1) Added a check whether the queried ns-decl
- * is already an "undeclaration" of the default
- * namespace.
- * 2) This fires an error if the default namespace
- * couldn't be "undeclared".
+ * If the ns-prefix is occupied by an other ns-decl on the
+ * result element, then this means:
+ * 1) The desired prefix is shadowed
+ * 2) There's no way around changing the prefix
+ *
+ * Try a desperate search for an in-scope ns-decl
+ * with a matching ns-name before we use the last option,
+ * which is to recreate the ns-decl with a modified prefix.
*/
- ret = xmlSearchNs(out->doc, out, NULL);
- if ((ret == NULL) ||
- (ret->href == NULL) || (ret->href[0] == 0))
- return(ret);
-
- if (ret != NULL) {
- xmlNsPtr newns;
-
- newns = xmlNewNs(out, URI, prefix);
- if (newns == NULL) {
- xsltTransformError(ctxt, NULL, cur,
- "Namespace fixup error: Failed to undeclare "
- "the default namespace '%s'.\n",
- ret->href);
+ ns = xmlSearchNsByHref(target->doc, target, nsName);
+ if (ns != NULL)
+ return(ns);
+
+ /*
+ * Fallback to changing the prefix.
+ */
+ } else if ((target->parent != NULL) &&
+ (target->parent->type == XML_ELEMENT_NODE))
+ {
+ /*
+ * Try to find a matching ns-decl in the ancestor-axis.
+ *
+ * Check the common case: The parent element of the current
+ * result element is in the same namespace (with an equal ns-prefix).
+ */
+ if ((target->parent->ns != NULL) &&
+ ((target->parent->ns->prefix != NULL) == (nsPrefix != NULL)))
+ {
+ ns = target->parent->ns;
+
+ if (nsPrefix == NULL) {
+ if (xmlStrEqual(ns->href, nsName))
+ return(ns);
+ } else if (xmlStrEqual(ns->prefix, nsPrefix) &&
+ xmlStrEqual(ns->href, nsName))
+ {
+ return(ns);
+ }
+ }
+ /*
+ * Lookup the remaining in-scope namespaces.
+ */
+ ns = xmlSearchNs(target->doc, target->parent, nsPrefix);
+ if (ns != NULL) {
+ if (xmlStrEqual(ns->href, nsName))
+ return(ns);
+ /*
+ * Now check for a nasty case: We need to ensure that the new
+ * ns-decl won't shadow a prefix in-use by an existing attribute.
+ * <foo xmlns:a="urn:test:a">
+ * <bar a:a="val-a">
+ * <xsl:attribute xmlns:a="urn:test:b" name="a:b">
+ * val-b</xsl:attribute>
+ * </bar>
+ * </foo>
+ */
+ if (target->properties) {
+ xmlAttrPtr attr = target->properties;
+ do {
+ if ((attr->ns) &&
+ xmlStrEqual(attr->ns->prefix, nsPrefix))
+ {
+ /*
+ * Bad, this prefix is already in use.
+ * Since we'll change the prefix anyway, try
+ * a search for a matching ns-decl based on the
+ * namespace name.
+ */
+ ns = xmlSearchNsByHref(target->doc, target, nsName);
+ if (ns != NULL)
+ return(ns);
+ goto declare_new_prefix;
+ }
+ attr = attr->next;
+ } while (attr != NULL);
}
+ } else {
/*
- * TODO: Why does this try to return an xmlns="" at all?
+ * Either no matching ns-prefix was found or the namespace is
+ * shadowed.
+ * Create a new ns-decl on the current result element.
+ *
+ * Hmm, we could also try to reuse an in-scope
+ * namespace with a matching ns-name but a different
+ * ns-prefix.
+ * What has higher priority?
+ * 1) If keeping the prefix: create a new ns-decl.
+ * 2) If reusal: first lookup ns-names; then fallback
+ * to creation of a new ns-decl.
+ * REVISIT: this currently uses case 1) although
+ * the old way was use xmlSearchNsByHref() and to let change
+ * the prefix.
*/
- return(newns);
+#if 0
+ ns = xmlSearchNsByHref(target->doc, target, nsName);
+ if (ns != NULL)
+ return(ns);
+#endif
}
- return(NULL);
+ /*
+ * Create the ns-decl on the current result element.
+ */
+ ns = xmlNewNs(target, nsName, nsPrefix);
+ /* TODO: check errors */
+ return(ns);
+ } else {
+ /*
+ * This is either the root of the tree or something weird is going on.
+ */
+ ns = xmlNewNs(target, nsName, nsPrefix);
+ /* TODO: Check result */
+ return(ns);
}
- if ((out->parent != NULL) &&
- (out->parent->type == XML_ELEMENT_NODE) &&
- (out->parent->ns != NULL) &&
- (xmlStrEqual(out->parent->ns->href, URI)))
+declare_new_prefix:
+ /*
+ * Fallback: we need to generate a new prefix and declare the namespace
+ * on the result element.
+ */
{
- ret = out->parent->ns;
- } else
- ret = xmlSearchNsByHref(out->doc, out, URI);
-
- if ((ret == NULL) || (ret->prefix == NULL)) {
- if (prefix == NULL) {
- do {
- sprintf(nprefix, "ns%d", prefixno++);
- ret = xmlSearchNs(out->doc, out, (xmlChar *)nprefix);
- } while (ret != NULL);
- prefix = (const xmlChar *) &nprefix[0];
- } else if ((ret != NULL) && (ret->prefix == NULL)) {
- /* found ns but no prefix - search for the prefix */
- ret = xmlSearchNs(out->doc, out, prefix);
- if (ret != NULL)
- return(ret); /* found it */
- }
- if (out->type == XML_ELEMENT_NODE)
- ret = xmlNewNs(out, URI, prefix);
+ xmlChar pref[30];
+ int counter = 1;
+
+ do {
+ snprintf((char *) pref, 30, "%s_%d", nsPrefix, counter++);
+ ns = xmlSearchNs(target->doc, target, BAD_CAST pref);
+ if (counter > 1000) {
+ xsltTransformError(ctxt, NULL, invocNode,
+ "Internal error in xsltAcquireResultInScopeNs(): "
+ "Failed to compute a unique ns-prefix for the "
+ "generated element");
+ return(NULL);
+ }
+ } while (ns != NULL);
+ ns = xmlNewNs(target, nsName, BAD_CAST pref);
+ /* TODO: Check result */
+ return(ns);
}
- return(ret);
+ return(NULL);
}
/**
* @ns: the namespace
* @out: the output node (or its parent)
*
- * REFACTORED NOTE: Won't be used anymore in the refactored code
- * for literal result elements/attributes.
+ * Find a matching (prefix and ns-name) ns-declaration
+ * for the requested @ns->prefix and @ns->href in the result tree.
+ * If none is found then a new ns-declaration will be
+ * added to @resultElem. If, in this case, the given prefix is
+ * already in use, then a ns-declaration with a modified ns-prefix
+ * be we created.
*
- * Find the right namespace value for this prefix, if needed create
- * and add a new namespace decalaration on the node
- * Handle namespace aliases
+ * Called by:
+ * - xsltCopyPropList() (*not* anymore)
+ * - xsltShallowCopyElement()
+ * - xsltCopyTreeInternal() (*not* anymore)
+ * - xsltApplyOneTemplateInt() (*not* in the refactored code),
+ * - xsltElement() (*not* anymore)
*
- * Returns the namespace node to use or NULL
+ * Returns a namespace declaration or NULL in case of
+ * namespace fixup failures or API or internal errors.
*/
xmlNsPtr
xsltGetNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur, xmlNsPtr ns,
- xmlNodePtr out) {
- xmlNsPtr ret;
- const xmlChar *URI = NULL; /* the replacement URI */
-
- if ((ctxt == NULL) || (cur == NULL) || (out == NULL) || (ns == NULL))
- return(NULL);
+ xmlNodePtr out)
+{
+ if (ns == NULL)
+ return(NULL);
+
#ifdef XSLT_REFACTORED
/*
* Namespace exclusion and ns-aliasing is performed at
- * compilation-time in the refactored code.
+ * compilation-time in the refactored code.
+ * Additionally, aliasing is not intended for non Literal
+ * Result Elements.
*/
- URI = ns->href;
+ return(xsltGetSpecialNamespace(ctxt, cur, ns->href, ns->prefix, out));
#else
{
xsltStylesheetPtr style;
+ const xmlChar *URI = NULL; /* the replacement URI */
+
+ if ((ctxt == NULL) || (cur == NULL) || (out == NULL))
+ return(NULL);
+
style = ctxt->style;
while (style != NULL) {
if (style->nsAliases != NULL)
style = xsltNextImport(style);
}
- }
-
- if (URI == UNDEFINED_DEFAULT_NS) {
- xmlNsPtr dflt;
- /*
- */
- dflt = xmlSearchNs(cur->doc, cur, NULL);
- if (dflt != NULL)
- URI = dflt->href;
- else
- return NULL;
- } else if (URI == NULL)
- URI = ns->href;
+
+
+ if (URI == UNDEFINED_DEFAULT_NS) {
+ return(xsltGetSpecialNamespace(ctxt, cur, NULL, NULL, out));
+#if 0
+ /*
+ * TODO: Removed, since wrong. If there was no default
+ * namespace in the stylesheet then this must resolve to
+ * the NULL namespace.
+ */
+ xmlNsPtr dflt;
+ dflt = xmlSearchNs(cur->doc, cur, NULL);
+ if (dflt != NULL)
+ URI = dflt->href;
+ else
+ return NULL;
#endif
- /*
- * If the parent is an XML_ELEMENT_NODE, and has the "equivalent"
- * namespace as ns (either both default, or both with a prefix
- * with the same href) then return the parent's ns record
- */
- if ((out->parent != NULL) &&
- (out->parent->type == XML_ELEMENT_NODE) &&
- (out->parent->ns != NULL) &&
- (((out->parent->ns->prefix == NULL) && (ns->prefix == NULL)) ||
- ((out->parent->ns->prefix != NULL) && (ns->prefix != NULL))) &&
- (xmlStrEqual(out->parent->ns->href, URI)))
- ret = out->parent->ns;
- else {
- /*
- * do a standard namespace search for ns in the output doc
- */
- ret = xmlSearchNs(out->doc, out, ns->prefix);
- if ((ret != NULL) && (!xmlStrEqual(ret->href, URI)))
- ret = NULL;
+ } else if (URI == NULL)
+ URI = ns->href;
- /*
- * if the search fails and it's not for the default prefix
- * do a search by href
- */
- if ((ret == NULL) && (ns->prefix != NULL))
- ret = xmlSearchNsByHref(out->doc, out, URI);
+ return(xsltGetSpecialNamespace(ctxt, cur, URI, ns->prefix, out));
}
+#endif
+}
- /*
- * For an element node, if we don't find it, or it's the default
- * and this element already defines a default (bug 165560), we need to
- * create it.
- */
- if (out->type == XML_ELEMENT_NODE) {
- if ((ret == NULL) || ((ret->prefix == NULL) && (out->ns == NULL) &&
- (out->nsDef != NULL) && (!xmlStrEqual(URI, out->nsDef->href)))) {
- ret = xmlNewNs(out, URI, ns->prefix);
- }
- }
- return(ret);
+/**
+ * xsltGetPlainNamespace:
+ * @ctxt: a transformation context
+ * @cur: the input node
+ * @ns: the namespace
+ * @out: the result element
+ *
+ * Obsolete.
+ * *Not* called by any Libxslt/Libexslt function.
+ * Exaclty the same as xsltGetNamespace().
+ *
+ * Returns a namespace declaration or NULL in case of
+ * namespace fixup failures or API or internal errors.
+ */
+xmlNsPtr
+xsltGetPlainNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur,
+ xmlNsPtr ns, xmlNodePtr out)
+{
+ return(xsltGetNamespace(ctxt, cur, ns, out));
}
/**
* new namespaces are added automatically. This handles namespaces
* aliases.
* This function is intended only for *internal* use at
- * transformation-time. Use it *only* for copying ns-decls of
- * literal result elements.
+ * transformation-time for copying ns-declarations of Literal
+ * Result Elements.
*
* Called by:
- * xsltCopyTree() (transform.c)
- * xsltCopyNode() (transform.c)
+ * xsltCopyTreeInternal() (transform.c)
+ * xsltShallowCopyElem() (transform.c)
+ *
+ * REVISIT: This function won't be used in the refactored code.
*
* Returns: a new xmlNsPtr, or NULL in case of error.
*/
p = q;
}
#else
+ /*
+ * TODO: Remove this if the refactored code gets enabled.
+ */
if (!xmlStrEqual(cur->href, XSLT_NAMESPACE)) {
const xmlChar *URI;
/* TODO apply cascading */
/**
* xsltCopyNamespace:
* @ctxt: a transformation context
- * @node: the target node
- * @cur: the namespace node
+ * @elem: the target element node
+ * @ns: the namespace node
*
- * Do a copy of an namespace node. If @node is non-NULL the
- * new namespaces are added automatically. This handles namespaces
- * aliases
+ * Copies a namespace node (declaration). If @elem is not NULL,
+ * then the new namespace will be declared on @elem.
*
- * Returns: a new xmlNsPtr, or NULL in case of error.
+ * Returns: a new xmlNsPtr, or NULL in case of an error.
*/
xmlNsPtr
-xsltCopyNamespace(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xmlNsPtr cur) {
- xmlNsPtr ret = NULL;
-
- if (cur == NULL)
+xsltCopyNamespace(xsltTransformContextPtr ctxt, xmlNodePtr elem,
+ xmlNsPtr ns)
+{
+ if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
return(NULL);
- if (cur->type != XML_NAMESPACE_DECL)
- return(NULL);
-
/*
* One can add namespaces only on element nodes
*/
- if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
- node = NULL;
-
-#ifdef XSLT_REFACTORED
- /*
- * Namespace exclusion and ns-aliasing is performed at
- * compilation-time in the refactored code.
- */
- ret = xmlNewNs(node, cur->href, cur->prefix);
-#else
- if (!xmlStrEqual(cur->href, XSLT_NAMESPACE)) {
- const xmlChar *URI;
-
- URI = (const xmlChar *) xmlHashLookup(ctxt->style->nsAliases,
- cur->href);
- if (URI == UNDEFINED_DEFAULT_NS)
- return(NULL);
- if (URI != NULL) {
- ret = xmlNewNs(node, URI, cur->prefix);
- } else {
- ret = xmlNewNs(node, cur->href, cur->prefix);
- }
- }
-#endif
- return(ret);
+ if ((elem != NULL) && (elem->type != XML_ELEMENT_NODE))
+ return(xmlNewNs(NULL, ns->href, ns->prefix));
+ else
+ return(xmlNewNs(elem, ns->href, ns->prefix));
}
xmlNodePtr out);
XSLTPUBFUN xmlNsPtr XSLTCALL
xsltCopyNamespace (xsltTransformContextPtr ctxt,
- xmlNodePtr node,
- xmlNsPtr cur);
+ xmlNodePtr elem,
+ xmlNsPtr ns);
XSLTPUBFUN xmlNsPtr XSLTCALL
xsltCopyNamespaceList (xsltTransformContextPtr ctxt,
xmlNodePtr node,
inst->psvi = comp;
comp->inst = inst;
+ /*
+ * Attribute "name".
+ */
+ /*
+ * TODO: Precompile the AVT. See bug #344894.
+ */
comp->name = xsltEvalStaticAttrValueTemplate(style, inst,
- (const xmlChar *)"name",
- NULL, &comp->has_name);
- if (comp->name != NULL) {
- if (xmlValidateQName(comp->name, 0)) {
- xsltTransformError(NULL, style, inst,
- "xsl:element : invalid name\n");
- if (style != NULL) style->errors++;
- }
+ (const xmlChar *)"name", NULL, &comp->has_name);
+ if (! comp->has_name) {
+ xsltTransformError(NULL, style, inst,
+ "xsl:element: The attribute 'name' is missing.\n");
+ style->errors++;
+ goto error;
}
+ /*
+ * Attribute "namespace".
+ */
+ /*
+ * TODO: Precompile the AVT. See bug #344894.
+ */
comp->ns = xsltEvalStaticAttrValueTemplate(style, inst,
- (const xmlChar *)"namespace",
- NULL, &comp->has_ns);
- if (comp->has_ns == 0) {
- xmlNsPtr defaultNs;
-
- defaultNs = xmlSearchNs(inst->doc, inst, NULL);
- if (defaultNs != NULL) {
- comp->ns = xmlDictLookup(style->dict, defaultNs->href, -1);
- comp->has_ns = 1;
+ (const xmlChar *)"namespace", NULL, &comp->has_ns);
+
+ if (comp->name != NULL) {
+ if (xmlValidateQName(comp->name, 0)) {
+ xsltTransformError(NULL, style, inst,
+ "xsl:element: The value '%s' of the attribute 'name' is "
+ "not a valid QName.\n", comp->name);
+ style->errors++;
+ } else {
+ const xmlChar *prefix = NULL, *name;
+
+ name = xsltSplitQName(style->dict, comp->name, &prefix);
+ if (comp->has_ns == 0) {
+ xmlNsPtr ns;
+
+ /*
+ * 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:element element, including any default
+ * namespace declaration.
+ */
+ ns = xmlSearchNs(inst->doc, inst, prefix);
+ if (ns != NULL) {
+ comp->ns = xmlDictLookup(style->dict, ns->href, -1);
+ comp->has_ns = 1;
+#ifdef XSLT_REFACTORED
+ comp->nsPrefix = prefix;
+ comp->name = name;
+#endif
+ } else if (prefix != NULL) {
+ xsltTransformError(NULL, style, inst,
+ "xsl:element: The prefixed QName '%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", comp->name);
+ style->errors++;
+ }
+ }
+ if ((prefix != NULL) &&
+ (!xmlStrncasecmp(prefix, (xmlChar *)"xml", 3)))
+ {
+ /*
+ * Mark is to be skipped.
+ */
+ comp->has_name = 0;
+ }
}
- }
+ }
+ /*
+ * Attribute "use-attribute-sets",
+ */
comp->use = xsltEvalStaticAttrValueTemplate(style, inst,
(const xmlChar *)"use-attribute-sets",
NULL, &comp->has_use);
+
+error:
+ return;
}
/**
return;
#ifdef XSLT_REFACTORED
- comp = (xsltStyleItemAttributePtr) xsltNewStylePreComp(style, XSLT_FUNC_ATTRIBUTE);
+ comp = (xsltStyleItemAttributePtr) xsltNewStylePreComp(style,
+ XSLT_FUNC_ATTRIBUTE);
#else
comp = xsltNewStylePreComp(style, XSLT_FUNC_ATTRIBUTE);
#endif
comp->inst = inst;
/*
- * TODO: more computation can be done there, especially namespace lookup
- */
+ * Attribute "name".
+ */
+ /*
+ * TODO: Precompile the AVT. See bug #344894.
+ */
comp->name = xsltEvalStaticAttrValueTemplate(style, inst,
(const xmlChar *)"name",
NULL, &comp->has_name);
+ if (! comp->has_name) {
+ xsltTransformError(NULL, style, inst,
+ "xsl:attribute: The attribute 'name' is missing.\n");
+ style->errors++;
+ return;
+ }
+ /*
+ * Attribute "namespace".
+ */
+ /*
+ * TODO: Precompile the AVT. See bug #344894.
+ */
+ comp->ns = xsltEvalStaticAttrValueTemplate(style, inst,
+ (const xmlChar *)"namespace",
+ NULL, &comp->has_ns);
+
if (comp->name != NULL) {
if (xmlValidateQName(comp->name, 0)) {
xsltTransformError(NULL, style, inst,
- "xsl:attribute : invalid QName\n");
- if (style != NULL) style->errors++;
- }
+ "xsl:attribute: The value '%s' of the attribute 'name' is "
+ "not a valid QName.\n", comp->name);
+ style->errors++;
+ } else {
+ const xmlChar *prefix = NULL, *name;
+
+ name = xsltSplitQName(style->dict, comp->name, &prefix);
+ if (prefix != NULL) {
+ if (comp->has_ns == 0) {
+ xmlNsPtr ns;
+
+ /*
+ * 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:element
+ * element, including any default namespace declaration.
+ */
+ ns = xmlSearchNs(inst->doc, inst, prefix);
+ if (ns != NULL) {
+ comp->ns = xmlDictLookup(style->dict, ns->href, -1);
+ comp->has_ns = 1;
+#ifdef XSLT_REFACTORED
+ comp->nsPrefix = prefix;
+ comp->name = name;
+#endif
+ } else {
+ xsltTransformError(NULL, style, inst,
+ "xsl:attribute: The prefixed QName '%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", comp->name);
+ style->errors++;
+ }
+ }
+ if (!xmlStrncasecmp(prefix, (xmlChar *) "xmlns", 5)) {
+ /*
+ * 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."
+ *
+ * Reject a prefix of "xmlns". Mark to be skipped.
+ */
+ comp->has_name = 0;
+
+#ifdef WITH_XSLT_DEBUG_PARSING
+ xsltGenericDebug(xsltGenericDebugContext,
+ "xsltAttribute: xmlns prefix forbidden\n");
+#endif
+ return;
+ }
+
+ }
+ }
}
- comp->ns = xsltEvalStaticAttrValueTemplate(style, inst,
- (const xmlChar *)"namespace",
- NULL, &comp->has_ns);
-
}
/**
/**
* xsltEvalTemplateString:
* @ctxt: the XSLT transformation context
- * @node: the stylesheet node
+ * @currentNode: the current node in the source tree
* @parent: the content parent
*
- * Evaluate a template string value, i.e. the parent list is interpreter
+ * Evaluate a template string value, i.e. the parent list is interpreted
* as template content and the resulting tree string value is returned
* This is needed for example by xsl:comment and xsl:processing-instruction
*
* caller.
*/
xmlChar *
-xsltEvalTemplateString(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xmlNodePtr parent) {
+xsltEvalTemplateString(xsltTransformContextPtr ctxt,
+ xmlNodePtr currentNode,
+ xmlNodePtr parent)
+{
xmlNodePtr oldInsert, insert = NULL;
xmlChar *ret;
- if ((ctxt == NULL) || (node == NULL) || (parent == NULL))
+ if ((ctxt == NULL) || (currentNode == NULL) || (parent == NULL))
return(NULL);
if (parent->children == NULL)
insert = xmlNewDocNode(ctxt->output, NULL,
(const xmlChar *)"fake", NULL);
if (insert == NULL) {
- xsltTransformError(ctxt, NULL, node,
+ xsltTransformError(ctxt, NULL, currentNode,
"Failed to create temporary node\n");
return(NULL);
}
oldInsert = ctxt->insert;
ctxt->insert = insert;
/* OPTIMIZE TODO: if parent->children consists only of text-nodes. */
- xsltApplyOneTemplate(ctxt, node, parent->children, NULL, NULL);
+ xsltApplyOneTemplate(ctxt, currentNode, parent->children, NULL, NULL);
ctxt->insert = oldInsert;
* xsltAttrTemplateValueProcessNode:
* @ctxt: the XSLT transformation context
* @str: the attribute template node value
- * @node: the node hosting the attribute
+ * @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 node) {
+ const xmlChar *str, xmlNodePtr inst)
+{
xmlChar *ret = NULL;
const xmlChar *cur;
xmlChar *expr, *val;
cur++;
while ((*cur != 0) && (*cur != '}')) cur++;
if (*cur == 0) {
- xsltTransformError(ctxt, NULL, NULL,
+ xsltTransformError(ctxt, NULL, inst,
"xsltAttrTemplateValueProcessNode: unmatched '{'\n");
ret = xmlStrncat(ret, str, cur - str);
return(ret);
/*
* TODO: keep precompiled form around
*/
- if ((nsList == NULL) && (node != NULL)) {
+ if ((nsList == NULL) && (inst != NULL)) {
int i = 0;
- nsList = xmlGetNsList(node->doc, node);
+ nsList = xmlGetNsList(inst->doc, inst);
if (nsList != NULL) {
while (nsList[i] != NULL)
i++;
str = cur;
continue;
} else {
- xsltTransformError(ctxt, NULL, NULL,
+ xsltTransformError(ctxt, NULL, inst,
"xsltAttrTemplateValueProcessNode: unmatched '}'\n");
}
} else
/**
* xsltEvalAttrValueTemplate:
* @ctxt: the XSLT transformation context
- * @node: the stylesheet node
+ * @inst: the instruction (or LRE) in the stylesheet holding the
+ * attribute with an AVT
* @name: the attribute QName
* @ns: the attribute namespace URI
*
* caller.
*/
xmlChar *
-xsltEvalAttrValueTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
- const xmlChar *name, const xmlChar *ns) {
+xsltEvalAttrValueTemplate(xsltTransformContextPtr ctxt, xmlNodePtr inst,
+ const xmlChar *name, const xmlChar *ns)
+{
xmlChar *ret;
xmlChar *expr;
- if ((ctxt == NULL) || (node == NULL) || (name == NULL))
+ if ((ctxt == NULL) || (inst == NULL) || (name == NULL))
return(NULL);
- expr = xsltGetNsProp(node, name, ns);
+ expr = xsltGetNsProp(inst, name, ns);
if (expr == NULL)
return(NULL);
* attribute content and the XPath precompiled expressions around
*/
- ret = xsltAttrTemplateValueProcessNode(ctxt, expr, node);
+ 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));
/**
* xsltEvalStaticAttrValueTemplate:
* @style: the XSLT stylesheet
- * @node: the stylesheet node
+ * @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
* caller.
*/
const xmlChar *
-xsltEvalStaticAttrValueTemplate(xsltStylesheetPtr style, xmlNodePtr node,
+xsltEvalStaticAttrValueTemplate(xsltStylesheetPtr style, xmlNodePtr inst,
const xmlChar *name, const xmlChar *ns, int *found) {
const xmlChar *ret;
xmlChar *expr;
- if ((style == NULL) || (node == NULL) || (name == NULL))
+ if ((style == NULL) || (inst == NULL) || (name == NULL))
return(NULL);
- expr = xsltGetNsProp(node, name, ns);
+ expr = xsltGetNsProp(inst, name, ns);
if (expr == NULL) {
*found = 0;
return(NULL);
/**
* xsltAttrTemplateProcess:
* @ctxt: the XSLT transformation context
- * @target: the result node
- * @cur: the attribute template node
+ * @target: the element where the attribute will be grafted
+ * @attr: the attribute node of a literal result element
*
- * Process the given attribute and return the new processed copy.
+ * 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 attribute replacement.
+ * Returns the generated attribute node.
*/
xmlAttrPtr
xsltAttrTemplateProcess(xsltTransformContextPtr ctxt, xmlNodePtr target,
- xmlAttrPtr cur) {
+ xmlAttrPtr attr)
+{
const xmlChar *value;
- xmlNsPtr ns;
xmlAttrPtr ret;
- if ((ctxt == NULL) || (cur == NULL) || (target == NULL))
+
+ if ((ctxt == NULL) || (attr == NULL) || (target == NULL))
return(NULL);
- if (cur->type != XML_ATTRIBUTE_NODE)
+ if (attr->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);
- }
+ /*
+ * 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 (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;
- }
+ 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) {
+ 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 (cur->ns != NULL)
- ns = xsltGetPlainNamespace(ctxt, cur->parent, cur->ns, target);
+ if (attr->ns != NULL)
+ ret = xmlNewNsProp(target,
+ xsltGetNamespace(ctxt, attr->parent, attr->ns, target),
+ attr->name, NULL);
else
- ns = NULL;
- ret = xmlNewNsProp(target, ns, cur->name, NULL);
+ ret = xmlNewNsProp(target, NULL, attr->name, NULL);
}
+ /*
+ * Set the value.
+ */
if (ret != NULL) {
xmlNodePtr text;
ret->last = ret->children = text;
text->parent = (xmlNodePtr) ret;
text->doc = ret->doc;
- if (cur->psvi != NULL) {
+
+ if (attr->psvi != NULL) {
+ /*
+ * Evaluate the Attribute Value Template.
+ */
xmlChar *val;
- val = xsltEvalAVT(ctxt, cur->psvi, cur->parent);
+ val = xsltEvalAVT(ctxt, attr->psvi, attr->parent);
if (val == NULL) {
- text->content = xmlStrdup(BAD_CAST "runtime error");
+ /*
+ * 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 {
- xsltTransformError(ctxt, NULL, cur->parent,
- "Failed to create attribute %s\n", cur->name);
+ 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);
}
* @target: the element where the attributes will be grafted
* @cur: the first attribute
*
- * Do a copy of an attribute list with attribute template processing
+ * 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.
*
- * Returns: a new xmlAttrPtr, or NULL in case of error.
+ * Called by xsltApplyOneTemplateInt() (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 cur) {
- xmlAttrPtr ret = NULL;
- xmlAttrPtr q;
- xmlNodePtr oldInsert;
+ 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;
- while (cur != NULL) {
- q = xsltAttrTemplateProcess(ctxt, target, cur);
- if (q != NULL) {
- q->parent = target;
- q->doc = target->doc;
- if (ret == NULL) {
- ret = q;
+ 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;
}
- cur = cur->next;
- }
+ /*
+ * 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))
+ {
+ text->content = (xmlChar *) value;
+ } else {
+ text->content = xmlStrdup(value);
+ }
+ }
+
+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(ret);
+ return(target->properties);
+
+error:
+ ctxt->insert = oldInsert;
+ return(NULL);
}
* @ctxt: the XSLT transformation context
* @node: the attribute template node
*
- * Process the given node and return the new string value.
- *
- * Returns the computed tree replacement
+ * Obsolete. Does always return NULL. Don't use it.
*/
xmlNodePtr *
xsltTemplateProcess(xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, xmlNodePtr node) {
#define IS_BLANK_NODE(n) \
(((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
+
+/*
+* Forward declarations
+*/
+
+static xmlNsPtr
+xsltCopyNamespaceListInternal(xmlNodePtr node, xmlNsPtr cur);
+
+static xmlNodePtr
+xsltCopyTreeInternal(xsltTransformContextPtr ctxt,
+ xmlNodePtr invocNode,
+ xmlNodePtr node,
+ xmlNodePtr insert, int isLRE, int topElemVisited);
+
/**
* templPush:
* @ctxt: the transformation context
len = xmlStrlen(string);
if ((ctxt->type == XSLT_OUTPUT_XML) &&
(ctxt->style->cdataSection != NULL) &&
- (target != NULL) && (target->type == XML_ELEMENT_NODE) &&
+ (target != NULL) &&
+ (target->type == XML_ELEMENT_NODE) &&
(((target->ns == NULL) &&
(xmlHashLookup2(ctxt->style->cdataSection,
target->name, NULL) != NULL)) ||
((target->ns != NULL) &&
(xmlHashLookup2(ctxt->style->cdataSection,
- target->name, target->ns->href) != NULL)))) {
+ target->name, target->ns->href) != NULL))))
+ {
if ((target != NULL) && (target->last != NULL) &&
- (target->last->type == XML_CDATA_SECTION_NODE)) {
+ (target->last->type == XML_CDATA_SECTION_NODE))
+ {
return(xsltAddTextString(ctxt, target->last, string, len));
}
copy = xmlNewCDataBlock(ctxt->output, string, len);
/*
* TODO: Since this doesn't merge adjacent CDATA-section nodes,
* we'll get: <![CDATA[x]]><!CDATA[y]]>.
+ * TODO: Reported in #321505.
*/
copy = xmlNewCDataBlock(ctxt->output, cur->content,
xmlStrlen(cur->content));
}
/**
- * xsltCopyProp:
+ * xsltShallowCopyAttr:
* @ctxt: a XSLT process context
- * @targetElem: the element where the attribute will be grafted
+ * @invocNode: responsible node in the stylesheet; used for error reports
+ * @target: the element where the attribute will be grafted
* @attr: the attribute to be copied
*
- * Do a copy of an attribute
+ * Do a copy of an attribute.
+ * Called by:
+ * - xsltCopyTreeInternal()
+ * - xsltCopyOf()
+ * - xsltCopy()
*
* Returns: a new xmlAttrPtr, or NULL in case of error.
*/
static xmlAttrPtr
-xsltCopyProp(xsltTransformContextPtr ctxt, xmlNodePtr targetElem,
- xmlAttrPtr attr)
+xsltShallowCopyAttr(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
+ xmlNodePtr target, xmlAttrPtr attr)
{
- xmlAttrPtr attrCopy;
+ xmlAttrPtr copy;
xmlChar *value;
-#ifdef XSLT_REFACTORED
- xmlNodePtr txtNode;
-#endif
if (attr == NULL)
return(NULL);
- if (targetElem->type != XML_ELEMENT_NODE) {
- /*
- * TODO: Hmm, it would be better to have the node at hand of the
- * instruction which lead to this here.
- */
- xsltTransformError(ctxt, NULL, NULL,
- "Result tree construction error: cannot set an attribute node "
- "on a non-element node.\n");
+ if (target->type != XML_ELEMENT_NODE) {
+ xsltTransformError(ctxt, NULL, invocNode,
+ "Cannot add an attribute node to a non-element node.\n");
return(NULL);
- }
+ }
+
+ if (target->children != NULL) {
+ xsltTransformError(ctxt, NULL, invocNode,
+ "Attribute nodes must be added before "
+ "any child nodes to an element.\n");
+ return(NULL);
+ }
-#ifdef XSLT_REFACTORED
- /*
- * Create the attribute node.
- */
+ value = xmlNodeListGetString(attr->doc, attr->children, 1);
if (attr->ns != NULL) {
- xmlNsPtr ns = NULL;
- const xmlChar *prefix = attr->ns->prefix;
-
- /*
- * Process namespace semantics
- *
- * RESTRUCTURE TODO: This is the same code as in
- * xsltAttributeInternal() (attributes.c), but I currently
- * don't want to add yet another ns-lookup function.
- */
- if ((targetElem->ns != NULL) &&
- (targetElem->ns->prefix != NULL) &&
- xmlStrEqual(targetElem->ns->href, attr->ns->href))
- {
- 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, attr->ns->href)))
- {
- goto namespace_finished;
- }
- }
- /*
- * Fallback to a search by ns-name.
- */
- ns = xmlSearchNsByHref(targetElem->doc, targetElem, attr->ns->href);
- 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 aready occupied.
- */
- break;
- }
- ns = ns->next;
- } while (ns != NULL);
- if (ns == NULL) {
- ns = xmlNewNs(targetElem, attr->ns->href, prefix);
- goto namespace_finished;
- }
- }
- }
- /*
- * Generate a new prefix.
- */
- {
- const xmlChar *basepref = prefix;
- xmlChar pref[30];
- int counter = 0;
-
- if (prefix != NULL)
- basepref = prefix;
- else
- basepref = xmlStrdup(BAD_CAST "ns");
-
- do {
- snprintf((char *) pref, 30, "%s_%d",
- basepref, counter++);
- ns = xmlSearchNs(targetElem->doc,
- (xmlNodePtr) attr, BAD_CAST pref);
- if (counter > 1000) {
- xsltTransformError(ctxt, NULL, (xmlNodePtr) attr,
- "Namespace fixup error: Failed to compute a "
- "new unique ns-prefix for the copied attribute "
- "{%s}%s'.\n", attr->ns->href, attr->name);
- ns = NULL;
- break;
- }
- } while (ns != NULL);
- if (basepref != prefix)
- xmlFree((xmlChar *)basepref);
- ns = xmlNewNs(targetElem, attr->ns->href, BAD_CAST pref);
- }
-
-namespace_finished:
+ xmlNsPtr ns;
+ ns = xsltGetSpecialNamespace(ctxt, invocNode,
+ attr->ns->href, attr->ns->prefix, target);
if (ns == NULL) {
- xsltTransformError(ctxt, NULL, (xmlNodePtr) attr,
+ xsltTransformError(ctxt, NULL, invocNode,
"Namespace fixup error: Failed to acquire an in-scope "
"namespace binding of the copied attribute '{%s}%s'.\n",
attr->ns->href, attr->name);
* TODO: Should we just stop here?
*/
}
- attrCopy = xmlSetNsProp(targetElem, ns, attr->name, NULL);
+ /*
+ * Note that xmlSetNsProp() will take care of duplicates
+ * and assigns the new namespace even to a duplicate.
+ */
+ copy = xmlSetNsProp(target, ns, attr->name, value);
} else {
- attrCopy = xmlSetNsProp(targetElem, NULL, attr->name, NULL);
+ copy = xmlSetNsProp(target, NULL, attr->name, value);
}
- if (attrCopy == NULL)
- return(NULL);
+ if (value != NULL)
+ xmlFree(value);
+
+ if (copy == NULL)
+ return(NULL);
+
+#if 0
/*
* NOTE: This was optimized according to bug #342695.
* TODO: Can this further be optimized, if source and target
* share the same dict and attr->children is just 1 text node
* which is in the dict? How probable is such a case?
*/
+ /*
+ * TODO: Do we need to create an empty text node if the value
+ * is the empty string?
+ */
value = xmlNodeListGetString(attr->doc, attr->children, 1);
if (value != NULL) {
- txtNode = xmlNewDocText(targetElem->doc, NULL);
+ txtNode = xmlNewDocText(target->doc, NULL);
if (txtNode == NULL)
return(NULL);
- if ((targetElem->doc != NULL) &&
- (targetElem->doc->dict != NULL))
+ if ((target->doc != NULL) &&
+ (target->doc->dict != NULL))
{
txtNode->content =
- (xmlChar *) xmlDictLookup(targetElem->doc->dict,
+ (xmlChar *) xmlDictLookup(target->doc->dict,
BAD_CAST value, -1);
- xmlFree(value);
+ xmlFree(value);
} else
txtNode->content = value;
- attrCopy->children = txtNode;
- }
- /*
- * URGENT TODO: Do we need to create an empty text node if the value
- * is the empty string?
- */
-
-#else /* not XSLT_REFACTORED */
-
- value = xmlNodeListGetString(attr->doc, attr->children, 1);
- if (attr->ns != NULL) {
- xmlNsPtr ns;
- ns = xsltGetPlainNamespace(ctxt, attr->parent, attr->ns, targetElem);
- attrCopy = xmlSetNsProp(targetElem, ns, attr->name, value);
- } else {
- attrCopy = xmlSetNsProp(targetElem, NULL, attr->name, value);
+ copy->children = txtNode;
}
- if (value != NULL)
- xmlFree(value);
-
-#endif /* not XSLT_REFACTORED */
+#endif
- return(attrCopy);
+ return(copy);
}
/**
- * xsltCopyPropList:
+ * xsltCopyAttrListNoOverwrite:
* @ctxt: a XSLT process context
- * @target: the element where the properties will be grafted
- * @cur: the first property
+ * @invocNode: responsible node in the stylesheet; used for error reports
+ * @target: the element where the new attributes will be grafted
+ * @attr: the first attribute in the list to be copied
*
- * Do a copy of a properties list.
+ * Copies a list of attribute nodes, starting with @attr, over to the
+ * @target element node.
*
- * Returns: a new xmlAttrPtr, or NULL in case of error.
+ * Called by:
+ * - xsltCopyTreeInternal()
+ *
+ * Returns 0 on success and -1 on errors and internal errors.
*/
-static xmlAttrPtr
-xsltCopyPropList(xsltTransformContextPtr ctxt, xmlNodePtr target,
- xmlAttrPtr cur) {
- xmlAttrPtr ret = NULL;
- xmlAttrPtr p = NULL,q;
- xmlNsPtr ns;
+static int
+xsltCopyAttrListNoOverwrite(xsltTransformContextPtr ctxt,
+ xmlNodePtr invocNode,
+ xmlNodePtr target, xmlAttrPtr attr)
+{
+ xmlAttrPtr last = NULL, copy;
+ xmlNsPtr origNs = NULL, copyNs = NULL;
+ xmlChar *value = NULL;
- while (cur != NULL) {
- if (cur->ns != NULL) {
- ns = xsltGetNamespace(ctxt, cur->parent, cur->ns, target);
+ /*
+ * Don't use xmlCopyProp() here, since it will try to
+ * reconciliate namespaces.
+ */
+ while (attr != NULL) {
+ /*
+ * Find a namespace node in the tree of @target.
+ * Avoid searching for the same ns.
+ */
+ if (attr->ns != origNs) {
+ origNs = attr->ns;
+ if (attr->ns != NULL) {
+ copyNs = xsltGetSpecialNamespace(ctxt, invocNode,
+ attr->ns->href, attr->ns->prefix, target);
+ if (copyNs == NULL)
+ return(-1);
+ } else
+ copyNs = NULL;
+ }
+ if (attr->children)
+ value = xmlNodeListGetString(attr->doc, attr->children, 1);
+ /*
+ * REVISIT: I think xmlNewDocProp() is the only attr function
+ * which does not eval if the attr is of type ID. This is good,
+ * since we don't need this.
+ */
+ copy = xmlNewDocProp(target->doc, attr->name, BAD_CAST value);
+ if (copy == NULL)
+ return(-1);
+ copy->parent = target;
+ copy->ns = copyNs;
+
+ if (last == NULL) {
+ target->properties = copy;
+ last = copy;
} else {
- ns = NULL;
+ last->next = copy;
+ copy->prev = last;
+ last = copy;
}
- q = xmlCopyProp(target, cur);
- if (q != NULL) {
- q->ns = ns;
- if (p == NULL) {
- ret = p = q;
- } else {
- p->next = q;
- q->prev = p;
- p = q;
- }
+ /*
+ * OPTIMIZE TODO: How to avoid this intermediate string?
+ */
+ if (value != NULL) {
+ xmlFree(value);
+ value = NULL;
}
- cur = cur->next;
- }
- return(ret);
+ attr = attr->next;
+ }
+ return(0);
}
/**
- * xsltCopyNode:
- * @ctxt: a XSLT process context
- * @node: the element node in the source tree.
- * @insert: the parent in the result tree.
+ * xsltShallowCopyElem:
+ * @ctxt: the XSLT process context
+ * @node: the element node in the source tree
+ * or the Literal Result Element
+ * @insert: the parent in the result tree
+ * @isLRE: if @node is a Literal Result Element
*
* Make a copy of the element node @node
- * and insert it as last child of @insert
- * Intended *only* for copying literal result elements and
- * text-nodes.
+ * and insert it as last child of @insert.
+ *
+ * URGENT TODO: The problem with this one (for the non-refactored code)
+ * is that it is used for both, Literal Result Elements *and*
+ * copying input nodes.
+ *
+ * BIG NOTE: This is only called for XML_ELEMENT_NODEs.
+ *
* Called from:
- * xsltApplyOneTemplateInt()
- * xsltCopy()
+ * xsltApplyOneTemplateInt() (for Literal Result Elements - which is a problem)
+ * xsltCopy() (for shallow-copying elements via xsl:copy)
*
* Returns a pointer to the new node, or NULL in case of error
*/
static xmlNodePtr
-xsltCopyNode(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xmlNodePtr insert) {
+xsltShallowCopyElem(xsltTransformContextPtr ctxt, xmlNodePtr node,
+ xmlNodePtr insert, int isLRE)
+{
xmlNodePtr copy;
if ((node->type == XML_DTD_NODE) || (insert == NULL))
if ((node->type == XML_TEXT_NODE) ||
(node->type == XML_CDATA_SECTION_NODE))
return(xsltCopyText(ctxt, insert, node, 0));
+
copy = xmlDocCopyNode(node, insert->doc, 0);
if (copy != NULL) {
copy->doc = ctxt->output;
xmlAddChild(insert, copy);
+
if (node->type == XML_ELEMENT_NODE) {
/*
* Add namespaces as they are needed
*/
- if (node->nsDef != NULL)
- xsltCopyNamespaceList(ctxt, copy, node->nsDef);
- }
- if ((node->type == XML_ELEMENT_NODE) ||
- (node->type == XML_ATTRIBUTE_NODE)) {
+ if (node->nsDef != NULL) {
+ /*
+ * TODO: Remove the LRE case in the refactored code
+ * gets enabled.
+ */
+ if (isLRE)
+ xsltCopyNamespaceList(ctxt, copy, node->nsDef);
+ else
+ xsltCopyNamespaceListInternal(copy, node->nsDef);
+ }
+
+ /*
+ * URGENT TODO: The problem with this is that it does not
+ * copy over all namespace nodes in scope.
+ * The damn thing about this is, that we would need to
+ * use the xmlGetNsList(), for every single node; this is
+ * also done in xsltCopyTreeInternal(), but only for the top node.
+ */
if (node->ns != NULL) {
- copy->ns = xsltGetNamespace(ctxt, node, node->ns, copy);
+ if (isLRE) {
+ /*
+ * REVISIT TODO: Since the non-refactored code still does
+ * ns-aliasing, we need to call xsltGetNamespace() here.
+ * Remove this when ready.
+ */
+ copy->ns = xsltGetNamespace(ctxt, node, node->ns, copy);
+ } else {
+ copy->ns = xsltGetSpecialNamespace(ctxt,
+ node, node->ns->href, node->ns->prefix, copy);
+
+ }
} else if ((insert->type == XML_ELEMENT_NODE) &&
- (insert->ns != NULL)) {
- xmlNsPtr defaultNs;
-
- defaultNs = xmlSearchNs(insert->doc, insert, NULL);
- if (defaultNs != NULL)
- xmlNewNs(copy, BAD_CAST "", NULL);
+ (insert->ns != NULL))
+ {
+ /*
+ * "Undeclare" the default namespace.
+ */
+ xsltGetSpecialNamespace(ctxt, node, NULL, NULL, copy);
}
}
} else {
xsltTransformError(ctxt, NULL, node,
- "xsltCopyNode: copy %s failed\n", node->name);
+ "xsltShallowCopyElem: copy %s failed\n", node->name);
}
return(copy);
}
/**
* xsltCopyTreeList:
* @ctxt: a XSLT process context
+ * @invocNode: responsible node in the stylesheet; used for error reports
* @list: the list of element nodes in the source tree.
* @insert: the parent in the result tree.
* @literal: is this a literal result element list
*
* Make a copy of the full list of tree @list
* and insert it as last children of @insert
- * For literal result element, some of the namespaces may not be copied
- * over according to section 7.1 .
+ *
+ * NOTE: Not to be used for Literal Result Elements.
+ *
+ * Used by:
+ * - xsltCopyOf()
*
* Returns a pointer to the new list, or NULL in case of error
*/
static xmlNodePtr
-xsltCopyTreeList(xsltTransformContextPtr ctxt, xmlNodePtr list,
- xmlNodePtr insert, int literal) {
+xsltCopyTreeList(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
+ xmlNodePtr list,
+ xmlNodePtr insert, int isLRE, int topElemVisited)
+{
xmlNodePtr copy, ret = NULL;
while (list != NULL) {
- copy = xsltCopyTree(ctxt, list, insert, literal);
+ copy = xsltCopyTreeInternal(ctxt, invocNode,
+ list, insert, isLRE, topElemVisited);
if (copy != NULL) {
if (ret == NULL) {
ret = copy;
* Do a copy of a namespace list. If @node is non-NULL the
* new namespaces are added automatically.
* Called by:
- * xsltCopyTree()
+ * xsltCopyTreeInternal()
*
- * TODO: What is the exact difference between this function
+ * QUESTION: What is the exact difference between this function
* and xsltCopyNamespaceList() in "namespaces.c"?
+ * ANSWER: xsltCopyNamespaceList() tries to apply ns-aliases.
*
* Returns: a new xmlNsPtr, or NULL in case of error.
*/
static xmlNsPtr
-xsltCopyNamespaceListInternal(xmlNodePtr node, xmlNsPtr cur) {
+xsltCopyNamespaceListInternal(xmlNodePtr elem, xmlNsPtr ns) {
xmlNsPtr ret = NULL;
- xmlNsPtr p = NULL,q;
+ xmlNsPtr p = NULL, q, luNs;
- if (cur == NULL)
- return(NULL);
- if (cur->type != XML_NAMESPACE_DECL)
+ if (ns == NULL)
return(NULL);
-
/*
* One can add namespaces only on element nodes
*/
- if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
- node = NULL;
+ if ((elem != NULL) && (elem->type != XML_ELEMENT_NODE))
+ elem = NULL;
- while (cur != NULL) {
- if (cur->type != XML_NAMESPACE_DECL)
+ do {
+ if (ns->type != XML_NAMESPACE_DECL)
break;
-
/*
- * Avoid duplicating namespace declarations on the tree
+ * Avoid duplicating namespace declarations on the tree.
*/
- if ((node != NULL) && (node->ns != NULL) &&
- (xmlStrEqual(node->ns->href, cur->href)) &&
- (xmlStrEqual(node->ns->prefix, cur->prefix))) {
- cur = cur->next;
- continue;
- }
-
- q = xmlNewNs(node, cur->href, cur->prefix);
+ if (elem != NULL) {
+ if ((elem->ns != NULL) &&
+ xmlStrEqual(elem->ns->prefix, ns->prefix) &&
+ xmlStrEqual(elem->ns->href, ns->href))
+ {
+ ns = ns->next;
+ continue;
+ }
+ luNs = xmlSearchNs(elem->doc, elem, ns->prefix);
+ if ((luNs != NULL) && (xmlStrEqual(luNs->href, ns->href)))
+ {
+ ns = ns->next;
+ continue;
+ }
+ }
+ q = xmlNewNs(elem, ns->href, ns->prefix);
if (p == NULL) {
ret = p = q;
} else if (q != NULL) {
p->next = q;
p = q;
}
- cur = cur->next;
- }
+ ns = ns->next;
+ } while (ns != NULL);
return(ret);
}
/**
- * xsltCopyTree:
- * @ctxt: a XSLT process context
- * @node: the element node in the source tree.
- * @insert: the parent in the result tree.
- * @literal: is this a literal result element list
+ * xsltShallowCopyNsNode:
+ * @ctxt: the XSLT transformation context
+ * @invocNode: responsible node in the stylesheet; used for error reports
+ * @insert: the target element node in the result tree
+ * @ns: the namespace node
+ *
+ * This is used for copying ns-nodes with xsl:copy-of and xsl:copy.
+ *
+ * Returns a new/existing ns-node, or NULL.
+ */
+static int
+xsltShallowCopyNsNode(xsltTransformContextPtr ctxt,
+ xmlNodePtr invocNode,
+ xmlNodePtr insert,
+ xmlNsPtr ns)
+{
+ xmlNsPtr tmpns;
+
+ if ((insert == NULL) || (insert->type != XML_ELEMENT_NODE))
+ return(-1);
+
+ if (insert->children != NULL) {
+ xsltTransformError(ctxt, NULL, invocNode,
+ "Namespace nodes must be added before "
+ "any child nodes are added to an element.\n");
+ return(1);
+ }
+ /*
+ *
+ * BIG NOTE: Xalan-J simply overwrites any ns-decls with
+ * an equal prefix. We definitively won't do that.
+ *
+ * MSXML 4.0 and the .NET ignores ns-decls for which an
+ * equal prefix is already in use.
+ *
+ * Saxon raises an error like:
+ * "net.sf.saxon.xpath.DynamicError: Cannot create two namespace
+ * nodes with the same name".
+ *
+ * NOTE: We'll currently follow MSXML here.
+ * REVISIT TODO: Check if it's better to follow Saxon here.
+ */
+ if (ns->prefix == NULL) {
+ /*
+ * If we are adding ns-nodes to an element using e.g.
+ * <xsl:copy-of select="/foo/namespace::*">, then we need
+ * to ensure that we don't incorrectly declare a default
+ * namespace on an element in no namespace, which otherwise
+ * would move the element incorrectly into a namespace, if
+ * the node tree is serialized.
+ */
+ if (insert->ns == NULL)
+ goto occupied;
+ } else if ((ns->prefix[0] == 'x') &&
+ xmlStrEqual(ns->prefix, BAD_CAST "xml"))
+ {
+ return(0);
+ }
+
+ if (insert->nsDef != NULL) {
+ tmpns = insert->nsDef;
+ do {
+ if ((tmpns->prefix == NULL) == (ns->prefix == NULL)) {
+ if ((tmpns->prefix == ns->prefix) ||
+ xmlStrEqual(tmpns->prefix, ns->prefix))
+ {
+ /*
+ * Same prefix.
+ */
+ if (xmlStrEqual(tmpns->href, ns->href))
+ return(0);
+ goto occupied;
+ }
+ }
+ tmpns = tmpns->next;
+ } while (tmpns != NULL);
+ }
+ tmpns = xmlSearchNs(insert->doc, insert, ns->prefix);
+ if ((tmpns != NULL) && xmlStrEqual(tmpns->href, ns->href))
+ return(0);
+ /*
+ * Declare a new namespace.
+ * TODO: The problem (wrt efficiency) with this xmlNewNs() is
+ * that it will again search the already declared namespaces
+ * for a duplicate :-/
+ */
+ xmlNewNs(insert, ns->href, ns->prefix);
+ return(0);
+
+occupied:
+ /*
+ * TODO: We could as well raise an error here (like Saxon does),
+ * or at least generate a warning.
+ */
+ return(0);
+}
+
+/**
+ * xsltCopyTreeInternal:
+ * @ctxt: the XSLT transformation context
+ * @invocNode: responsible node in the stylesheet; used for error reports
+ * @node: the element node in the source tree
+ * @insert: the parent in the result tree
+ * @isLRE: indicates if @node is a Literal Result Element
+ * @topElemVisited: indicates if a top-most element was already processed
*
* Make a copy of the full tree under the element node @node
* and insert it as last child of @insert
- * For literal result element, some of the namespaces may not be copied
- * over according to section 7.1.
- * TODO: Why is this a public function?
+ *
+ * NOTE: Not to be used for Literal Result Elements.
+ *
+ * Used by:
+ * - xsltCopyOf()
*
* Returns a pointer to the new tree, or NULL in case of error
*/
-xmlNodePtr
-xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xmlNodePtr insert, int literal) {
+static xmlNodePtr
+xsltCopyTreeInternal(xsltTransformContextPtr ctxt,
+ xmlNodePtr invocNode,
+ xmlNodePtr node,
+ xmlNodePtr insert, int isLRE, int topElemVisited)
+{
xmlNodePtr copy;
if (node == NULL)
return(xsltCopyTextString(ctxt, insert, node->content, 0));
case XML_ATTRIBUTE_NODE:
return((xmlNodePtr)
- xsltCopyProp(ctxt, insert, (xmlAttrPtr) node));
+ xsltShallowCopyAttr(ctxt, invocNode, insert, (xmlAttrPtr) node));
case XML_NAMESPACE_DECL:
- if (insert->type != XML_ELEMENT_NODE)
- return(NULL);
- return((xmlNodePtr)
- xsltCopyNamespaceList(ctxt, insert, (xmlNsPtr) node));
+ return((xmlNodePtr) xsltShallowCopyNsNode(ctxt, invocNode,
+ insert, (xmlNsPtr) node));
case XML_DOCUMENT_TYPE_NODE:
case XML_DOCUMENT_FRAG_NODE:
}
if (XSLT_IS_RES_TREE_FRAG(node)) {
if (node->children != NULL)
- copy = xsltCopyTreeList(ctxt, node->children, insert, 0);
+ copy = xsltCopyTreeList(ctxt, invocNode,
+ node->children, insert, 0, 0);
else
copy = NULL;
return(copy);
*/
if (insert->last != copy)
return(insert->last);
-
copy->next = NULL;
- /*
- * Add namespaces as they are needed
- */
- if ((node->type == XML_ELEMENT_NODE) ||
- (node->type == XML_ATTRIBUTE_NODE)) {
- xmlNsPtr *nsList, *cur, ns;
+
+ if (node->type == XML_ELEMENT_NODE) {
/*
- * Must add any new namespaces in scope for the node.
- * TODO: Since we try to reuse existing in-scope ns-decls by
- * using xmlSearchNsByHref(), this will eventually change
- * the prefix of an original ns-binding; thus it might
- * break QNames in element/attribute content.
- */
- nsList = xmlGetNsList(node->doc, node);
- if (nsList != NULL) {
- cur = nsList;
- while (*cur != NULL) {
- ns = xmlSearchNsByHref(insert->doc, insert, (*cur)->href);
- if (ns == NULL)
- xmlNewNs(copy, (*cur)->href, (*cur)->prefix);
- cur++;
+ * Copy in-scope namespace nodes.
+ *
+ * REVISIT: Since we try to reuse existing in-scope ns-decls by
+ * using xmlSearchNsByHref(), this will eventually change
+ * the prefix of an original ns-binding; thus it might
+ * break QNames in element/attribute content.
+ * OPTIMIZE TODO: If we had a xmlNsPtr * on the transformation
+ * context, plus a ns-lookup function, which writes directly
+ * to a given list, then we wouldn't need to create/free the
+ * nsList every time.
+ */
+ if ((topElemVisited == 0) &&
+ (node->parent != NULL) &&
+ (node->parent->type != XML_DOCUMENT_NODE) &&
+ (node->parent->type != XML_HTML_DOCUMENT_NODE))
+ {
+ xmlNsPtr *nsList, *curns, ns;
+
+ /*
+ * If this is a top-most element in a tree to be
+ * copied, then we need to ensure that all in-scope
+ * namespaces are copied over. For nodes deeper in the
+ * tree, it is sufficient to reconcile only the ns-decls
+ * (node->nsDef entries).
+ */
+
+ nsList = xmlGetNsList(node->doc, node);
+ if (nsList != NULL) {
+ curns = nsList;
+ do {
+ /*
+ * Search by prefix first in order to break as less
+ * QNames in element/attribute content as possible.
+ */
+ ns = xmlSearchNs(insert->doc, insert,
+ (*curns)->prefix);
+
+ if ((ns == NULL) ||
+ (! xmlStrEqual(ns->href, (*curns)->href)))
+ {
+ ns = NULL;
+ /*
+ * Search by namespace name.
+ * REVISIT TODO: Currently disabled.
+ */
+#if 0
+ ns = xmlSearchNsByHref(insert->doc,
+ insert, (*curns)->href);
+#endif
+ }
+ if (ns == NULL) {
+ /*
+ * Declare a new namespace on the copied element.
+ */
+ ns = xmlNewNs(copy, (*curns)->href,
+ (*curns)->prefix);
+ /* TODO: Handle errors */
+ }
+ if (node->ns == *curns) {
+ /*
+ * If this was the original's namespace then set
+ * the generated counterpart on the copy.
+ */
+ copy->ns = ns;
+ }
+ curns++;
+ } while (*curns != NULL);
+ xmlFree(nsList);
}
- xmlFree(nsList);
- }
- if (node->ns != NULL) {
+ } else if (node->nsDef != NULL) {
/*
- * This will map copy->ns to one of the newly created
- * in-scope ns-decls.
+ * Copy over all namespace declaration attributes.
*/
- copy->ns = xsltGetNamespace(ctxt, node, node->ns, copy);
+ if (node->nsDef != NULL) {
+ if (isLRE)
+ xsltCopyNamespaceList(ctxt, copy, node->nsDef);
+ else
+ xsltCopyNamespaceListInternal(copy, node->nsDef);
+ }
+ }
+ /*
+ * Set the namespace.
+ */
+ if (node->ns != NULL) {
+ if (copy->ns == NULL) {
+ /*
+ * This will map copy->ns to one of the newly created
+ * in-scope ns-decls, OR create a new ns-decl on @copy.
+ */
+ copy->ns = xsltGetSpecialNamespace(ctxt, invocNode,
+ node->ns->href, node->ns->prefix, copy);
+ }
} else if ((insert->type == XML_ELEMENT_NODE) &&
(insert->ns != NULL))
{
- xmlNsPtr defaultNs;
-
- defaultNs = xmlSearchNs(insert->doc, insert, NULL);
- if (defaultNs != NULL)
- xmlNewNs(copy, BAD_CAST "", NULL);
+ /*
+ * "Undeclare" the default namespace on @copy with xmlns="".
+ */
+ xsltGetSpecialNamespace(ctxt, invocNode, NULL, NULL, copy);
}
+ /*
+ * Copy attribute nodes.
+ */
+ if (node->properties != NULL) {
+ xsltCopyAttrListNoOverwrite(ctxt, invocNode,
+ copy, node->properties);
+ }
+ if (topElemVisited == 0)
+ topElemVisited = 1;
}
- if (node->nsDef != NULL) {
- if (literal)
- xsltCopyNamespaceList(ctxt, copy, node->nsDef);
- else
- xsltCopyNamespaceListInternal(copy, node->nsDef);
+ /*
+ * Copy the subtree.
+ */
+ if (node->children != NULL) {
+ xsltCopyTreeList(ctxt, invocNode,
+ node->children, copy, isLRE, topElemVisited);
}
- if (node->properties != NULL)
- copy->properties = xsltCopyPropList(ctxt, copy,
- node->properties);
- if (node->children != NULL)
- xsltCopyTreeList(ctxt, node->children, copy, literal);
} else {
- xsltTransformError(ctxt, NULL, node,
- "xsltCopyTree: copy %s failed\n", node->name);
+ xsltTransformError(ctxt, NULL, invocNode,
+ "xsltCopyTreeInternal: Copying of '%s' failed.\n", node->name);
}
return(copy);
}
+/**
+ * xsltCopyTree:
+ * @ctxt: the XSLT transformation context
+ * @node: the element node in the source tree
+ * @insert: the parent in the result tree
+ * @literal: indicates if @node is a Literal Result Element
+ *
+ * Make a copy of the full tree under the element node @node
+ * and insert it as last child of @insert
+ * For literal result element, some of the namespaces may not be copied
+ * over according to section 7.1.
+ * TODO: Why is this a public function?
+ *
+ * Returns a pointer to the new tree, or NULL in case of error
+ */
+xmlNodePtr
+xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr node,
+ xmlNodePtr insert, int literal)
+{
+ return(xsltCopyTreeInternal(ctxt, node, node, insert, literal, 0));
+
+}
+
/************************************************************************
* *
* Error/fallback processing *
}
}
-#ifdef XSLT_REFACTORED
-/**
-* xsltTransLREUndeclareDefaultNs:
-* @ctxt: the transformation context
-* @cur: the literal result element
-* @ns: the namespace
-* @out: the output node (or its parent)
-*
-*
-* Find a matching (prefix and ns-name) ns-declaration
-* for the given @ns in the result tree.
-* If none is found then a new ns-declaration will be
-* added to @out. If, in this case, the given prefix is already
-* in use, then a ns-declaration with a modified ns-prefix
-* be we created.
-*
-* Returns the acquired ns-declaration
-* or NULL in case of an API or internal error.
-*/
-static int
-xsltTransLREUndeclareResultDefaultNs(xsltTransformContextPtr ctxt,
- xmlNodePtr cur,
- xmlNodePtr resultElem)
-{
- xmlNsPtr ns;
- /*
- * OPTIMIZE TODO: This all could be optimized by keeping track of
- * the ns-decls currently in-scope via a specialized context.
- */
- /*
- * Search on the result element itself.
- */
- if (resultElem->nsDef != NULL) {
- ns = resultElem->nsDef;
- do {
- if (ns->prefix == NULL) {
- if ((ns->href != NULL) && (ns->href[0] != 0)) {
- /*
- * Raise a namespace normalization error.
- */
- xsltTransformError(ctxt, NULL, cur,
- "Namespace normalization error: Cannot undeclare "
- "the default namespace, since the default namespace "
- "'%s' is already declared on the result element.\n",
- ns->href);
- return(1);
- } else {
- /*
- * The default namespace was undeclared on the
- * result element.
- */
- return(0);
- }
- break;
- }
- ns = ns->next;
- } while (ns != NULL);
- }
-
- if ((resultElem->parent != NULL) &&
- (resultElem->parent->type == XML_ELEMENT_NODE))
- {
- /*
- * The parent element is in no namespace, so assume
- * that there is no default namespace in scope.
- */
- if (resultElem->parent->ns == NULL)
- return(0);
-
- ns = xmlSearchNs(resultElem->doc, resultElem->parent,
- NULL);
- /*
- * Fine if there's no default ns is scope, or if the
- * default ns was undeclared.
- */
- if ((ns == NULL) || (ns->href == NULL) || (ns->href[0] == 0))
- return(0);
-
- /*
- * Undeclare the default namespace.
- */
- ns = xmlNewNs(resultElem, BAD_CAST "", NULL);
- /* TODO: Check result */
- return(0);
- }
- return(0);
-}
-
-/**
-* xsltTransLREAcquireResultInScopeNs:
-* @ctxt: the transformation context
-* @cur: the literal result element (in the stylesheet)
-* @literalNs: the namespace (in the stylsheet)
-* @resultElem: the generated result element
-*
-*
-* Find a matching (prefix and ns-name) ns-declaration
-* for the given @ns in the result tree.
-* If none is found then a new ns-declaration will be
-* added to @out. If, in this case, the given prefix is already
-* in use, then a ns-declaration with a modified ns-prefix
-* be we created.
-*
-* Returns the acquired ns-declaration
-* or NULL in case of an API or internal error.
-*/
-static xmlNsPtr
-xsltTransLREAcquireResultInScopeNs(xsltTransformContextPtr ctxt,
- xmlNodePtr cur,
- xmlNsPtr literalNs,
- xmlNodePtr resultElem)
-{
- xmlNsPtr ns;
- int prefixOccupied = 0;
-
- if ((ctxt == NULL) || (cur == NULL) || (resultElem == NULL))
- return(NULL);
-
- /*
- * OPTIMIZE TODO: This all could be optimized by keeping track of
- * the ns-decls currently in-scope via a specialized context.
- */
- /*
- * NOTE: Namespace exclusion and ns-aliasing is performed at
- * compilation-time in the refactored code; so this need not be done
- * here.
- */
- /*
- * First: search on the result element itself.
- */
- if (resultElem->nsDef != NULL) {
- ns = resultElem->nsDef;
- do {
- if ((ns->prefix == NULL) == (literalNs->prefix == NULL)) {
- if (literalNs->prefix == NULL) {
- if (xmlStrEqual(ns->href, literalNs->href))
- return(ns);
- prefixOccupied = 1;
- break;
- } else if ((ns->prefix[0] == literalNs->prefix[0]) &&
- xmlStrEqual(ns->prefix, literalNs->prefix))
- {
- if (xmlStrEqual(ns->href, literalNs->href))
- return(ns);
- prefixOccupied = 1;
- break;
- }
- }
- ns = ns->next;
- } while (ns != NULL);
- }
- if (prefixOccupied) {
- /*
- * If the ns-prefix is occupied by an other ns-decl on the
- * result element, then this means:
- * 1) The desired prefix is shadowed
- * 2) There's no way around changing the prefix
- *
- * Try a desperate search for an in-scope ns-decl
- * with a matching ns-name before we use the last option,
- * which is to recreate the ns-decl with a modified prefix.
- */
- ns = xmlSearchNsByHref(resultElem->doc, resultElem, literalNs->href);
- if (ns != NULL)
- return(ns);
-
- /*
- * Fallback to changing the prefix.
- */
- } else if ((resultElem->parent != NULL) &&
- (resultElem->parent->type == XML_ELEMENT_NODE)) {
- /*
- * Try to find a matching ns-decl in the ancestor-axis.
- *
- * Check the common case: The parent element of the current
- * result element is in the same namespace (with an equal ns-prefix).
- */
- if ((resultElem->parent->ns != NULL) &&
- ((resultElem->parent->ns->prefix == NULL) ==
- (literalNs->prefix == NULL)))
- {
- ns = resultElem->parent->ns;
-
- if (literalNs->prefix == NULL) {
- if (xmlStrEqual(ns->href, literalNs->href))
- return(ns);
- } else if ((ns->prefix[0] == literalNs->prefix[0]) &&
- xmlStrEqual(ns->prefix, literalNs->prefix) &&
- xmlStrEqual(ns->href, literalNs->href))
- {
- return(ns);
- }
- }
- /*
- * Lookup the remaining in-scope namespaces.
- */
- ns = xmlSearchNs(resultElem->doc, resultElem->parent,
- literalNs->prefix);
- if ((ns != NULL) && xmlStrEqual(ns->href, literalNs->href))
- return(ns);
- ns = NULL;
- /*
- * Either no matching ns-prefix was found or the namespace is
- * shadowed.
- * Create a new ns-decl on the current result element.
- *
- * SPEC TODO: Hmm, we could also try to reuse an in-scope
- * namespace with a matching ns-name but a different
- * ns-prefix.
- * What has higher precedence?
- * 1) If keeping the prefix: create a new ns-decl.
- * 2) If reusal: first lookup ns-names; then fallback
- * to creation of a new ns-decl.
- * REVISIT TODO: this currently uses case 2) since this
- * is the way it used to be before refactoring.
- */
- ns = xmlSearchNsByHref(resultElem->doc, resultElem,
- literalNs->href);
- if (ns != NULL)
- return(ns);
- /*
- * Create the ns-decl on the current result element.
- */
- ns = xmlNewNs(resultElem, literalNs->href, literalNs->prefix);
- /* TODO: check errors */
- return(ns);
- } else if ((resultElem->parent == NULL) ||
- (resultElem->parent->type != XML_ELEMENT_NODE))
- {
- /*
- * This is the root of the tree.
- */
- ns = xmlNewNs(resultElem, literalNs->href, literalNs->prefix);
- /* TODO: Check result */
- return(ns);
- }
- /*
- * Fallback: we need to generate a new prefix and declare the namespace
- * on the result element.
- */
- {
- xmlChar prefix[30];
- int counter = 0;
-
- /*
- * Comment copied from xslGetNamespace():
- * "For an element node, if we don't find it, or it's the default
- * and this element already defines a default (bug 165560), we
- * need to create it."
- */
- do {
- snprintf((char *) prefix, 30, "%s_%d",
- literalNs->prefix, counter++);
- ns = xmlSearchNs(resultElem->doc, resultElem, BAD_CAST prefix);
- if (counter > 1000) {
- xsltTransformError(ctxt, NULL, cur,
- "Internal error in xsltTransLREAcquireInScopeNs(): "
- "Failed to compute a unique ns-prefix for the "
- "result element");
- return(NULL);
- }
- } while (ns != NULL);
- ns = xmlNewNs(resultElem, literalNs->href, BAD_CAST prefix);
- /* TODO: Check result */
- return(ns);
- }
- return(NULL);
-}
-
-#endif /* XSLT_REFACTORED */
-
/**
* xsltApplyOneTemplate:
* @ctxt: a XSLT process context
#endif
/*
* Copy the raw element-node.
- * OLD: if ((copy = xsltCopyNode(ctxt, cur, insert)) == NULL)
+ * OLD: if ((copy = xsltShallowCopyElem(ctxt, cur, insert))
+ * == NULL)
* goto error;
*/
copy = xmlDocCopyNode(cur, insert->doc, 0);
if (cur->ns != NULL) {
/*
* If there's no such ns-decl in the result tree,
- * then xsltGetNamespace() will create a ns-decl
- * on the copied node.
- */
- /*
- * REVISIT TODO: Changed to use
- * xsltTransLREAcquireInScopeNs() instead of
- * xsltGetNamespace().
- * OLD: copy->ns = xsltGetNamespace(ctxt, cur,
- * cur->ns, copy);
- */
- copy->ns = xsltTransLREAcquireResultInScopeNs(ctxt,
- cur, cur->ns, copy);
+ * then xsltGetSpecialNamespace() will
+ * create a ns-decl on the copied node.
+ */
+ copy->ns = xsltGetSpecialNamespace(ctxt, cur,
+ cur->ns->href, cur->ns->prefix, copy);
} else {
/*
* Undeclare the default namespace if needed.
- * This can be skipped, if:
- * 1) If the result element has no ns-decls, in which
- * case the result element abviously does not
- * declare a default namespace.
- * 2) AND there's either no parent, or the parent
- * is in no namespace; this means there's no
- * default namespace is scope to care about.
+ * This can be skipped, if the result element has
+ * no ns-decls, in which case the result element
+ * obviously does not declare a default namespace;
+ * AND there's either no parent, or the parent
+ * element is in no namespace; this means there's no
+ * default namespace is scope to care about.
*
- * REVISIT TODO: This might result in massive
+ * REVISIT: This might result in massive
* generation of ns-decls if nodes in a default
* namespaces are mixed with nodes in no namespace.
*
*/
if (copy->nsDef ||
- ((insert != NULL) && (insert->ns != NULL)))
- xsltTransLREUndeclareResultDefaultNs(ctxt,
- cur, copy);
-#if 0
- defaultNs = xmlSearchNs(insert->doc, insert, NULL);
- if ((defaultNs != NULL) && (defaultNs->href != NULL))
- xmlNewNs(copy, BAD_CAST "", NULL);
-#endif
+ ((insert != NULL) &&
+ (insert->type == XML_ELEMENT_NODE) &&
+ (insert->ns != NULL)))
+ {
+ xsltGetSpecialNamespace(ctxt, cur,
+ NULL, NULL, copy);
+ }
}
}
/*
* is processed to produce an attribute for the element in
* the result tree."
* TODO: Refactor this, since it still uses ns-aliasing.
+ * NOTE: See bug #341325.
*/
if (cur->properties != NULL) {
xsltAttrListTemplateProcess(ctxt, copy, cur->properties);
}
- /*
- * OLD-COMMENT: "Add extra namespaces inherited from the
- * current template if we are in the first level children
- * and this is a "real" template.
- *
- * SPEC XSLT 2.0:
- * "The following namespaces are designated as excluded
- * namespaces:
- * - The XSLT namespace URI
- * (http://www.w3.org/1999/XSL/Transform)
- * - A namespace URI declared as an extension namespace
- * - A namespace URI designated by using an
- * [xsl:]exclude-result-prefixes
- *
- * TODO:
- * XSLT 1.0
- * 1) Supply all in-scope namespaces
- * 2) Skip excluded namespaces (see above)
- * 3) Apply namespace aliasing
- *
- * XSLT 2.0 (will generate
- * redundant namespaces in some cases):
- * 1) Supply all in-scope namespaces
- * 2) Skip excluded namespaces if *not* target-namespace
- * of an namespace alias
- * 3) Apply namespace aliasing
- *
- * NOTE: See bug #341325.
- */
-#if 0
- if ((templ != NULL) && (oldInsert == insert) &&
- (ctxt->templ != NULL) &&
- (ctxt->templ->inheritedNs != NULL)) {
- int i;
- xmlNsPtr ns, ret;
-
- for (i = 0; i < ctxt->templ->inheritedNsNr; i++) {
- const xmlChar *URI = NULL;
- xsltStylesheetPtr style;
-
- ns = ctxt->templ->inheritedNs[i];
- /*
- * Apply namespace aliasing.
- *
- * TODO: Compute the effective value of namespace
- * aliases at compilation-time in order to avoid
- * the lookup in the import-tree here.
- */
- style = ctxt->style;
- while (style != NULL) {
- if (style->nsAliases != NULL)
- URI = (const xmlChar *)
- xmlHashLookup(style->nsAliases, ns->href);
- if (URI != NULL)
- break;
-
- style = xsltNextImport(style);
- }
- if (URI == UNDEFINED_DEFAULT_NS) {
- xmlNsPtr defaultNs;
-
- defaultNs = xmlSearchNs(cur->doc, cur, NULL);
- if (defaultNs == NULL) {
- /*
- * TODO: Should not happen; i.e., it is
- * an error at compilation-time if there's
- * no default namespace in scope if
- * "#default" is used.
- */
- continue;
- } else
- URI = defaultNs->href;
- }
-
- if (URI == NULL) {
- /*
- * There was no matching namespace-alias, so
- * just create a matching ns-decl if not
- * already in scope.
- */
- ret = xmlSearchNs(copy->doc, copy, ns->prefix);
- if ((ret == NULL) ||
- (!xmlStrEqual(ret->href, ns->href)))
- xmlNewNs(copy, ns->href, ns->prefix);
- } else if (!xmlStrEqual(URI, XSLT_NAMESPACE)) {
- ret = xmlSearchNs(copy->doc, copy, ns->prefix);
- if ((ret == NULL) ||
- (!xmlStrEqual(ret->href, URI))) {
- /*
- * Here we create a namespace
- * declaration with the literal namespace
- * prefix and with the target namespace name.
- * TODO: We should consider to fix this and
- * use the *target* namespace prefix, not the
- * literal one (see bug #341325).
- */
- xmlNewNs(copy, URI, ns->prefix);
- }
- }
- }
- if (copy->ns != NULL) {
- /*
- * Fix the node namespace if needed
- */
- copy->ns = xsltGetNamespace(ctxt, copy, copy->ns, copy);
- }
- }
-#endif
} else if (IS_XSLT_ELEM_FAST(cur)) {
/*
* XSLT instructions
ctxt->insert = insert;
if (!xsltApplyFallbacks(ctxt, node, cur)) {
xsltGenericError(xsltGenericErrorContext,
- "xsltApplyOneTemplate: %s was not compiled\n",
- cur->name);
+ "xsltApplyOneTemplate: %s was not compiled\n",
+ cur->name);
}
ctxt->insert = oldInsert;
}
xsltMessage(ctxt, node, cur);
} else {
xsltGenericError(xsltGenericErrorContext,
- "xsltApplyOneTemplate: problem with xsl:%s\n",
- cur->name);
+ "xsltApplyOneTemplate: problem with xsl:%s\n",
+ cur->name);
}
goto skip_children;
} else if ((cur->type == XML_TEXT_NODE) ||
"xsltApplyOneTemplate: copy node %s\n",
cur->name));
#endif
- if ((copy = xsltCopyNode(ctxt, cur, insert)) == NULL)
- goto error;
- /*
- * all the attributes are directly inherited
- */
- if (cur->properties != NULL) {
- xsltAttrListTemplateProcess(ctxt, copy,
- cur->properties);
- }
+ if ((copy = xsltShallowCopyElem(ctxt, cur, insert, 1)) == NULL)
+ goto error;
/*
* Add extra namespaces inherited from the current template
* if we are in the first level children and this is a
for (i = 0; i < ctxt->templ->inheritedNsNr; i++) {
const xmlChar *URI = NULL;
xsltStylesheetPtr style;
- ns = ctxt->templ->inheritedNs[i];
+ ns = ctxt->templ->inheritedNs[i];
+
+ /* Note that the XSLT namespace was already excluded
+ * in xsltGetInheritedNsList().
+ */
+#if 0
+ if (xmlStrEqual(ns->href, XSLT_NAMESPACE))
+ continue;
+#endif
style = ctxt->style;
while (style != NULL) {
- if (style->nsAliases != NULL)
- URI = (const xmlChar *)
- xmlHashLookup(style->nsAliases, ns->href);
- if (URI != NULL)
- break;
-
- style = xsltNextImport(style);
- }
-
- if (URI == UNDEFINED_DEFAULT_NS) {
- xmlNsPtr dflt;
- dflt = xmlSearchNs(cur->doc, cur, NULL);
- if (dflt == NULL)
- continue;
- else
- URI = dflt->href;
+ if (style->nsAliases != NULL)
+ URI = (const xmlChar *)
+ xmlHashLookup(style->nsAliases, ns->href);
+ if (URI != NULL)
+ break;
+
+ style = xsltNextImport(style);
}
-
- if (URI == NULL) {
- ret = xmlSearchNs(copy->doc, copy, ns->prefix);
- if ((ret == NULL) ||
- (!xmlStrEqual(ret->href, ns->href)))
- xmlNewNs(copy, ns->href, ns->prefix);
- } else if (!xmlStrEqual(URI, XSLT_NAMESPACE)) {
- ret = xmlSearchNs(copy->doc, copy, ns->prefix);
- if ((ret == NULL) ||
- (!xmlStrEqual(ret->href, URI)))
+ if (URI == UNDEFINED_DEFAULT_NS)
+ continue;
+ if (URI == NULL)
+ URI = ns->href;
+ /*
+ * TODO: The following will still be buggy for the
+ * non-refactored code.
+ */
+ ret = xmlSearchNs(copy->doc, copy, ns->prefix);
+ if ((ret == NULL) || (!xmlStrEqual(ret->href, URI)))
+ {
xmlNewNs(copy, URI, ns->prefix);
}
}
/*
* Fix the node namespace if needed
*/
- copy->ns = xsltGetNamespace(ctxt, copy, copy->ns, copy);
+ copy->ns = xsltGetNamespace(ctxt, cur, copy->ns, copy);
}
}
+ /*
+ * all the attributes are directly inherited
+ */
+ if (cur->properties != NULL) {
+ xsltAttrListTemplateProcess(ctxt, copy, cur->properties);
+ }
}
#endif /* else of XSLT_REFACTORED */
/**
* xsltCopy:
- * @ctxt: a XSLT process context
- * @node: the node in the source tree.
- * @inst: the xslt copy node
- * @comp: precomputed information
+ * @ctxt: an XSLT process context
+ * @node: the node in the source tree
+ * @inst: the element node of the XSLT-copy instruction
+ * @comp: computed information of the XSLT-copy instruction
*
- * Execute the xsl:copy instruction on the source node.
+ * Execute the XSLT-copy instruction on the source node.
*/
void
xsltCopy(xsltTransformContextPtr ctxt, xmlNodePtr node,
- xmlNodePtr inst, xsltStylePreCompPtr castedComp) {
+ xmlNodePtr inst, xsltStylePreCompPtr castedComp)
+{
#ifdef XSLT_REFACTORED
xsltStyleItemCopyPtr comp = (xsltStyleItemCopyPtr) castedComp;
#else
break;
case XML_ELEMENT_NODE:
/*
- * NOTE: The "fake" is a doc-node, not an element node.
- * OLD:
+ * REVISIT NOTE: The "fake" is a doc-node, not an element node.
+ * REMOVED:
* if (xmlStrEqual(node->name, BAD_CAST " fake node libxslt"))
* return;
*/
XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
"xsltCopy: node %s\n", node->name));
#endif
- copy = xsltCopyNode(ctxt, node, ctxt->insert);
+ copy = xsltShallowCopyElem(ctxt, node, ctxt->insert, 0);
ctxt->insert = copy;
if (comp->use != NULL) {
xsltApplyAttributeSet(ctxt, node, inst, comp->use);
XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
"xsltCopy: attribute %s\n", node->name));
#endif
- if (ctxt->insert->type == XML_ELEMENT_NODE) {
- xmlAttrPtr attr = (xmlAttrPtr) node, ret = NULL, cur;
-
- if (attr->ns != NULL) {
- if (!xmlStrEqual(attr->ns->href, XSLT_NAMESPACE)) {
- ret = xmlCopyProp(ctxt->insert, attr);
- ret->ns = xsltGetNamespace(ctxt, node, attr->ns,
- ctxt->insert);
- }
- } else
- ret = xmlCopyProp(ctxt->insert, attr);
-
- if (ret != NULL) {
- cur = ctxt->insert->properties;
- if (cur != NULL) {
- /*
- * Avoid duplicates and insert at the end
- * of the attribute list
- */
- while (cur->next != NULL) {
- if ((xmlStrEqual(cur->name, ret->name)) &&
- (((cur->ns == NULL) && (ret->ns == NULL)) ||
- ((cur->ns != NULL) && (ret->ns != NULL) &&
- (xmlStrEqual(cur->ns->href,
- ret->ns->href))))) {
- xmlFreeProp(ret);
- return;
- }
- cur = cur->next;
- }
- if ((xmlStrEqual(cur->name, ret->name)) &&
- (((cur->ns == NULL) && (ret->ns == NULL)) ||
- ((cur->ns != NULL) && (ret->ns != NULL) &&
- (xmlStrEqual(cur->ns->href,
- ret->ns->href))))) {
- xmlNodePtr tmp;
-
- /*
- * Attribute already exists,
- * update it with the new value
- */
- tmp = cur->children;
- cur->children = ret->children;
- ret->children = tmp;
- tmp = cur->last;
- cur->last = ret->last;
- ret->last = tmp;
- xmlFreeProp(ret);
- return;
- }
- cur->next = ret;
- ret->prev = cur;
- } else
- ctxt->insert->properties = ret;
- }
- }
+ /*
+ * REVISIT: We could also raise an error if the parent is not
+ * an element node.
+ * OPTIMIZE TODO: Can we set the value/children of the
+ * attribute without an intermediate copy of the string value?
+ */
+ xsltShallowCopyAttr(ctxt, inst, ctxt->insert, (xmlAttrPtr) node);
break;
}
case XML_PI_NODE:
#ifdef WITH_XSLT_DEBUG_PROCESS
XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
"xsltCopy: namespace declaration\n"));
-#endif
- xsltCopyNamespace(ctxt, ctxt->insert, (xmlNsPtr)node);
+#endif
+ xsltShallowCopyNsNode(ctxt, inst, ctxt->insert, (xmlNsPtr)node);
break;
default:
break;
#else
xsltStylePreCompPtr comp = castedComp;
#endif
- xmlChar *prop = NULL, *attributes = NULL, *namespace;
- const xmlChar *name;
- const xmlChar *prefix;
- xmlNsPtr ns = NULL, oldns = NULL;
+ xmlChar *prop = NULL;
+ const xmlChar *name, *prefix = NULL, *nsName = NULL;
xmlNodePtr copy;
xmlNodePtr oldInsert;
- int generateDefault = 0;
-
if (ctxt->insert == NULL)
return;
- if (!comp->has_name) {
- 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;
/*
* stack and saves
oldInsert = ctxt->insert;
if (comp->name == NULL) {
- prop = xsltEvalAttrValueTemplate(ctxt, inst,
- (const xmlChar *)"name", NULL);
- if (prop == NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "xsl:element : name is missing\n");
- return;
- }
+ /* 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:element: The attribute 'name' is missing.\n");
+ goto error;
+ }
if (xmlValidateQName(prop, 0)) {
xsltTransformError(ctxt, NULL, inst,
- "xsl:element : invalid name\n");
- /* we fall through to catch any other errors if possible */
+ "xsl:element: 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);
+ if ((prefix != NULL) &&
+ (!xmlStrncasecmp(prefix, (xmlChar *)"xml", 3)))
+ {
+ /*
+ * TODO: Should we really disallow an "xml" prefix?
+ */
+ goto error;
+ }
} else {
+ /*
+ * The "name" value was static.
+ */
+#ifdef XSLT_REFACTORED
+ prefix = comp->nsPrefix;
+ name = comp->name;
+#else
name = xsltSplitQName(ctxt->dict, comp->name, &prefix);
+#endif
}
-
+
/*
* Create the new element
*/
"xsl:element : creation of %s failed\n", name);
return;
}
- xmlAddChild(ctxt->insert, copy);
- ctxt->insert = copy;
+ xmlAddChild(ctxt->insert, copy);
- if ((comp->ns == NULL) && (comp->has_ns)) {
- namespace = xsltEvalAttrValueTemplate(ctxt, inst,
- (const xmlChar *)"namespace", NULL);
- if (namespace != NULL) {
- ns = xsltGetSpecialNamespace(ctxt, inst, namespace, prefix,
- ctxt->insert);
- xmlFree(namespace);
- }
- } else if ((comp->ns != NULL) && (prefix == NULL) && (comp->has_ns)) {
- generateDefault = 1;
- } else if (comp->ns != NULL) {
- ns = xsltGetSpecialNamespace(ctxt, inst, comp->ns, prefix,
- ctxt->insert);
- }
- if ((ns == NULL) && (prefix != NULL)) {
- if (!xmlStrncasecmp(prefix, (xmlChar *)"xml", 3)) {
-#ifdef WITH_XSLT_DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltElement: xml prefix forbidden\n");
-#endif
- return;
- }
- oldns = xmlSearchNs(inst->doc, inst, prefix);
- if (oldns == NULL) {
- xsltTransformError(ctxt, NULL, inst,
- "xsl:element : no namespace bound to prefix %s\n", prefix);
+ /*
+ * Namespace
+ * ---------
+ */
+ if (comp->has_ns) {
+ if (comp->ns != NULL) {
+ /*
+ * No AVT; just plain text for the namespace name.
+ */
+ if (comp->ns[0] != 0)
+ nsName = comp->ns;
} else {
- ns = xsltGetNamespace(ctxt, inst, oldns, ctxt->insert);
- }
+ xmlChar *tmpNsName;
+ /*
+ * Eval the AVT.
+ */
+ /* TODO: check attr acquisition wrt to the XSLT namespace */
+ tmpNsName = xsltEvalAttrValueTemplate(ctxt, inst,
+ (const xmlChar *) "namespace", XSLT_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 {
+ xmlNsPtr ns;
+ /*
+ * 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:element element, including any default
+ * namespace declaration.
+ */
+ ns = xmlSearchNs(inst->doc, inst, prefix);
+ if (ns == NULL) {
+ /*
+ * TODO: Check this in the compilation layer in case it's a
+ * static value.
+ */
+ if (prefix != NULL) {
+ xsltTransformError(ctxt, NULL, inst,
+ "xsl:element: 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.
+ */
+ if (nsName != NULL) {
+ copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, prefix, copy);
+ } else if ((copy->parent != NULL) &&
+ (copy->parent->type == XML_ELEMENT_NODE) &&
+ (copy->parent->ns != NULL))
+ {
+ /*
+ * "Undeclare" the default namespace.
+ */
+ xsltGetSpecialNamespace(ctxt, inst, NULL, NULL, copy);
}
- if (generateDefault == 1) {
- xmlNsPtr defaultNs = NULL;
-
- if ((oldInsert != NULL) && (oldInsert->type == XML_ELEMENT_NODE))
- defaultNs = xmlSearchNs(oldInsert->doc, oldInsert, NULL);
- if ((defaultNs == NULL) || (!xmlStrEqual(defaultNs->href, comp->ns))) {
- ns = xmlNewNs(ctxt->insert, comp->ns, NULL);
- ctxt->insert->ns = ns;
- } else {
- ctxt->insert->ns = defaultNs;
- }
- } else if ((ns == NULL) && (oldns != NULL)) {
- /* very specific case xsltGetNamespace failed */
- ns = xmlNewNs(ctxt->insert, oldns->href, oldns->prefix);
- ctxt->insert->ns = ns;
- } else
- ctxt->insert->ns = ns;
-
+ ctxt->insert = copy;
if (comp->has_use) {
if (comp->use != NULL) {
xsltApplyAttributeSet(ctxt, node, inst, comp->use);
} else {
+ xmlChar *attrSets = NULL;
/*
* BUG TODO: use-attribute-sets is not a value template.
* use-attribute-sets = qnames
*/
- attributes = xsltEvalAttrValueTemplate(ctxt, inst,
- (const xmlChar *)"use-attribute-sets", NULL);
- if (attributes != NULL) {
- xsltApplyAttributeSet(ctxt, node, inst, attributes);
- xmlFree(attributes);
+ attrSets = xsltEvalAttrValueTemplate(ctxt, inst,
+ (const xmlChar *)"use-attribute-sets", NULL);
+ if (attrSets != NULL) {
+ xsltApplyAttributeSet(ctxt, node, inst, attrSets);
+ xmlFree(attrSets);
}
}
}
-
- xsltApplyOneTemplateInt(ctxt, ctxt->node, inst->children, NULL, NULL, 0);
+ /*
+ * Instantiate the sequence constructor.
+ */
+ if (inst->children != NULL)
+ xsltApplyOneTemplateInt(ctxt, ctxt->node, inst->children,
+ NULL, NULL, 0);
+error:
ctxt->insert = oldInsert;
+ return;
}
#ifdef XSLT_REFACTORED
if (comp->inScopeNs != NULL) {
ctxt->xpathCtxt->namespaces = comp->inScopeNs->list;
- ctxt->xpathCtxt->nsNr = comp->inScopeNs->number;
+ ctxt->xpathCtxt->nsNr = comp->inScopeNs->xpathNumber;
} else {
ctxt->xpathCtxt->namespaces = NULL;
ctxt->xpathCtxt->nsNr = 0;
if ((cur->type == XML_DOCUMENT_NODE) ||
(cur->type == XML_HTML_DOCUMENT_NODE))
{
- xsltCopyTreeList(ctxt, cur->children, ctxt->insert, 0);
+ xsltCopyTreeList(ctxt, inst,
+ cur->children, ctxt->insert, 0, 0);
} else if (cur->type == XML_ATTRIBUTE_NODE) {
- xsltCopyProp(ctxt, ctxt->insert, (xmlAttrPtr) cur);
+ xsltShallowCopyAttr(ctxt, inst,
+ ctxt->insert, (xmlAttrPtr) cur);
} else {
- xsltCopyTree(ctxt, cur, ctxt->insert, 0);
+ xsltCopyTreeInternal(ctxt, inst,
+ cur, ctxt->insert, 0, 0);
}
}
}
} else if (res->type == XPATH_XSLT_TREE) {
/*
- * Result tree fragment
+ * Result tree fragment (e.g. via <xsl:variable ...><foo/></xsl:variable>)
* --------------------
*/
#ifdef WITH_XSLT_DEBUG_PROCESS
(list->nodeTab[0] != NULL) &&
(IS_XSLT_REAL_NODE(list->nodeTab[0])))
{
- xsltCopyTreeList(ctxt, list->nodeTab[0]->children,
- ctxt->insert, 0);
+ xsltCopyTreeList(ctxt, inst,
+ list->nodeTab[0]->children, ctxt->insert, 0, 0);
}
} else {
/* Convert to a string. */
#ifdef XSLT_REFACTORED
if (comp->inScopeNs != NULL) {
ctxt->xpathCtxt->namespaces = comp->inScopeNs->list;
- ctxt->xpathCtxt->nsNr = comp->inScopeNs->number;
+ ctxt->xpathCtxt->nsNr = comp->inScopeNs->xpathNumber;
} else {
ctxt->xpathCtxt->namespaces = NULL;
ctxt->xpathCtxt->nsNr = 0;
#ifdef XSLT_REFACTORED
if (comp->inScopeNs != NULL) {
ctxt->xpathCtxt->namespaces = comp->inScopeNs->list;
- ctxt->xpathCtxt->nsNr = comp->inScopeNs->number;
+ ctxt->xpathCtxt->nsNr = comp->inScopeNs->xpathNumber;
} else {
ctxt->xpathCtxt->namespaces = NULL;
ctxt->xpathCtxt->nsNr = 0;
#ifdef XSLT_REFACTORED
if (wcomp->inScopeNs != NULL) {
ctxt->xpathCtxt->namespaces = wcomp->inScopeNs->list;
- ctxt->xpathCtxt->nsNr = wcomp->inScopeNs->number;
+ ctxt->xpathCtxt->nsNr = wcomp->inScopeNs->xpathNumber;
} else {
ctxt->xpathCtxt->namespaces = NULL;
ctxt->xpathCtxt->nsNr = 0;
#ifdef XSLT_REFACTORED
if (comp->inScopeNs != NULL) {
ctxt->xpathCtxt->namespaces = comp->inScopeNs->list;
- ctxt->xpathCtxt->nsNr = comp->inScopeNs->number;
+ ctxt->xpathCtxt->nsNr = comp->inScopeNs->xpathNumber;
} else {
ctxt->xpathCtxt->namespaces = NULL;
ctxt->xpathCtxt->nsNr = 0;
ctxt->xpathCtxt->namespaces = comp->nsList;
ctxt->xpathCtxt->nsNr = comp->nsNr;
#endif
+ /*
+ * OPTIMIZE TODO: Use a specialized function, which returns only
+ * true/false.
+ */
res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);
ctxt->xpathCtxt->contextSize = oldContextSize;
ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
#ifdef XSLT_REFACTORED
if (comp->inScopeNs != NULL) {
ctxt->xpathCtxt->namespaces = comp->inScopeNs->list;
- ctxt->xpathCtxt->nsNr = comp->inScopeNs->number;
+ ctxt->xpathCtxt->nsNr = comp->inScopeNs->xpathNumber;
} else {
ctxt->xpathCtxt->namespaces = NULL;
ctxt->xpathCtxt->nsNr = 0;
#ifdef XSLT_REFACTORED
if (precomp->inScopeNs != NULL) {
ctxt->xpathCtxt->namespaces = precomp->inScopeNs->list;
- ctxt->xpathCtxt->nsNr = precomp->inScopeNs->number;
+ ctxt->xpathCtxt->nsNr = precomp->inScopeNs->xpathNumber;
} else {
ctxt->xpathCtxt->namespaces = NULL;
ctxt->xpathCtxt->nsNr = 0;
#ifdef XSLT_REFACTORED
if (precomp->inScopeNs != NULL) {
ctxt->xpathCtxt->namespaces = precomp->inScopeNs->list;
- ctxt->xpathCtxt->nsNr = precomp->inScopeNs->number;
+ ctxt->xpathCtxt->nsNr = precomp->inScopeNs->xpathNumber;
} else {
ctxt->xpathCtxt->namespaces = NULL;
ctxt->xpathCtxt->nsNr = 0;
*/
const xmlChar *xsltXSLTTextMarker = (const xmlChar *) "XSLT Text Element";
+/*
+* xsltXSLTAttrMarker:
+* Marker for XSLT attribute on Literal Result Elements.
+*/
+const xmlChar *xsltXSLTAttrMarker = (const xmlChar *) "LRE XSLT Attr";
+
#endif
/*
xmlFree(style->methodURI);
style->methodURI = NULL;
+ /*
+ * TODO: Don't use xsltGetQNameURI().
+ */
URI = xsltGetQNameURI(cur, &prop);
if (prop == NULL) {
if (style != NULL) style->errors++;
} else {
const xmlChar *URI;
+ /*
+ * TODO: Don't use xsltGetQNameURI().
+ */
URI = xsltGetQNameURI(cur, &element);
if (element == NULL) {
/*
} else {
const xmlChar *URI;
+ /*
+ * TODO: Don't use xsltGetQNameURI().
+ */
URI = xsltGetQNameURI(cur, &element);
xmlHashAddEntry2(style->stripSpaces, element, URI,
} else {
const xmlChar *URI;
+ /*
+ * TODO: Don't use xsltGetQNameURI().
+ */
URI = xsltGetQNameURI(cur, &element);
xmlHashAddEntry2(style->stripSpaces, element, URI,
extElemNs = cctxt->inode->extElemNs;
exclResultNs = cctxt->inode->exclResultNs;
- for (i = 0; i < item->inScopeNs->number; i++) {
+ for (i = 0; i < item->inScopeNs->totalNumber; i++) {
ns = item->inScopeNs->list[i];
/*
* Skip namespaces designated as excluded namespaces
* Recognized as an namespace alias; convert it to
* the target namespace.
*/
- ns = alias->literalNs;
+ if (alias->targetNs != NULL)
+ ns = alias->literalNs;
+ else {
+ /*
+ * The target is the NULL namespace.
+ */
+ goto skip_ns;
+ }
break;
}
alias = alias->next;
xsltCompilerBuildInScopeNsList(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
{
xsltNsListContainerPtr nsi = NULL;
- xmlNsPtr *list = NULL;
+ xmlNsPtr *list = NULL, ns;
+ int i, maxns = 5;
/*
* Create a new ns-list for this position in the node-tree.
* xmlGetNsList() will return NULL, if there are no ns-decls in the
* to the resulting list; the XPath module handles the XML namespace
* internally.
*/
- list = xmlGetNsList(node->doc, node);
- if (list == NULL)
+ while (node != NULL) {
+ if (node->type == XML_ELEMENT_NODE) {
+ ns = node->nsDef;
+ while (ns != NULL) {
+ if (nsi == NULL) {
+ nsi = (xsltNsListContainerPtr)
+ xmlMalloc(sizeof(xsltNsListContainer));
+ if (nsi == NULL) {
+ xsltTransformError(NULL, cctxt->style, NULL,
+ "xsltCompilerBuildInScopeNsList: "
+ "malloc failed!\n");
+ goto internal_err;
+ }
+ memset(nsi, 0, sizeof(xsltNsListContainer));
+ nsi->list =
+ (xmlNsPtr *) xmlMalloc(maxns * sizeof(xmlNsPtr));
+ if (nsi->list == NULL) {
+ xsltTransformError(NULL, cctxt->style, NULL,
+ "xsltCompilerBuildInScopeNsList: "
+ "malloc failed!\n");
+ goto internal_err;
+ }
+ nsi->list[0] = NULL;
+ }
+ /*
+ * Skip shadowed namespace bindings.
+ */
+ for (i = 0; i < nsi->totalNumber; i++) {
+ if ((ns->prefix == nsi->list[i]->prefix) ||
+ (xmlStrEqual(ns->prefix, nsi->list[i]->prefix)))
+ break;
+ }
+ if (i >= nsi->totalNumber) {
+ if (nsi->totalNumber >= maxns) {
+ maxns *= 2;
+ nsi->list =
+ (xmlNsPtr *) xmlRealloc(nsi->list,
+ maxns * sizeof(xmlNsPtr));
+ if (nsi->list == NULL) {
+ xsltTransformError(NULL, cctxt->style, NULL,
+ "xsltCompilerBuildInScopeNsList: "
+ "realloc failed!\n");
+ goto internal_err;
+ }
+ }
+ nsi->list[nsi->totalNumber++] = ns;
+ nsi->list[nsi->totalNumber] = NULL;
+ }
+
+ ns = ns->next;
+ }
+ }
+ node = node->parent;
+ }
+ if (nsi == NULL)
return(NULL);
/*
- * Create the info-structure.
+ * Move the default namespace to last position.
*/
- nsi = (xsltNsListContainerPtr) xmlMalloc(sizeof(xsltNsListContainer));
- if (nsi == NULL) {
- xsltTransformError(NULL, cctxt->style, NULL,
- "xsltCompilerBuildInScopeNsList: malloc failed.\n");
- goto internal_err;
+ nsi->xpathNumber = nsi->totalNumber;
+ for (i = 0; i < nsi->totalNumber; i++) {
+ if (nsi->list[i]->prefix == NULL) {
+ ns = nsi->list[i];
+ nsi->list[i] = nsi->list[nsi->totalNumber-1];
+ nsi->list[nsi->totalNumber-1] = ns;
+ nsi->xpathNumber--;
+ break;
+ }
}
- memset(nsi, 0, sizeof(xsltNsListContainer));
- nsi->list = list;
- /*
- * Eval the number of ns-decls; this is used to speed up
- * XPath-context initialization.
- */
- while (list[nsi->number] != NULL)
- nsi->number++;
/*
* Store the ns-list in the stylesheet.
*/
int instrCategory)
{
xsltPointerListPtr list = NULL;
- xmlChar *value = NULL;
+ xmlChar *value;
+ xmlAttrPtr attr;
if ((cctxt == NULL) || (node == NULL))
return(NULL);
-
+
if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
- value = xmlGetNsProp(node, BAD_CAST "exclude-result-prefixes", NULL);
+ attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes", NULL);
else
- value = xmlGetNsProp(node, BAD_CAST "exclude-result-prefixes",
+ attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes",
XSLT_NAMESPACE);
+ if (attr == NULL)
+ return(def);
- if (value == NULL)
+ if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
+ /*
+ * Mark the XSLT attr.
+ */
+ attr->psvi = (void *) xsltXSLTAttrMarker;
+ }
+
+ if ((attr->children != NULL) &&
+ (attr->children->content != NULL))
+ value = attr->children->content;
+ else {
+ xsltTransformError(NULL, cctxt->style, node,
+ "Attribute 'exclude-result-prefixes': Invalid value.\n");
+ cctxt->style->errors++;
return(def);
+ }
if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,
BAD_CAST value) != 0)
if (cctxt->inode != NULL)
cctxt->inode->nsChanged = 1;
-exit:
- if (value != NULL)
- xmlFree(value);
+exit:
if (list != NULL)
return(list);
else
if (attr == NULL)
return(def);
+ if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
+ /*
+ * Mark the XSLT attr.
+ */
+ attr->psvi = (void *) xsltXSLTAttrMarker;
+ }
+
if ((attr->children != NULL) &&
(attr->children->content != NULL))
value = attr->children->content;
if (cctxt->inode != NULL)
cctxt->inode->nsChanged = 1;
-exit:
- if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
- /*
- * Remove the XSLT attribute from the literal result element.
- */
- xmlUnlinkNode((xmlNodePtr) attr);
- xmlFreeProp(attr);
- }
+exit:
if (list != NULL)
return(list);
else
return(def);
}
-
/*
* xsltParseAttrXSLTVersion:
*
if (attr == NULL)
return(0);
+ attr->psvi = (void *) xsltXSLTAttrMarker;
+
if ((attr->children != NULL) &&
(attr->children->content != NULL))
value = attr->children->content;
if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
/*
- * Remove the XSLT attribute from the literal result element.
+ * Set a marker on XSLT attributes.
*/
- xmlUnlinkNode((xmlNodePtr) attr);
- xmlFreeProp(attr);
+ attr->psvi = (void *) xsltXSLTAttrMarker;
}
return(1);
}
-#if 0
-static int
-xsltParseRemoveXSLTAttrs(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
-{
- if (node->properties == NULL)
- return(0);
- else {
- xmlAttrPtr tmpattr, attr = node->properties;
- do {
- if (IS_XSLT_ATTR_FAST(attr)) {
- tmpattr = attr;
- attr = attr->next;
- xmlUnlinkNode((xmlNodePtr) tmpattr);
- xmlFreeProp(tmpattr);
- } else
- attr = attr->next;
- } while (attr != NULL);
- }
-}
-#endif
-
static int
xsltParsePreprocessStylesheetTree(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
{
cur->psvi = NULL;
cctxt->inode->category = XSLT_ELEMENT_CATEGORY_LRE;
if (cur->properties != NULL) {
+ xmlAttrPtr attr = cur->properties;
/*
* Attribute "xsl:exclude-result-prefixes".
*/
xsltParseAttrXSLTVersion(cctxt, cur,
XSLT_ELEMENT_CATEGORY_LRE);
/*
- * Report invalid XSLT attributes.
+ * Report invalid XSLT attributes.
+ * For XSLT 1.0 only xsl:use-attribute-sets is allowed
+ * next to xsl:version, xsl:exclude-result-prefixes and
+ * xsl:extension-element-prefixes.
+ *
+ * Mark all XSLT attributes, in order to skip such
+ * attributes when instantiating the LRE.
*/
- if (cur->properties) {
- xmlAttrPtr attr = cur->properties;
-
- do {
- if (IS_XSLT_ATTR_FAST(attr) &&
- (! xmlStrEqual(attr->name,
- BAD_CAST "use-attribute-sets")))
+ do {
+ if ((attr->psvi != xsltXSLTAttrMarker) &&
+ IS_XSLT_ATTR_FAST(attr))
+ {
+ if (! xmlStrEqual(attr->name,
+ BAD_CAST "use-attribute-sets"))
{
- xsltTransformError(NULL, cctxt->style, cur,
+ xsltTransformError(NULL, cctxt->style,
+ cur,
"Unknown XSLT attribute '%s'.\n",
- attr->name);
- cctxt->style->errors++;
+ attr->name);
+ cctxt->style->errors++;
+ } else {
+ /*
+ * XSLT attr marker.
+ */
+ attr->psvi = (void *) xsltXSLTAttrMarker;
}
- attr = attr->next;
- } while (attr != NULL);
- }
+ }
+ attr = attr->next;
+ } while (attr != NULL);
}
/*
* Create/reuse info for the literal result element.
if (prop != NULL) {
const xmlChar *URI;
+ /*
+ * TODO: Don't use xsltGetQNameURI().
+ */
URI = xsltGetQNameURI(key, &prop);
if (prop == NULL) {
if (style != NULL) style->errors++;
templ->next = cctxt->style->templates;
cctxt->style->templates = templ;
- templ->style = cctxt->style;
-
-
- /*
- * Get inherited namespaces.
- */
- if (cctxt->inode->inScopeNs != NULL) {
- int i, j;
- xmlNsPtr ns;
- xsltPointerListPtr extElemNs = cctxt->inode->extElemNs;
- xsltPointerListPtr exclResultNs = cctxt->inode->exclResultNs;
- xsltNsListContainerPtr inScopeNs = cctxt->inode->inScopeNs;
-
- for (i = 0; i < inScopeNs->number; i++) {
- ns = inScopeNs->list[i];
- /*
- * Exclude the XSLT namespace.
- */
- if (xmlStrEqual(ns->href, XSLT_NAMESPACE))
- goto skip_ns;
- /*
- * Exclude excluded result namespaces.
- */
- if (exclResultNs) {
- for (j = 0; j < exclResultNs->number; j++)
- if (xmlStrEqual(ns->href, BAD_CAST exclResultNs->items[j]))
- goto skip_ns;
- }
- /*
- * Exclude extension-element namespaces.
- */
- if (extElemNs) {
- for (j = 0; j < extElemNs->number; j++)
- if (xmlStrEqual(ns->href, BAD_CAST extElemNs->items[j]))
- goto skip_ns;
- }
- /*
- * Add the xmlNs item.
- */
- if (templ->inheritedNs == NULL) {
- templ->inheritedNs = (xmlNsPtr *) xmlMalloc(
- inScopeNs->number * sizeof(xmlNsPtr));
- if (templ->inheritedNs == NULL) {
- xmlGenericError(xmlGenericErrorContext,
- "xsltGetInheritedNsList : out of memory!\n");
- cctxt->style->errors++;
- goto error;
- }
- memset(templ->inheritedNs, 0,
- inScopeNs->number * sizeof(xmlNsPtr));
- }
- templ->inheritedNs[templ->inheritedNsNr++] = ns;
-skip_ns:
- {}
- }
-#ifdef WITH_XSLT_DEBUG_PARSING
- if (templ->inheritedNsNr != 0) {
- xsltGenericDebug(xsltGenericDebugContext,
- "xsl:template has %d inherited namespaces\n",
- templ->inheritedNsNr);
- }
-#endif
- }
+ templ->style = cctxt->style;
/*
* Attribute "mode".
/*
* TODO: We need a standardized function for extraction
* of namespace names and local names from QNames.
+ * Don't use xsltGetQNameURI() as it cannot channeƶ
+ * reports through the context.
*/
modeURI = xsltGetQNameURI(templNode, &prop);
if (prop == NULL) {
const xmlChar *nameURI;
xsltTemplatePtr curTempl;
+ /*
+ * TODO: Don't use xsltGetQNameURI().
+ */
nameURI = xsltGetQNameURI(templNode, &prop);
if (prop == NULL) {
cctxt->style->errors++;
if (prop != NULL) {
const xmlChar *URI;
+ /*
+ * TODO: Don't use xsltGetQNameURI().
+ */
URI = xsltGetQNameURI(template, &prop);
if (prop == NULL) {
if (style != NULL) style->errors++;
const xmlChar *URI;
xsltTemplatePtr cur;
+ /*
+ * TODO: Don't use xsltGetQNameURI().
+ */
URI = xsltGetQNameURI(template, &prop);
if (prop == NULL) {
if (style != NULL) style->errors++;
/* ==================================================================== */
#ifdef XSLT_REFACTORED
+
+extern const xmlChar *xsltXSLTAttrMarker;
+
/* TODO: REMOVE: #define XSLT_REFACTORED_EXCLRESNS */
/* TODO: REMOVE: #define XSLT_REFACTORED_NSALIAS */
* Internal define to enable the pointer-comparison of
* namespaces of XSLT elements.
*/
-#define XSLT_REFACTORED_XSLT_NSCOMP
+/* #define XSLT_REFACTORED_XSLT_NSCOMP */
/**
* XSLT_REFACTORED_XPATHCOMP
typedef xsltNsListContainer *xsltNsListContainerPtr;
struct _xsltNsListContainer {
xmlNsPtr *list;
- int number;
+ int totalNumber;
+ int xpathNumber;
};
/**
struct _xsltStyleItemElement {
XSLT_ITEM_COMMON_FIELDS
- const xmlChar *use; /* copy, element */
- int has_use; /* copy, element */
- const xmlChar *name; /* element, attribute, pi */
- int has_name; /* element, attribute, pi */
- const xmlChar *ns; /* element */
- int has_ns; /* element */
-
+ const xmlChar *use;
+ int has_use;
+ const xmlChar *name;
+ int has_name;
+ const xmlChar *ns;
+ const xmlChar *nsPrefix;
+ int has_ns;
};
/**
struct _xsltStyleItemAttribute {
XSLT_ITEM_COMMON_FIELDS
- const xmlChar *name; /* element, attribute, pi */
- int has_name; /* element, attribute, pi */
- const xmlChar *ns; /* element attribute */
- int has_ns; /* element attribute */
+ const xmlChar *name;
+ int has_name;
+ const xmlChar *ns;
+ const xmlChar *nsPrefix;
+ int has_ns;
};
/**
typedef xsltStyleItemApplyTemplates *xsltStyleItemApplyTemplatesPtr;
struct _xsltStyleItemApplyTemplates {
- XSLT_ITEM_COMMON_FIELDS
+ XSLT_ITEM_COMMON_FIELDS
const xmlChar *mode; /* apply-templates */
const xmlChar *modeURI; /* apply-templates */
#ifdef XSLT_REFACTORED
if (comp->inScopeNs != NULL) {
ctxt->xpathCtxt->namespaces = comp->inScopeNs->list;
- ctxt->xpathCtxt->nsNr = comp->inScopeNs->number;
+ ctxt->xpathCtxt->nsNr = comp->inScopeNs->xpathNumber;
} else {
ctxt->xpathCtxt->namespaces = NULL;
ctxt->xpathCtxt->nsNr = 0;