+Fri May 12 23:23:06 CEST 2006 Kasimier Buchcik <libxml2-cvs@cazic.net>
+
+ * libxslt/documents.c libxslt/namespaces.c
+ libxslt/preproc.c libxslt/transform.c
+ libxslt/xslt.c libxslt/xsltInternals.h libxslt/xsltutils.c:
+ Next step of refactoring. For more details see bug #341588.
+ I applied the suggestion of Jerome Pesenti to the refactored
+ (still IDFEDed out with XSLT_REFACTORED) code: The XPath
+ compilation context (accessible via the compilation context)
+ is now reused for compilation of expressions at
+ compilation-time; this should reduce compilation time to 50%
+ for avarage stylesheets.
+
Thu May 11 22:12:22 CEST 2006 Kasimier Buchcik <libxml2-cvs@cazic.net>
* libxslt/extensions.c: Changed a comment to indicate that a
void
xsltFreeStyleDocuments(xsltStylesheetPtr style) {
xsltDocumentPtr doc, cur;
-#ifdef XSLT_REFACTORED
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP
xsltNsMapPtr nsMap;
#endif
if (style == NULL)
return;
-#ifdef XSLT_REFACTORED
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP
if (XSLT_HAS_INTERNAL_NSMAP(style))
nsMap = XSLT_GET_INTERNAL_NSMAP(style);
else
nsMap = NULL;
-#endif
+#endif
cur = style->docList;
while (cur != NULL) {
doc = cur;
cur = cur->next;
-
-#ifdef XSLT_REFACTORED
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP
/*
* Restore all changed namespace URIs of ns-decls.
*/
if (nsMap)
xsltRestoreDocumentNamespaces(nsMap, doc->doc);
#endif
-
xsltFreeDocumentKeys(doc);
if (!doc->main)
xmlFreeDoc(doc->doc);
* *
************************************************************************/
+#ifdef XSLT_REFACTORED
+static xsltNsAliasPtr
+xsltNewNsAlias(xsltCompilerCtxtPtr cctxt)
+{
+ xsltNsAliasPtr ret;
+
+ if (cctxt == NULL)
+ return(NULL);
+
+ ret = (xsltNsAliasPtr) xmlMalloc(sizeof(xsltNsAlias));
+ if (ret == NULL) {
+ xsltTransformError(NULL, cctxt->style, NULL,
+ "Internal error in xsltNewNsAlias(): Memory allocation failed.\n");
+ cctxt->style->errors++;
+ return(NULL);
+ }
+ memset(ret, 0, sizeof(xsltNsAlias));
+ /*
+ * TODO: Store the item at current stylesheet-level.
+ */
+ ret->next = cctxt->nsAliases;
+ cctxt->nsAliases = ret;
+
+ return(ret);
+}
+#endif /* XSLT_REFACTORED */
/**
* xsltNamespaceAlias:
* @style: the XSLT stylesheet
* them as well as the corresponding namespace.
*/
void
-xsltNamespaceAlias(xsltStylesheetPtr style, xmlNodePtr node) {
- xmlChar *sprefix;
- xmlNsPtr sNs;
- const xmlChar *shref;
- xmlChar *rprefix;
- xmlNsPtr rNs;
- const xmlChar *rhref;
-
- sprefix = xmlGetNsProp(node, (const xmlChar *)"stylesheet-prefix", NULL);
- if (sprefix == NULL) {
+xsltNamespaceAlias(xsltStylesheetPtr style, xmlNodePtr node)
+{
+ xmlChar *resultPrefix = NULL;
+ xmlChar *stylePrefix = NULL;
+ xmlNsPtr literalNs = NULL;
+ xmlNsPtr targetNs = NULL;
+
+#ifdef XSLT_REFACTORED
+ xsltNsAliasPtr alias;
+
+ if ((style == NULL) || (node == NULL))
+ return;
+
+ /*
+ * SPEC XSLT 1.0:
+ * "If a namespace URI is declared to be an alias for multiple
+ * different namespace URIs, then the declaration with the highest
+ * import precedence is used. It is an error if there is more than
+ * one such declaration. An XSLT processor may signal the error;
+ * if it does not signal the error, it must recover by choosing,
+ * from amongst the declarations with the highest import precedence,
+ * the one that occurs last in the stylesheet."
+ *
+ * SPEC TODO: Check for the errors mentioned above.
+ */
+ /*
+ * NOTE that the XSLT 2.0 also *does* use the NULL namespace if
+ * "#default" is used and there's no default namespace is scope.
+ * I.e., this is *not* an error.
+ * Most XSLT 1.0 implementations work this way.
+ * The XSLT 1.0 spec has nothing to say on the subject.
+ */
+ /*
+ * Attribute "stylesheet-prefix".
+ */
+ stylePrefix = xmlGetNsProp(node, (const xmlChar *)"stylesheet-prefix", NULL);
+ if (stylePrefix == NULL) {
+ xsltTransformError(NULL, style, node,
+ "The attribute 'stylesheet-prefix' is missing.\n");
+ return;
+ }
+ if (xmlStrEqual(stylePrefix, (const xmlChar *)"#default"))
+ literalNs = xmlSearchNs(node->doc, node, NULL);
+ else {
+ literalNs = xmlSearchNs(node->doc, node, stylePrefix);
+ if (literalNs == NULL) {
+ xsltTransformError(NULL, style, node,
+ "Attribute 'stylesheet-prefix': There's no namespace "
+ "declaration in scope for the prefix '%s'.\n",
+ stylePrefix);
+ goto error;
+ }
+ }
+ /*
+ * Attribute "result-prefix".
+ */
+ resultPrefix = xmlGetNsProp(node, (const xmlChar *)"result-prefix", NULL);
+ if (resultPrefix == NULL) {
+ xsltTransformError(NULL, style, node,
+ "The attribute 'result-prefix' is missing.\n");
+ goto error;
+ }
+ if (xmlStrEqual(resultPrefix, (const xmlChar *)"#default"))
+ targetNs = xmlSearchNs(node->doc, node, NULL);
+ else {
+ targetNs = xmlSearchNs(node->doc, node, resultPrefix);
+
+ if (targetNs == NULL) {
+ xsltTransformError(NULL, style, node,
+ "Attribute 'result-prefix': There's no namespace "
+ "declaration in scope for the prefix '%s'.\n",
+ stylePrefix);
+ goto error;
+ }
+ }
+ /*
+ *
+ * Same alias for multiple different target namespace URIs:
+ * TODO: The one with the highest import precedence is used.
+ * Example:
+ * <xsl:namespace-alias stylesheet-prefix="foo"
+ * result-prefix="bar"/>
+ *
+ * <xsl:namespace-alias stylesheet-prefix="foo"
+ * result-prefix="zar"/>
+ *
+ * Same target namespace URI for multiple different aliases:
+ * All alias-definitions will be used.
+ * Example:
+ * <xsl:namespace-alias stylesheet-prefix="bar"
+ * result-prefix="foo"/>
+ *
+ * <xsl:namespace-alias stylesheet-prefix="zar"
+ * result-prefix="foo"/>
+ * Cases using #default:
+ * <xsl:namespace-alias stylesheet-prefix="#default"
+ * result-prefix="#default"/>
+ * TODO: Has this an effect at all?
+ *
+ * <xsl:namespace-alias stylesheet-prefix="foo"
+ * result-prefix="#default"/>
+ * From namespace to no namespace.
+ *
+ * <xsl:namespace-alias stylesheet-prefix="#default"
+ * result-prefix="foo"/>
+ * From no namespace to namespace.
+ */
+
+
+ /*
+ * 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 */
+ const xmlChar *literalNsName;
+ const xmlChar *targetNsName;
+
+
+ if ((style == NULL) || (node == NULL))
+ return;
+
+ stylePrefix = xmlGetNsProp(node, (const xmlChar *)"stylesheet-prefix", NULL);
+ if (stylePrefix == NULL) {
xsltTransformError(NULL, style, node,
"namespace-alias: stylesheet-prefix attribute missing\n");
return;
}
- rprefix = xmlGetNsProp(node, (const xmlChar *)"result-prefix", NULL);
- if (rprefix == NULL) {
+ resultPrefix = xmlGetNsProp(node, (const xmlChar *)"result-prefix", NULL);
+ if (resultPrefix == NULL) {
xsltTransformError(NULL, style, node,
"namespace-alias: result-prefix attribute missing\n");
goto error;
}
- if (xmlStrEqual(sprefix, (const xmlChar *)"#default")) {
- /*
- * Do we have a default namespace previously declared?
- */
- sNs = xmlSearchNs(node->doc, node, NULL);
- if (sNs == NULL)
- shref = NULL; /* No - set NULL */
- else
- shref = sNs->href; /* Yes - set for nsAlias table */
+ if (xmlStrEqual(stylePrefix, (const xmlChar *)"#default")) {
+ literalNs = xmlSearchNs(node->doc, node, NULL);
+ if (literalNs == NULL) {
+ literalNsName = NULL;
+ } else
+ literalNsName = literalNs->href; /* Yes - set for nsAlias table */
} else {
- sNs = xmlSearchNs(node->doc, node, sprefix);
+ literalNs = xmlSearchNs(node->doc, node, stylePrefix);
- if ((sNs == NULL) || (sNs->href == NULL)) {
+ if ((literalNs == NULL) || (literalNs->href == NULL)) {
xsltTransformError(NULL, style, node,
"namespace-alias: prefix %s not bound to any namespace\n",
- sprefix);
+ stylePrefix);
goto error;
} else
- shref = sNs->href;
+ literalNsName = literalNs->href;
}
/*
* been explicitly declared the special value UNDEFINED_DEFAULT_NS is
* put into the nsAliases table
*/
- if (xmlStrEqual(rprefix, (const xmlChar *)"#default")) {
- rNs = xmlSearchNs(node->doc, node, NULL);
- if (rNs == NULL)
- rhref = UNDEFINED_DEFAULT_NS;
- else
- rhref = rNs->href;
+ if (xmlStrEqual(resultPrefix, (const xmlChar *)"#default")) {
+ targetNs = xmlSearchNs(node->doc, node, NULL);
+ if (targetNs == NULL) {
+ targetNsName = UNDEFINED_DEFAULT_NS;
+ } else
+ targetNsName = targetNs->href;
} else {
- rNs = xmlSearchNs(node->doc, node, rprefix);
+ targetNs = xmlSearchNs(node->doc, node, resultPrefix);
- if ((rNs == NULL) || (rNs->href == NULL)) {
+ if ((targetNs == NULL) || (targetNs->href == NULL)) {
xsltTransformError(NULL, style, node,
"namespace-alias: prefix %s not bound to any namespace\n",
- rprefix);
+ resultPrefix);
goto error;
} else
- rhref = rNs->href;
+ targetNsName = targetNs->href;
}
/*
- * Special case if #default is used for stylesheet and no default has
- * been explicitly declared. We use style->defaultAlias for this
- */
- if (shref == NULL) {
- if (rNs != NULL)
- style->defaultAlias = rNs->href;
+ * Special case: if #default is used for
+ * the stylesheet-prefix (literal namespace) and there's no default
+ * namespace in scope, we'll use style->defaultAlias for this.
+ */
+ if (literalNsName == NULL) {
+ if (targetNs != NULL) {
+ /*
+ * BUG TODO: Is it not sufficient to have only 1 field for
+ * this, since subsequently alias declarations will
+ * overwrite this.
+ * Example:
+ * <xsl:namespace-alias result-prefix="foo"
+ * stylesheet-prefix="#default"/>
+ * <xsl:namespace-alias result-prefix="bar"
+ * stylesheet-prefix="#default"/>
+ * The mapping for "foo" won't be visible anymore.
+ */
+ style->defaultAlias = targetNs->href;
+ }
} else {
if (style->nsAliases == NULL)
style->nsAliases = xmlHashCreate(10);
"namespace-alias: cannot create hash table\n");
goto error;
}
- xmlHashAddEntry((xmlHashTablePtr) style->nsAliases,
- shref, (void *) rhref);
+ xmlHashAddEntry((xmlHashTablePtr) style->nsAliases,
+ literalNsName, (void *) targetNsName);
}
+#endif /* else of XSLT_REFACTORED */
error:
- if (sprefix != NULL)
- xmlFree(sprefix);
- if (rprefix != NULL)
- xmlFree(rprefix);
+ if (stylePrefix != NULL)
+ xmlFree(stylePrefix);
+ if (resultPrefix != NULL)
+ xmlFree(resultPrefix);
}
/**
* 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)
*
* Returns the namespace node to use or NULL
*/
xmlNsPtr
xsltGetPlainNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur,
- xmlNsPtr ns, xmlNodePtr out) {
- xsltStylesheetPtr style;
+ xmlNsPtr ns, xmlNodePtr out) {
xmlNsPtr ret;
const xmlChar *URI = NULL; /* the replacement URI */
if ((ctxt == NULL) || (cur == NULL) || (out == NULL) || (ns == NULL))
return(NULL);
- 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);
+#ifdef XSLT_REFACTORED
+ /*
+ * Namespace exclusion and ns-aliasing is performed at
+ * compilation-time in the refactored code.
+ */
+ 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;
+
+ style = xsltNextImport(style);
+ }
}
if (URI == UNDEFINED_DEFAULT_NS) {
if (URI == NULL)
URI = ns->href;
+#endif
if ((out->parent != NULL) &&
(out->parent->type == XML_ELEMENT_NODE) &&
(out->parent->type == XML_ELEMENT_NODE) &&
(out->parent->ns != NULL) &&
(xmlStrEqual(out->parent->ns->href, URI)))
+ {
ret = out->parent->ns;
- else
+ } else
ret = xmlSearchNsByHref(out->doc, out, URI);
if ((ret == NULL) || (ret->prefix == 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 the right namespace value for this prefix, if needed create
* and add a new namespace decalaration on the node
* Handle namespace aliases
*/
xmlNsPtr
xsltGetNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur, xmlNsPtr ns,
- xmlNodePtr out) {
- xsltStylesheetPtr style;
+ xmlNodePtr out) {
xmlNsPtr ret;
const xmlChar *URI = NULL; /* the replacement URI */
if ((ctxt == NULL) || (cur == NULL) || (out == NULL) || (ns == NULL))
return(NULL);
-
- style = ctxt->style;
- while (style != NULL) {
- if (style->nsAliases != NULL)
- URI = (const xmlChar *)
+
+#ifdef XSLT_REFACTORED
+ /*
+ * Namespace exclusion and ns-aliasing is performed at
+ * compilation-time in the refactored code.
+ */
+ 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;
-
- style = xsltNextImport(style);
+ if (URI != NULL)
+ break;
+
+ style = xsltNextImport(style);
+ }
}
if (URI == UNDEFINED_DEFAULT_NS) {
xmlNsPtr dflt;
+ /*
+ */
dflt = xmlSearchNs(cur->doc, cur, NULL);
if (dflt != NULL)
URI = dflt->href;
return NULL;
} else if (URI == NULL)
URI = ns->href;
-
+#endif
/*
* If the parent is an XML_ELEMENT_NODE, and has the "equivalent"
* namespace as ns (either both default, or both with a prefix
*
* Do a copy of an namespace list. If @node is non-NULL the
* new namespaces are added automatically. This handles namespaces
- * aliases
+ * aliases.
+ * This function is intended only for *internal* use at
+ * transformation-time. Use it *only* for copying ns-decls of
+ * literal result elements.
+ *
+ * Called by:
+ * xsltCopyTree() (transform.c)
+ * xsltCopyNode() (transform.c)
*
* Returns: a new xmlNsPtr, or NULL in case of error.
*/
xsltCopyNamespaceList(xsltTransformContextPtr ctxt, xmlNodePtr node,
xmlNsPtr cur) {
xmlNsPtr ret = NULL, tmp;
- xmlNsPtr p = NULL,q;
- const xmlChar *URI;
+ xmlNsPtr p = NULL,q;
if (cur == NULL)
return(NULL);
break;
/*
- * Avoid duplicating namespace declrations on the tree
+ * Avoid duplicating namespace declarations in the tree if
+ * a matching declaration is in scope.
*/
if (node != NULL) {
if ((node->ns != NULL) &&
- (xmlStrEqual(node->ns->href, cur->href)) &&
- (xmlStrEqual(node->ns->prefix, cur->prefix))) {
+ (xmlStrEqual(node->ns->prefix, cur->prefix)) &&
+ (xmlStrEqual(node->ns->href, cur->href))) {
cur = cur->next;
continue;
}
continue;
}
}
-
+#ifdef XSLT_REFACTORED
+ /*
+ * Namespace exclusion and ns-aliasing is performed at
+ * compilation-time in the refactored code.
+ */
+ q = xmlNewNs(node, cur->href, cur->prefix);
+ if (p == NULL) {
+ ret = p = q;
+ } else {
+ p->next = q;
+ p = q;
+ }
+#else
if (!xmlStrEqual(cur->href, XSLT_NAMESPACE)) {
+ const xmlChar *URI;
/* TODO apply cascading */
URI = (const xmlChar *) xmlHashLookup(ctxt->style->nsAliases,
cur->href);
p = q;
}
}
+#endif
cur = cur->next;
}
return(ret);
xsltCopyNamespace(xsltTransformContextPtr ctxt, xmlNodePtr node,
xmlNsPtr cur) {
xmlNsPtr ret = NULL;
- const xmlChar *URI;
-
+
if (cur == NULL)
return(NULL);
if (cur->type != XML_NAMESPACE_DECL)
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)
ret = xmlNewNs(node, cur->href, cur->prefix);
}
}
+#endif
return(ret);
}
return(cur);
}
+#ifdef XSLT_REFACTORED
+static void
+xsltLREEffectiveNsNodesFree(xsltEffectiveNsPtr first)
+{
+ xsltEffectiveNsPtr tmp;
+
+ while (first != NULL) {
+ tmp = first;
+ first = first->next;
+ xmlFree(tmp);
+ }
+}
+#endif
+
/**
* xsltFreeStylePreComp:
* @comp: an XSLT Style precomputed block
* URGENT TODO: Implement destructors.
*/
switch (comp->type) {
+ case XSLT_FUNC_LITERAL_RESULT_ELEMENT: {
+ xsltStyleItemLRElementInfoPtr item =
+ (xsltStyleItemLRElementInfoPtr) comp;
+ if (item->effectiveNs)
+ xsltLREEffectiveNsNodesFree(item->effectiveNs);
+ }
+ break;
case XSLT_FUNC_COPY:
break;
case XSLT_FUNC_SORT: {
xmlXPathFreeCompExpr(item->comp);
}
break;
- case XSLT_FUNC_OTHERWISE:
+ case XSLT_FUNC_OTHERWISE:
+ case XSLT_FUNC_FALLBACK:
+ case XSLT_FUNC_MESSAGE:
+ case XSLT_FUNC_INCLUDE:
+ case XSLT_FUNC_ATTRSET:
+
break;
default:
/* TODO: Raise error. */
*
* 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.
+ * Called from:
+ * xsltApplyOneTemplateInt()
+ * xsltCopy()
*
* Returns a pointer to the new node, or NULL in case of error
*/
*
* Do a copy of a namespace list. If @node is non-NULL the
* new namespaces are added automatically.
+ * Called by:
+ * xsltCopyTree()
+ *
+ * TODO: What is the exact difference between this function
+ * and xsltCopyNamespaceList() in "namespaces.c"?
*
* Returns: a new xmlNsPtr, or NULL in case of error.
*/
xmlNsPtr *nsList, *cur, ns;
/*
* must add in any new namespaces in scope for the node
+ * REVISIT:
+ * Question: Do we really have to add every namespace in scope?
+ * Answer: I think yes, since if we are only adding the
+ * ns-decls which are declared on this element and actually
+ * referenced by this element/attribute, then we would miss
+ * ns-decls for QName in element/attribute content.
*/
nsList = xmlGetNsList(node->doc, node);
if (nsList != NULL) {
xmlNodePtr child;
int ret = 0;
- if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
- return(ret);
+ if ((ctxt == NULL) || (node == NULL) || (inst == NULL) ||
+ (inst->children == NULL))
+ return(0);
child = inst->children;
while (child != NULL) {
}
}
+/**
+* xsltTransLREAcquireInScopeNs:
+* @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.
+*/
+xmlNsPtr
+xsltTransLREAcquireInScopeNs(xsltTransformContextPtr ctxt,
+ xmlNodePtr cur, xmlNsPtr literalNs,
+ xmlNodePtr resultElem)
+{
+ xmlNsPtr ns;
+ int prefixOccupied = 0;
+
+ if ((ctxt == NULL) || (cur == NULL) ||
+ (resultElem == NULL) || (literalNs == 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.
+ */
+#if 0
+ ns = xmlSearchNsByHref(resultElem->doc, resultElem,
+ literalNs->href);
+ if (ns != NULL)
+ return(ns);
+#endif
+ /*
+ * 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);
+}
/**
* xsltApplyOneTemplate:
xmlNodePtr oldInst = NULL;
int oldBase;
xmlDocPtr tmpRVT = NULL;
+#ifdef XSLT_REFACTORED
+ xsltStylePreCompPtr info;
+#endif
int level = 0;
if (insert == NULL) {
#ifdef WITH_XSLT_DEBUG_PROCESS
XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
- "xsltApplyOneTemplate: insert == NULL !\n"));
+ "xsltApplyOneTemplateInt: insert == NULL !\n"));
#endif
goto error;
}
#endif
#ifdef XSLT_REFACTORED
- if (IS_XSLT_ELEM_FAST(cur)) {
-#else
- if (IS_XSLT_ELEM(cur)) {
+ if (cur->type == XML_ELEMENT_NODE) {
+ info = (xsltStylePreCompPtr) cur->psvi;
+ /*
+ * We expect a compiled representation on:
+ * 1) XSLT instructions of this XSLT version (1.0)
+ * (with a few exceptions)
+ * 2) Literal result elements
+ * 3) Extension instructions
+ * 4) XSLT instructions of future XSLT versions
+ * (forwards-compatible mode).
+ */
+ if (info == NULL) {
+ /*
+ * Handle the rare cases where we don't expect a compiled
+ * representation on an XSLT element.
+ */
+ if (IS_XSLT_ELEM_FAST(cur) && IS_XSLT_NAME(cur, "message")) {
+ xsltMessage(ctxt, node, cur);
+ goto skip_children;
+ }
+ /*
+ * Something really went wrong:
+ */
+ xsltTransformError(ctxt, NULL, cur,
+ "Internal error in xsltApplyOneTemplateInt(): "
+ "The element '%s' in the stylesheet has no compiled "
+ "representation.\n",
+ cur->name);
+ goto skip_children;
+ }
+
+ if (info->type == XSLT_FUNC_LITERAL_RESULT_ELEMENT) {
+ xsltStyleItemLRElementInfoPtr lrInfo =
+ (xsltStyleItemLRElementInfoPtr) info;
+ /*
+ * Literal result elements
+ * --------------------------------------------------------
+ */
+#ifdef WITH_XSLT_DEBUG_PROCESS
+ XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
+ xsltGenericDebug(xsltGenericDebugContext,
+ "xsltApplyOneTemplateInt: copy literal result "
+ "element '%s'\n", cur->name));
#endif
+ /*
+ * Copy the raw element-node.
+ * OLD: if ((copy = xsltCopyNode(ctxt, cur, insert)) == NULL)
+ * goto error;
+ */
+ copy = xmlDocCopyNode(cur, insert->doc, 0);
+ if (copy == NULL) {
+ xsltTransformError(ctxt, NULL, cur,
+ "Internal error in xsltApplyOneTemplateInt(): "
+ "Failed to copy literal result element '%s'.\n",
+ cur->name);
+ goto error;
+ } else {
+ /*
+ * Add the element-node to the result tree.
+ */
+ copy->doc = ctxt->output;
+ xmlAddChild(insert, copy);
+ /*
+ * Create effective namespaces declarations.
+ * OLD: xsltCopyNamespaceList(ctxt, copy, cur->nsDef);
+ */
+ if (lrInfo->effectiveNs != NULL) {
+ xsltEffectiveNsPtr effNs = lrInfo->effectiveNs;
+ xmlNsPtr ns, lastns = NULL;
+
+ while (effNs != NULL) {
+ /*
+ * Avoid generating redundant namespace
+ * declarations; thus lookup if there is already
+ * such a ns-decl in the result.
+ */
+ ns = xmlSearchNs(copy->doc, copy,
+ effNs->prefix);
+ if ((ns != NULL) &&
+ (xmlStrEqual(ns->href, effNs->nsName)))
+ {
+ effNs = effNs->next;
+ continue;
+ }
+ ns = xmlNewNs(copy, effNs->nsName,
+ effNs->prefix);
+ if (ns == NULL) {
+ xsltTransformError(ctxt, NULL, cur,
+ "Internal error in xsltApplyOneTemplateInt(): "
+ "Failed to copy a namespace declaration.\n");
+ goto error;
+ }
+
+ if (lastns == NULL)
+ copy->nsDef = ns;
+ else
+ lastns->next =ns;
+ lastns = ns;
+
+ effNs = effNs->next;
+ }
+
+ }
+ /*
+ * NOTE that we don't need to apply ns-alising: this was
+ * already done at compile-time.
+ */
+ 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 = xsltTransLREAcquireInScopeNs(ctxt,
+ cur, cur->ns, copy);
+ } else if ((insert->type == XML_ELEMENT_NODE) &&
+ (insert->ns != NULL))
+ {
+ xmlNsPtr defaultNs;
+
+ /*
+ * Undeclare the default namespace if needed.
+ * REVISIT TODO: This might result in massive
+ * generation of ns-decls if nodes in a default
+ * namespaces are mixed with nodes in no namespace.
+ *
+ */
+ defaultNs = xmlSearchNs(insert->doc, insert, NULL);
+ if ((defaultNs != NULL) && (defaultNs->href != NULL))
+ xmlNewNs(copy, BAD_CAST "", NULL);
+ }
+ }
+ /*
+ * SPEC XSLT 2.0 "Each attribute of the literal result
+ * element, other than an attribute in the XSLT namespace,
+ * is processed to produce an attribute for the element in
+ * the result tree."
+ * TODO: Refactor this, since it still uses ns-aliasing.
+ */
+ 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
+ * --------------------------------------------------------
+ */
+ if (info->type == XSLT_FUNC_UNKOWN_FORWARDS_COMPAT) {
+ /*
+ * We hit an unknown XSLT element.
+ * Try to apply one of the fallback cases.
+ */
+ ctxt->insert = insert;
+ if (!xsltApplyFallbacks(ctxt, node, cur)) {
+ xsltTransformError(ctxt, NULL, cur,
+ "The is no fallback behaviour defined for "
+ "the unknown XSLT element '%s'.\n",
+ cur->name);
+ }
+ ctxt->insert = oldInsert;
+ goto skip_children;
+ }
+ /*
+ * Execute the XSLT instruction.
+ */
+ if (info->func != NULL) {
+ ctxt->insert = insert;
+ info->func(ctxt, node, cur, (xsltElemPreCompPtr) info);
+ ctxt->insert = oldInsert;
+ goto skip_children;
+ }
+ /*
+ * Some XSLT instructions need custom execution.
+ */
+ if (info->type == XSLT_FUNC_VARIABLE) {
+ if (level != 0) {
+ /*
+ * Build a new subframe and skip all the nodes
+ * at that level.
+ */
+ ctxt->insert = insert;
+ xsltApplyOneTemplateInt(ctxt, node, cur, NULL, NULL, 0);
+ while (cur->next != NULL)
+ cur = cur->next;
+ ctxt->insert = oldInsert;
+ } else {
+ xsltParseStylesheetVariable(ctxt, cur);
+ }
+ } else if (info->type == XSLT_FUNC_PARAM) {
+ xsltParseStylesheetParam(ctxt, cur);
+ } else if (info->type == XSLT_FUNC_MESSAGE) {
+ /*
+ * TODO: Won't be hit, since we don't compile xsl:message.
+ */
+ xsltMessage(ctxt, node, cur);
+ } else {
+ xsltGenericError(xsltGenericErrorContext,
+ "Internal error in xsltApplyOneTemplateInt(): "
+ "Don't know how to process the XSLT element "
+ "'%s'.\n", cur->name);
+ }
+ goto skip_children;
+
+ } else {
+ xsltTransformFunction func;
+ /*
+ * Extension intructions (elements)
+ * --------------------------------------------------------
+ */
+ if (cur->psvi == xsltExtMarker) {
+ /*
+ * The xsltExtMarker was set during the compilation
+ * of extension instructions if there was no registered
+ * handler for this specific extension function at
+ * compile-time.
+ * Libxslt will now lookup if a handler is
+ * registered in the context of this transformation.
+ */
+ func = (xsltTransformFunction)
+ xsltExtElementLookup(ctxt, cur->name, cur->ns->href);
+ } else
+ func = ((xsltElemPreCompPtr) cur->psvi)->func;
+
+ if (func == NULL) {
+ /*
+ * No handler available.
+ * Try to execute fallback behaviour via xsl:fallback.
+ */
+#ifdef WITH_XSLT_DEBUG_PROCESS
+ XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
+ xsltGenericDebug(xsltGenericDebugContext,
+ "xsltApplyOneTemplate: unknown extension %s\n",
+ cur->name));
+#endif
+ ctxt->insert = insert;
+ if (!xsltApplyFallbacks(ctxt, node, cur)) {
+ xsltTransformError(ctxt, NULL, cur,
+ "Unknown extension instruction '{%s}%s'.\n",
+ cur->ns->href, cur->name);
+ }
+ ctxt->insert = oldInsert;
+ } else {
+ /*
+ * Execute the handler-callback.
+ */
+#ifdef WITH_XSLT_DEBUG_PROCESS
+ XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
+ "xsltApplyOneTemplate: extension construct %s\n",
+ cur->name));
+#endif
+ ctxt->insert = insert;
+ func(ctxt, node, cur, cur->psvi);
+ ctxt->insert = oldInsert;
+ }
+ goto skip_children;
+ }
+
+ } else if (XSLT_IS_TEXT_NODE(cur)) {
+ /*
+ * Text
+ * ------------------------------------------------------------
+ */
+#ifdef WITH_XSLT_DEBUG_PROCESS
+ if (cur->name == xmlStringTextNoenc) {
+ XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
+ xsltGenericDebug(xsltGenericDebugContext,
+ "xsltApplyOneTemplateInt: copy unescaped text '%s'\n",
+ cur->content));
+ } else {
+ XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
+ xsltGenericDebug(xsltGenericDebugContext,
+ "xsltApplyOneTemplateInt: copy text '%s'\n",
+ cur->content));
+ }
+#endif
+ if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL)
+ goto error;
+ }
+
+#else /* XSLT_REFACTORED */
+
+ if (IS_XSLT_ELEM(cur)) {
/*
* This is an XSLT node
*/
goto skip_children;
} else if ((cur->type == XML_TEXT_NODE) ||
(cur->type == XML_CDATA_SECTION_NODE)) {
+
/*
* This text comes from the stylesheet
* For stylesheets, the set of whitespace-preserving
/*
* Add extra namespaces inherited from the current template
* if we are in the first level children and this is a
- * "real" template.
+ * "real" template.
*/
if ((templ != NULL) && (oldInsert == insert) &&
(ctxt->templ != NULL) && (ctxt->templ->inheritedNs != NULL)) {
style = xsltNextImport(style);
}
-
+
if (URI == UNDEFINED_DEFAULT_NS) {
xmlNsPtr dflt;
dflt = xmlSearchNs(cur->doc, cur, NULL);
}
}
}
+#endif /* else of XSLT_REFACTORED */
/*
- * Skip to next node, in document order.
+ * Descend into content in document order.
*/
if (cur->children != NULL) {
if (cur->children->type != XML_ENTITY_DECL) {
continue;
}
}
- skip_children:
+
+skip_children:
/*
- If xslt:message just processed, might have terminate='yes'
- If so, break out of while to clean up processing.
+ * If xslt:message was just processed, we might have hit a
+ * terminate='yes'; if so, then break the loop and clean up.
+ * TODO: Do we need to check this also before trying to descend
+ * into the content?
*/
if (ctxt->state == XSLT_STATE_STOPPED)
break;
* @inst: the xslt copy node
* @comp: precomputed information
*
- * Process the xslt copy node on the source node
+ * Execute the xsl:copy instruction on the source node.
*/
void
xsltCopy(xsltTransformContextPtr ctxt, xmlNodePtr node,
#include <libxml/xmlerror.h>
#include <libxml/parserInternals.h>
#include <libxml/xpathInternals.h>
+#include <libxml/xpath.h>
#include "xslt.h"
#include "xsltInternals.h"
#include "pattern.h"
const xmlChar *xsltConstNamespaceNameXSLT= (const xmlChar *) XSLT_NAMESPACE;
-static const xmlChar *xsltLibxsltDataElementNameMeta =
- (const xmlChar *) "meta";
-
-static const xmlChar *xsltLibxsltDataElementNamespaceMeta =
- (const xmlChar *) XSLT_DEFAULT_URL;
-
-static const xmlChar *xsltUserDataElemMarker =
- (const xmlChar *) "User Data Element";
-
/*
* xsltLiteralResultMarker:
* Marker for Literal result elements, in order to avoid multiple attempts
}
#ifdef XSLT_REFACTORED
-/**
- * xsltCompilerCreate:
- *
- * Create an XSLT compiler context.
- *
- * Returns the allocated xsltCompilerCtxtPtr or NULL in case of error.
- */
-static xsltCompilerCtxtPtr
-xsltCompilerCreate(xsltStylesheetPtr style) {
- xsltCompilerCtxtPtr ret;
-
- ret = (xsltCompilerCtxtPtr) xmlMalloc(sizeof(xsltCompilerCtxt));
- if (ret == NULL) {
- xsltTransformError(NULL, style, NULL,
- "xsltCompilerCreate: allocation of compiler "
- "context failed.\n");
- return(NULL);
- }
- memset(ret, 0, sizeof(xsltCompilerCtxt));
-
- ret->errSeverity = XSLT_ERROR_SEVERITY_ERROR;
-
- style->compCtxt = (void *) ret;
- ret->style = style;
- ret->tmpList = xsltPointerListCreate(20);
- if (ret->tmpList == NULL) {
- xmlFree(ret);
- return(NULL);
- }
- ret->dict = style->dict;
- return(ret);
-}
static void
-xsltCompilerCtxtFree(xsltCompilerCtxtPtr cctxt)
-{
- if (cctxt == NULL)
- return;
- /*
- * Free node-infos.
- */
- if (cctxt->inodeList != NULL) {
- xsltCompilerNodeInfoPtr tmp, cur = cctxt->inodeList;
- while (cur != NULL) {
- tmp = cur;
- cur = cur->next;
- xmlFree(tmp);
- }
- }
- if (cctxt->tmpList != NULL)
- xsltPointerListFree(cctxt->tmpList);
- xmlFree(cctxt);
+xsltFreeNsAliasList(xsltNsAliasPtr item)
+{
+ xsltNsAliasPtr tmp;
+
+ while (item) {
+ tmp = item;
+ item = item->next;
+ xmlFree(tmp);
+ }
+ return;
}
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP
static void
xsltFreeNamespaceMap(xsltNsMapPtr item)
{
return(ret);
}
+#endif /* XSLT_REFACTORED_XSLT_NSCOMP */
+
+/**
+ * xsltCompilerCtxtFree:
+ *
+ * Free an XSLT compiler context.
+ */
+static void
+xsltCompilationCtxtFree(xsltCompilerCtxtPtr cctxt)
+{
+ if (cctxt == NULL)
+ return;
+ /*
+ * Free node-infos.
+ */
+ if (cctxt->inodeList != NULL) {
+ xsltCompilerNodeInfoPtr tmp, cur = cctxt->inodeList;
+ while (cur != NULL) {
+ tmp = cur;
+ cur = cur->next;
+ xmlFree(tmp);
+ }
+ }
+ if (cctxt->tmpList != NULL)
+ xsltPointerListFree(cctxt->tmpList);
+ if (cctxt->xpathCtxt != NULL)
+ xmlXPathFreeContext(cctxt->xpathCtxt);
+ if (cctxt->nsAliases != NULL)
+ xsltFreeNsAliasList(cctxt->nsAliases);
+
+ xmlFree(cctxt);
+}
+
+/**
+ * xsltCompilerCreate:
+ *
+ * Creates an XSLT compiler context.
+ *
+ * Returns the pointer to the created xsltCompilerCtxt or
+ * NULL in case of an internal error.
+ */
+static xsltCompilerCtxtPtr
+xsltCompilationCtxtCreate(xsltStylesheetPtr style) {
+ xsltCompilerCtxtPtr ret;
+
+ ret = (xsltCompilerCtxtPtr) xmlMalloc(sizeof(xsltCompilerCtxt));
+ if (ret == NULL) {
+ xsltTransformError(NULL, style, NULL,
+ "xsltCompilerCreate: allocation of compiler "
+ "context failed.\n");
+ return(NULL);
+ }
+ memset(ret, 0, sizeof(xsltCompilerCtxt));
+
+ ret->errSeverity = XSLT_ERROR_SEVERITY_ERROR;
+ ret->tmpList = xsltPointerListCreate(20);
+ if (ret->tmpList == NULL) {
+ goto internal_err;
+ }
+ /*
+ * Create the XPath compilation context in order
+ * to speed up precompilation of XPath expressions.
+ */
+ ret->xpathCtxt = xmlXPathNewContext(NULL);
+ if (ret->xpathCtxt == NULL)
+ goto internal_err;
+
+ return(ret);
+
+internal_err:
+ xsltCompilationCtxtFree(ret);
+ return(NULL);
+}
+
static void
xsltFreePrincipalStylesheetData(xsltPrincipalStylesheetDataPtr data)
if (data->inScopeNamespaces != NULL) {
int i;
- xsltNsListPtr nsi;
+ xsltNsListContainerPtr nsi;
xsltPointerListPtr list =
(xsltPointerListPtr) data->inScopeNamespaces;
/*
* REVISIT TODO: Free info of in-scope namespaces.
*/
- nsi = (xsltNsListPtr) list->items[i];
+ nsi = (xsltNsListContainerPtr) list->items[i];
if (nsi->list != NULL)
xmlFree(nsi->list);
xmlFree(nsi);
xsltPointerListFree(list);
data->extElemNamespaces = NULL;
}
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP
xsltFreeNamespaceMap(data->nsMap);
+#endif
xmlFree(data);
}
goto internal_err;
/*
* Global list of excluded result ns-decls.
- */
+ */
ret->exclResultNamespaces = xsltPointerListCreate(-1);
if (ret->exclResultNamespaces == NULL)
goto internal_err;
/*
- * Global list of extension element namespace names.
+ * Global list of extension instruction namespace names.
*/
ret->extElemNamespaces = xsltPointerListCreate(-1);
if (ret->extElemNamespaces == NULL)
*/
static int
xsltCleanupStylesheetTree(xmlDocPtr doc, xmlNodePtr rootElem)
-{
+{
+#if 0 /* TODO: Currently disabled, since probably not needed. */
xmlNodePtr cur;
if ((doc == NULL) || (rootElem == NULL) ||
goto leave_node;
}
}
+#endif /* #if 0 */
return(0);
}
if ((style->principal == style) && (style->doc))
xsltCleanupStylesheetTree(style->doc,
xmlDocGetRootElement(style->doc));
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP
/*
* Restore changed ns-decls before freeing the document.
*/
xsltRestoreDocumentNamespaces(XSLT_GET_INTERNAL_NSMAP(style),
style->doc);
}
+#endif /* XSLT_REFACTORED_XSLT_NSCOMP */
#else
/*
* Start with a cleanup of the main stylesheet's doc.
if ((style->parent == NULL) && (style->doc))
xsltCleanupStylesheetTree(style->doc,
xmlDocGetRootElement(style->doc));
-#endif
+#endif /* XSLT_REFACTORED */
xsltFreeKeys(style);
xsltFreeExts(style);
* @template: the "extension-element-prefixes" prefix
*
* parse an XSLT stylesheet's "extension-element-prefix" attribute value
- * and register the namespaces of extension elements.
+ * and register the namespaces of extension instruction.
* SPEC "A namespace is designated as an extension namespace by using
* an extension-element-prefixes attribute on:
* 1) an xsl:stylesheet element
- * 2) TODO: an xsl:extension-element-prefixes attribute on a
+ * 2) an xsl:extension-element-prefixes attribute on a
* literal result element
- * 3) TODO: an extension element."
+ * 3) an extension instruction."
*/
static void
xsltParseStylesheetExtPrefix(xsltStylesheetPtr style, xmlNodePtr cur,
prefixes = xmlGetNsProp(cur,
(const xmlChar *)"extension-element-prefixes", NULL);
} else {
- /* For literal result elements and extension elements. */
+ /* For literal result elements and extension instructions. */
prefixes = xmlGetNsProp(cur,
(const xmlChar *)"extension-element-prefixes", XSLT_NAMESPACE);
}
#ifdef XSLT_REFACTORED
/*
+* xsltTreeEnsureXMLDecl:
+* @doc: the doc
+*
+* BIG NOTE:
+* This was copy&pasted from Libxml2's xmlTreeEnsureXMLDecl() in "tree.c".
+* Ensures that there is an XML namespace declaration on the doc.
+*
+* Returns the XML ns-struct or NULL on API and internal errors.
+*/
+static xmlNsPtr
+xsltTreeEnsureXMLDecl(xmlDocPtr doc)
+{
+ if (doc == NULL)
+ return (NULL);
+ if (doc->oldNs != NULL)
+ return (doc->oldNs);
+ {
+ xmlNsPtr ns;
+ ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
+ if (ns == NULL) {
+ xmlGenericError(xmlGenericErrorContext,
+ "xsltTreeEnsureXMLDecl: Failed to allocate "
+ "the XML namespace.\n");
+ return (NULL);
+ }
+ memset(ns, 0, sizeof(xmlNs));
+ ns->type = XML_LOCAL_NAMESPACE;
+ ns->href = xmlStrdup(XML_XML_NAMESPACE);
+ ns->prefix = xmlStrdup((const xmlChar *)"xml");
+ doc->oldNs = ns;
+ return (ns);
+ }
+}
+
+/*
+* xsltTreeAcquireStoredNs:
+* @doc: the doc
+* @nsName: the namespace name
+* @prefix: the prefix
+*
+* BIG NOTE:
+* This was copy&pasted from Libxml2's xmlDOMWrapStoreNs() in "tree.c".
+* Creates or reuses an xmlNs struct on doc->oldNs with
+* the given prefix and namespace name.
+*
+* Returns the aquired ns struct or NULL in case of an API
+* or internal error.
+*/
+static xmlNsPtr
+xsltTreeAcquireStoredNs(xmlDocPtr doc,
+ const xmlChar *nsName,
+ const xmlChar *prefix)
+{
+ xmlNsPtr ns;
+
+ if (doc == NULL)
+ return (NULL);
+ ns = xsltTreeEnsureXMLDecl(doc);
+ if (ns == NULL)
+ return (NULL);
+ if (ns->next != NULL) {
+ /* Reuse. */
+ ns = ns->next;
+ while (ns != NULL) {
+ if ((ns->prefix == NULL) != (prefix == NULL)) {
+ /* NOP */
+ } else if (prefix == NULL) {
+ if (xmlStrEqual(ns->href, nsName))
+ return (ns);
+ } else {
+ if ((ns->prefix[0] == prefix[0]) &&
+ xmlStrEqual(ns->prefix, prefix) &&
+ xmlStrEqual(ns->href, nsName))
+ return (ns);
+
+ }
+ if (ns->next == NULL)
+ break;
+ ns = ns->next;
+ }
+ }
+ /* Create. */
+ ns->next = xmlNewNs(NULL, nsName, prefix);
+ return (ns->next);
+}
+
+/**
+ * xsltLREBuildEffectiveNs:
+ *
+ * Apply ns-aliasing on the namespace of the given @elem and
+ * its attributes.
+ */
+static int
+xsltLREBuildEffectiveNs(xsltCompilerCtxtPtr cctxt,
+ xmlNodePtr elem)
+{
+ xmlNsPtr ns;
+ xsltNsAliasPtr alias;
+
+ if ((cctxt == NULL) || (elem == NULL))
+ return(-1);
+ if ((cctxt->nsAliases == NULL) || (! cctxt->hasNsAliases))
+ return(0);
+
+ alias = cctxt->nsAliases;
+ while (alias != NULL) {
+ if ( /* If both namespaces are NULL... */
+ ( (elem->ns == NULL) &&
+ ((alias->literalNs == NULL) ||
+ (alias->literalNs->href == NULL)) ) ||
+ /* ... or both namespace are equal */
+ ( (elem->ns != NULL) &&
+ (alias->literalNs != NULL) &&
+ xmlStrEqual(elem->ns->href, alias->literalNs->href) ) )
+ {
+ if ((alias->targetNs != NULL) &&
+ (alias->targetNs->href != NULL))
+ {
+ /*
+ * Convert namespace.
+ */
+ if (elem->doc == alias->docOfTargetNs) {
+ /*
+ * This is the nice case: same docs.
+ * This will eventually assign a ns-decl which
+ * is shadowed, but this has no negative effect on
+ * the generation of the result tree.
+ */
+ elem->ns = alias->targetNs;
+ } else {
+ /*
+ * This target xmlNs originates from a different
+ * stylesheet tree. Try to locate it in the
+ * in-scope namespaces.
+ * OPTIMIZE TODO: Use the compiler-node-info inScopeNs.
+ */
+ ns = xmlSearchNs(elem->doc, elem,
+ alias->targetNs->prefix);
+ /*
+ * If no matching ns-decl found, then assign a
+ * ns-decl stored in xmlDoc.
+ */
+ if ((ns == NULL) ||
+ (! xmlStrEqual(ns->href, alias->targetNs->href)))
+ {
+ /*
+ * BIG NOTE: The use of xsltTreeAcquireStoredNs()
+ * is not very efficient, but currently I don't
+ * see an other way of *safely* changing a node's
+ * namespace, since the xmlNs struct in
+ * alias->targetNs might come from an other
+ * stylesheet tree. So we need to anchor it in the
+ * current document, without adding it to the tree,
+ * which would otherwise change the in-scope-ns
+ * semantic of the tree.
+ */
+ ns = xsltTreeAcquireStoredNs(elem->doc,
+ alias->targetNs->href,
+ alias->targetNs->prefix);
+
+ if (ns == NULL) {
+ xsltTransformError(NULL, cctxt->style, elem,
+ "Internal error in "
+ "xsltLREBuildEffectiveNs(): "
+ "failed to acquire a stored "
+ "ns-declaration.\n");
+ cctxt->style->errors++;
+ return(-1);
+
+ }
+ }
+ elem->ns = ns;
+ }
+ } else {
+ /*
+ * Move into or leave in the NULL namespace.
+ */
+ elem->ns = NULL;
+ }
+ break;
+ }
+ alias = alias->next;
+ }
+ /*
+ * Same with attributes of literal result elements.
+ */
+ if (elem->properties != NULL) {
+ xmlAttrPtr attr = elem->properties;
+
+ while (attr != NULL) {
+ if (attr->ns == NULL) {
+ attr = attr->next;
+ continue;
+ }
+ alias = cctxt->nsAliases;
+ while (alias != NULL) {
+ if ( /* If both namespaces are NULL... */
+ ( (elem->ns == NULL) &&
+ ((alias->literalNs == NULL) ||
+ (alias->literalNs->href == NULL)) ) ||
+ /* ... or both namespace are equal */
+ ( (elem->ns != NULL) &&
+ (alias->literalNs != NULL) &&
+ xmlStrEqual(elem->ns->href, alias->literalNs->href) ) )
+ {
+ if ((alias->targetNs != NULL) &&
+ (alias->targetNs->href != NULL))
+ {
+ if (elem->doc == alias->docOfTargetNs) {
+ elem->ns = alias->targetNs;
+ } else {
+ ns = xmlSearchNs(elem->doc, elem,
+ alias->targetNs->prefix);
+ if ((ns == NULL) ||
+ (! xmlStrEqual(ns->href, alias->targetNs->href)))
+ {
+ ns = xsltTreeAcquireStoredNs(elem->doc,
+ alias->targetNs->href,
+ alias->targetNs->prefix);
+
+ if (ns == NULL) {
+ xsltTransformError(NULL, cctxt->style, elem,
+ "Internal error in "
+ "xsltLREBuildEffectiveNs(): "
+ "failed to acquire a stored "
+ "ns-declaration.\n");
+ cctxt->style->errors++;
+ return(-1);
+
+ }
+ }
+ elem->ns = ns;
+ }
+ } else {
+ /*
+ * Move into or leave in the NULL namespace.
+ */
+ elem->ns = NULL;
+ }
+ break;
+ }
+ alias = alias->next;
+ }
+
+ attr = attr->next;
+ }
+ }
+ return(0);
+}
+
+/**
+ * xsltLREBuildEffectiveNsNodes:
+ *
+ * Computes the effective namespaces nodes for a literal result
+ * element.
+ * @effectiveNs is the set of effective ns-nodes
+ * on the literal result element, which will be added to the result
+ * element if not already existing in the result tree.
+ * This means that excluded namespaces (via exclude-result-prefixes,
+ * extension-element-prefixes and the XSLT namespace) not added
+ * to the set.
+ * Namespace-aliasing was applied on the @effectiveNs.
+ */
+static int
+xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt,
+ xsltStyleItemLRElementInfoPtr item,
+ xmlNodePtr elem)
+{
+ xmlNsPtr ns;
+ xsltEffectiveNsPtr effNs, lastEffNs = NULL;
+ int i;
+ xsltPointerListPtr extElemNs = cctxt->inode->extElemNs;
+ xsltPointerListPtr exclResultNs = cctxt->inode->exclResultNs;
+
+ if ((cctxt == NULL) || (cctxt->inode == NULL) || (elem == NULL) ||
+ (item == NULL) || (item->effectiveNs != NULL))
+ return(-1);
+
+ if (elem->nsDef == NULL)
+ return(0);
+
+ extElemNs = cctxt->inode->extElemNs;
+ exclResultNs = cctxt->inode->exclResultNs;
+
+ for (ns = elem->nsDef; ns != NULL; ns = ns->next) {
+ /*
+ * Skip namespaces designated as excluded namespaces
+ * -------------------------------------------------
+ *
+ * XSLT-20 TODO: In XSLT 2.0 we need to keep namespaces
+ * which are target namespaces of namespace-aliases
+ * regardless if designated as excluded.
+ *
+ * Exclude the XSLT namespace.
+ */
+ if (xmlStrEqual(ns->href, XSLT_NAMESPACE))
+ goto skip_ns;
+
+ /*
+ * Exclude excluded result namespaces.
+ */
+ if (exclResultNs) {
+ for (i = 0; i < exclResultNs->number; i++)
+ if (xmlStrEqual(ns->href, BAD_CAST exclResultNs->items[i]))
+ goto skip_ns;
+ }
+ /*
+ * Exclude extension-element namespaces.
+ */
+ if (extElemNs) {
+ for (i = 0; i < extElemNs->number; i++)
+ if (xmlStrEqual(ns->href, BAD_CAST extElemNs->items[i]))
+ goto skip_ns;
+ }
+ /*
+ * Apply namespace aliasing
+ * ------------------------
+ *
+ * NOTE: The ns-aliasing machanism is non-cascading.
+ * (checked with Saxon, Xalan and MSXML .NET).
+ * URGENT TODO: is style->nsAliases the effective list of
+ * ns-aliases, or do we need to lookup the whole
+ * import-tree?
+ * TODO: Get rid of import-tree lookup.
+ */
+ if (cctxt->hasNsAliases) {
+ xsltNsAliasPtr alias = cctxt->nsAliases;
+ do {
+ /*
+ * TODO: What to do with xmlns="" ?
+ */
+ if ((alias->literalNs != NULL) &&
+ (alias->literalNs->href == ns->href))
+ {
+ /*
+ * Recognized as an namespace alias; convert it to
+ * the target namespace.
+ */
+ ns = alias->literalNs;
+ break;
+ }
+ alias = alias->next;
+ } while (alias != NULL);
+ }
+ /*
+ * Add the effective namespace declaration.
+ */
+ effNs = (xsltEffectiveNsPtr) xmlMalloc(sizeof(xsltEffectiveNs));
+ if (effNs == NULL) {
+ xsltTransformError(NULL, cctxt->style, elem,
+ "Internal error in xsltLREBuildEffectiveNs(): "
+ "failed to allocate memory.\n");
+ cctxt->style->errors++;
+ return(-1);
+ }
+ effNs->next = NULL;
+ effNs->prefix = ns->prefix;
+ effNs->nsName = ns->href;
+
+ if (lastEffNs == NULL)
+ item->effectiveNs = effNs;
+ else
+ lastEffNs->next = effNs;
+ lastEffNs = effNs;
+
+skip_ns:
+ {}
+ }
+ return(0);
+}
+
+
+/**
+ * xsltLREInfoCreate:
+ *
+ * Creates a new info for a literal result element.
+ */
+static int
+xsltLREInfoCreate(xsltCompilerCtxtPtr cctxt,
+ xmlNodePtr elem)
+{
+ xsltStyleItemLRElementInfoPtr item;
+
+ if ((cctxt == NULL) || (cctxt->inode == NULL))
+ return(-1);
+
+ item = (xsltStyleItemLRElementInfoPtr)
+ xmlMalloc(sizeof(xsltStyleItemLRElementInfo));
+ if (item == NULL) {
+ xsltTransformError(NULL, cctxt->style, NULL,
+ "Internal error in xsltLREInfoCreate(): "
+ "memory allocation failed.\n");
+ cctxt->style->errors++;
+ return(-1);
+ }
+ memset(item, 0, sizeof(xsltStyleItemLRElementInfo));
+ item->type = XSLT_FUNC_LITERAL_RESULT_ELEMENT;
+ /*
+ * Store it in the stylesheet.
+ */
+ item->next = cctxt->style->preComps;
+ cctxt->style->preComps = (xsltElemPreCompPtr) item;
+ /*
+ * @inScopeNs are used for execution of XPath expressions
+ * in AVTs.
+ */
+ item->inScopeNs = cctxt->inode->inScopeNs;
+
+ if (elem && (elem->nsDef != NULL))
+ xsltLREBuildEffectiveNsNodes(cctxt, item, elem);
+
+ cctxt->inode->litResElemInfo = item;
+ cctxt->inode->nsChanged = 0;
+ return(0);
+}
+
+/*
* xsltCompilerNodePush:
*
* @cctxt: the compilation context
inode->prev = cctxt->inodeLast;
}
cctxt->inodeLast = inode;
- cctxt->maxNodeInfos++;
- }
- /*
- * REVISIT TODO: Keep the reset always complete.
- */
+ cctxt->maxNodeInfos++;
+ if (cctxt->inode == NULL) {
+ cctxt->inode = inode;
+ /*
+ * Create an initial literal result element info for
+ * the root of the stylesheet.
+ */
+ xsltLREInfoCreate(cctxt, NULL);
+ }
+ }
cctxt->depth++;
-
+ cctxt->inode = inode;
/*
+ * REVISIT TODO: Keep the reset always complete.
* NOTE: Be carefull with the @node, since it might be
* a doc-node.
*/
inode->node = node;
-
inode->depth = cctxt->depth;
inode->templ = NULL;
inode->category = XSLT_ELEMENT_CATEGORY_XSLT;
inode->extContentHandled = 0;
inode->isRoot = 0;
- if (inode->prev != NULL) {
+ if (inode->prev != NULL) {
/*
* Inherit the following information:
+ * ---------------------------------
+ *
+ * In-scope namespaces
*/
inode->inScopeNs = inode->prev->inScopeNs;
/*
- * in-scope namespaces
+ * Info for literal result elements
+ */
+ inode->litResElemInfo = inode->prev->litResElemInfo;
+ inode->nsChanged = inode->prev->nsChanged;
+ /*
+ * Excluded result namespaces
*/
inode->exclResultNs = inode->prev->exclResultNs;
/*
- * extension-element namespaces
+ * Extension instruction namespaces
*/
inode->extElemNs = inode->prev->extElemNs;
/*
- * whitespace perservation
+ * Whitespace preservation
*/
inode->preserveWhitespace = inode->prev->preserveWhitespace;
/*
- * forwards-compatible mode
+ * Forwards-compatible mode
*/
inode->forwardsCompat = inode->prev->forwardsCompat;
} else {
inode->preserveWhitespace = 0;
inode->forwardsCompat = 0;
}
- cctxt->inode = inode;
+
return(inode);
}
*
* Returns the ns-info or NULL if there are no namespaces in scope.
*/
-static xsltNsListPtr
+static xsltNsListContainerPtr
xsltCompilerBuildInScopeNsList(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
{
- xsltNsListPtr nsi = NULL;
+ xsltNsListContainerPtr nsi = NULL;
xmlNsPtr *list = NULL;
/*
* Create a new ns-list for this position in the node-tree.
/*
* Create the info-structure.
*/
- nsi = (xsltNsListPtr) xmlMalloc(sizeof(xsltNsList));
+ nsi = (xsltNsListContainerPtr) xmlMalloc(sizeof(xsltNsListContainer));
if (nsi == NULL) {
xsltTransformError(NULL, cctxt->style, NULL,
"xsltCompilerBuildInScopeNsList: malloc failed.\n");
goto internal_err;
}
- memset(nsi, 0, sizeof(xsltNsList));
+ memset(nsi, 0, sizeof(xsltNsListContainer));
nsi->list = list;
/*
* Eval the number of ns-decls; this is used to speed up
xsltTransformError(NULL, cctxt->style, NULL,
"xsltCompilerBuildInScopeNsList: failed to add ns-info.\n");
goto internal_err;
- }
+ }
+ /*
+ * Notify of change in status wrt namespaces.
+ */
+ if (cctxt->inode != NULL)
+ cctxt->inode->nsChanged = 1;
return(nsi);
if (list == NULL)
goto exit;
/*
- * Store the list in the stylesheet.
+ * Store the list in the stylesheet/compiler context.
*/
if (xsltPointerListAddSize(
cctxt->psData->exclResultNamespaces, list, 5) == -1)
list = NULL;
goto exit;
}
+ /*
+ * Notify of change in status wrt namespaces.
+ */
+ if (cctxt->inode != NULL)
+ cctxt->inode->nsChanged = 1;
exit:
if (value != NULL)
list = NULL;
goto exit;
}
+ /*
+ * Notify of change in status wrt namespaces.
+ */
+ if (cctxt->inode != NULL)
+ cctxt->inode->nsChanged = 1;
exit:
if (value != NULL)
xmlChar *value;
const xmlChar *name, *nsNameXSLT = NULL;
int strictWhitespace, inXSLText = 0;
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP
xsltNsMapPtr nsMapItem;
+#endif
if ((cctxt == NULL) || (cctxt->style == NULL) ||
(node == NULL) || (node->type != XML_ELEMENT_NODE))
doc = node->doc;
if (doc == NULL)
- return(-1);
+ goto internal_err;
style = cctxt->style;
if ((style->dict != NULL) && (doc->dict == style->dict))
* TODO: I'd love to use a string pointer comparison here :-/
*/
if (IS_XSLT_ELEM(cur)) {
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP
if (cur->ns->href != nsNameXSLT) {
nsMapItem = xsltNewNamespaceMapItem(cctxt,
doc, cur, cur->ns);
goto internal_err;
cur->ns->href = nsNameXSLT;
}
+#endif
if (cur->name == NULL)
goto process_attributes;
elem->psvi = NULL;
- if (! (IS_IN_XSLT_NS(elem)))
+ if (! (IS_XSLT_ELEM_FAST(elem)))
return(-1);
/*
- * Detection of handled content of extension elements.
+ * Detection of handled content of extension instructions.
*/
if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
cctxt->inode->extContentHandled = 1;
xmlNodePtr child = elem->children;
do {
if (child->type == XML_ELEMENT_NODE) {
- if (IS_IN_XSLT_NS(child)) {
- xsltStyleType type;
-
- type = xsltGetXSLTElementTypeByNode(cctxt, child);
- if ((type == XSLT_FUNC_WITHPARAM) ||
- (type == XSLT_FUNC_SORT))
- {
- /* cctxt->inode->type = type; */
+ if (IS_XSLT_ELEM_FAST(child)) {
+ if (xmlStrEqual(child->name, BAD_CAST "with-param")) {
+ cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM;
xsltParseAnyXSLTElem(cctxt, child);
- } else {
+ } else if (xmlStrEqual(child->name, BAD_CAST "sort")) {
+ cctxt->inode->curChildType = XSLT_FUNC_SORT;
+ xsltParseAnyXSLTElem(cctxt, child);
+ } else
xsltParseContentError(cctxt->style, child);
- }
} else
xsltParseContentError(cctxt->style, child);
}
xmlNodePtr child = elem->children;
do {
if (child->type == XML_ELEMENT_NODE) {
- if (IS_IN_XSLT_NS(child)) {
+ if (IS_XSLT_ELEM_FAST(child)) {
xsltStyleType type;
type = xsltGetXSLTElementTypeByNode(cctxt, child);
empty_content:
if (elem->children != NULL) {
- xsltTransformError(NULL, cctxt->style, elem,
- "This XSLT element must have no content.\n");
- cctxt->style->errors++;
+ xmlNodePtr child = elem->children;
+ /*
+ * Relaxed behaviour: we will allow whitespace-only text-nodes.
+ */
+ do {
+ if (((child->type != XML_TEXT_NODE) &&
+ (child->type != XML_CDATA_SECTION_NODE)) ||
+ (! IS_BLANK_NODE(child)))
+ {
+ xsltTransformError(NULL, cctxt->style, elem,
+ "This XSLT element must have no content.\n");
+ cctxt->style->errors++;
+ break;
+ }
+ child = child->next;
+ } while (child != NULL);
}
goto exit;
int nbWhen = 0, nbOtherwise = 0, err = 0;
do {
if (child->type == XML_ELEMENT_NODE) {
- if (IS_IN_XSLT_NS(child)) {
+ if (IS_XSLT_ELEM_FAST(child)) {
xsltStyleType type;
type = xsltGetXSLTElementTypeByNode(cctxt, child);
*/
do {
if ((child->type == XML_ELEMENT_NODE) &&
- IS_IN_XSLT_NS(child))
+ IS_XSLT_ELEM_FAST(child))
{
if (xsltGetXSLTElementTypeByNode(cctxt, child) ==
XSLT_FUNC_SORT)
return(-1);
}
+static xsltStyleItemUknownPtr
+xsltForwardsCompatUnkownItemCreate(xsltCompilerCtxtPtr cctxt)
+{
+ xsltStyleItemUknownPtr item;
+
+ item = (xsltStyleItemUknownPtr) xmlMalloc(sizeof(xsltStyleItemUknown));
+ if (item == NULL) {
+ xsltTransformError(NULL, cctxt->style, NULL,
+ "Internal error in xsltForwardsCompatUnkownItemCreate(): "
+ "Failed to allocate memory.\n");
+ cctxt->style->errors++;
+ return(NULL);
+ }
+ memset(item, 0, sizeof(xsltStyleItemUknown));
+ item->type = XSLT_FUNC_UNKOWN_FORWARDS_COMPAT;
+ /*
+ * Store it in the stylesheet.
+ */
+ item->next = cctxt->style->preComps;
+ cctxt->style->preComps = (xsltElemPreCompPtr) item;
+ return(item);
+}
+
static int
-xsltParseForwardsCompatUnexpectedXSLTElem(xsltCompilerCtxtPtr cctxt,
- xmlNodePtr node)
+xsltParseUnknownXSLTElem(xsltCompilerCtxtPtr cctxt,
+ xmlNodePtr node)
{
if ((cctxt == NULL) || (node == NULL))
return(-1);
/*
- * Detection of handled content of extension elements.
+ * Detection of handled content of extension instructions.
*/
if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
cctxt->inode->extContentHandled = 1;
+ }
+ if (cctxt->inode->forwardsCompat == 0) {
+ /*
+ * We are not in forwards-compatible mode, so raise an error.
+ */
+ xsltTransformError(NULL, cctxt->style, node,
+ "Unknown XSLT element '%s'.\n", node->name);
+ cctxt->style->errors++;
+ return(0);
}
-
- node->psvi = NULL;
+ /*
+ * Forwards-compatible mode.
+ * ------------------------
+ *
+ * Parse/compile xsl:fallback elements.
+ *
+ * QUESTION: Do we have to raise an error if there's no xsl:fallback?
+ * ANSWER: No, since in the stylesheet the fallback behaviour might
+ * also be provided by using the XSLT function "element-available".
+ */
+ if (cctxt->unknownItem == NULL) {
+ /*
+ * Create a singleton for all unknown XSLT instructions.
+ */
+ cctxt->unknownItem = xsltForwardsCompatUnkownItemCreate(cctxt);
+ if (cctxt->unknownItem == NULL) {
+ node->psvi = NULL;
+ return(-1);
+ }
+ }
+ node->psvi = cctxt->unknownItem;
if (node->children == NULL)
return(0);
else {
*/
if (node->nsDef != NULL)
cctxt->inode->inScopeNs =
- xsltCompilerBuildInScopeNsList(cctxt, node);
+ xsltCompilerBuildInScopeNsList(cctxt, node);
/*
* Parse all xsl:fallback children.
*/
do {
if ((child->type == XML_ELEMENT_NODE) &&
- IS_IN_XSLT_NS(child) &&
+ IS_XSLT_ELEM_FAST(child) &&
IS_XSLT_NAME(child, "fallback"))
{
cctxt->inode->curChildType = XSLT_FUNC_FALLBACK;
}
child = child->next;
} while (child != NULL);
+
xsltCompilerNodePop(cctxt, node);
}
return(0);
return;
}
/*
- * Detection of handled content of extension elements.
+ * Detection of handled content of extension instructions.
*/
if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
cctxt->inode->extContentHandled = 1;
* xsl:processing-instruction, xsl:comment, xsl:element
* xsl:attribute.
* Additional allowed content:
- * 1) extension elements
+ * 1) extension instructions
* 2) literal result elements
* 3) PCDATA
*
if (cur->psvi == xsltXSLTTextMarker) {
/*
- * Process xsl:text elements.
- * ==========================
+ * xsl:text elements
+ * --------------------------------------------------------
*/
xmlNodePtr tmp;
attr = attr->next;
} while (attr != NULL);
}
- } else if (IS_IN_XSLT_NS(cur)) {
+ } else if (IS_XSLT_ELEM_FAST(cur)) {
/*
* TODO: Using the XSLT-marker is still not stable yet.
*/
/* if (cur->psvi == xsltXSLTElemMarker) { */
/*
- * This is element in the XSLT namespace.
- * =====================================
+ * XSLT instructions
+ * --------------------------------------------------------
*/
+ cur->psvi = NULL;
type = xsltGetXSLTElementTypeByNode(cctxt, cur);
switch (type) {
case XSLT_FUNC_APPLYIMPORTS:
case XSLT_FUNC_PI:
case XSLT_FUNC_TEXT:
case XSLT_FUNC_VALUEOF:
- case XSLT_FUNC_VARIABLE:
- /* cctxt->inode->type = type; */
+ case XSLT_FUNC_VARIABLE:
/*
* Parse the XSLT element.
*/
xsltParseAnyXSLTElem(cctxt, cur);
break;
default:
- cur->psvi = NULL;
- /*
- * Ignore unknown elements in the
- * XSLT namespace if in forwards-compatible
- * mode.
- */
- if (cctxt->inode->forwardsCompat) {
- /*
- * This will parse xsl:fallback elements.
- */
- xsltParseForwardsCompatUnexpectedXSLTElem(
- cctxt, cur);
- } else {
- xsltParseContentError(cctxt->style, cur);
- }
+ xsltParseUnknownXSLTElem(cctxt, cur);
cur = cur->next;
continue;
}
} else {
/*
- * This is a non-XSLT element.
- * ==========================
+ * Non-XSLT elements
+ * -----------------
+ */
+ xsltCompilerNodePush(cctxt, cur);
+ /*
+ * Update the in-scope namespaces if needed.
*/
- xsltCompilerNodePush(cctxt, cur);
+ if (cur->nsDef != NULL)
+ cctxt->inode->inScopeNs =
+ xsltCompilerBuildInScopeNsList(cctxt, cur);
/*
* The current element is either a literal result element
- * or an extension element.
+ * or an extension instruction.
*
* Process attr "xsl:extension-element-prefixes".
* FUTURE TODO: IIRC in XSLT 2.0 this attribute must be
xsltParseExtElemPrefixes(cctxt,
cur, cctxt->inode->extElemNs, 0);
/*
- * Eval if we have an extension element here.
+ * Eval if we have an extension instruction here.
*/
if ((cur->ns != NULL) &&
(cctxt->inode->extElemNs != NULL) &&
(xsltCheckExtPrefix(cctxt->style, cur->ns->href) == 1))
{
/*
- * This is an extension element.
- * ============================
+ * Extension instructions
+ * ----------------------------------------------------
* Mark the node information.
*/
cctxt->inode->category = XSLT_ELEMENT_CATEGORY_EXTENSION;
* TODO: Temporary sanity check.
*/
xsltTransformError(NULL, cctxt->style, cur,
- "Internal error: (xsltParseNonXSLTElement) "
- " Occupied psvi field.\n");
+ "Internal error in xsltParseSequenceConstructor(): "
+ "Occupied PSVI field.\n");
cctxt->style->errors++;
cur = cur->next;
continue;
/*
* BIG NOTE: Now the ugly part. In previous versions
* of Libxslt (until 1.1.16), all the content of an
- * extension element was processed and compiled without
+ * extension instruction was processed and compiled without
* the need of the extension-author to explicitely call
* such a processing;.We now need to mimic this old
* behaviour in order to avoid breaking old code
}
} else {
/*
- * This is a literal result element.
- * ================================
+ * Literal result element
+ * ----------------------------------------------------
* Allowed XSLT attributes:
* xsl:extension-element-prefixes CDATA #IMPLIED
* xsl:exclude-result-prefixes CDATA #IMPLIED
* TODO: xsl:use-attribute-sets %qnames; #IMPLIED
* xsl:version NMTOKEN #IMPLIED
*/
- cctxt->inode->category = XSLT_ELEMENT_CATEGORY_LR;
+ cur->psvi = NULL;
+ cctxt->inode->category = XSLT_ELEMENT_CATEGORY_LR;
if (cur->properties != NULL) {
/*
* Attribute "xsl:exclude-result-prefixes".
xsltParseAttrXSLTVersion(cctxt, cur, 0);
}
/*
- * TODO: Create the literal result item.
- * TODO: Check what this *defaultAlias* mechanism does. Do we
- * need to create the compiled item after such namespace
- * conversion?
+ * Create/reuse info for the literal result element.
+ */
+ if (cctxt->inode->nsChanged)
+ xsltLREInfoCreate(cctxt, cur);
+ cur->psvi = cctxt->inode->litResElemInfo;
+ /*
+ * Apply ns-aliasing on the element and on its attributes.
+ */
+ if (cctxt->hasNsAliases)
+ xsltLREBuildEffectiveNs(cctxt, cur);
+ /*
+ * Compile attribute value templates (AVT).
*/
- if ((cur->ns == NULL) && (cctxt->style->defaultAlias != NULL) &&
- (cur->type == XML_ELEMENT_NODE))
- {
-
- cur->ns = xmlSearchNsByHref(cur->doc, cur,
- cctxt->style->defaultAlias);
- }
if (cur->properties) {
xmlAttrPtr attr = cur->properties;
return;
/*
- * Detection of handled content of extension elements.
+ * Detection of handled content of extension instructions.
*/
if (XSLT_CCTXT(style)->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
XSLT_CCTXT(style)->inode->extContentHandled = 1;
/*
* Process xsl:param elements, which can only occur as the
* immediate children of xsl:template (well, and of any
- * user-defined extension element if needed).
+ * user-defined extension instruction if needed).
*/
do {
if ((child->type == XML_ELEMENT_NODE) &&
- IS_IN_XSLT_NS(child) && IS_XSLT_NAME(child, "param"))
+ IS_XSLT_ELEM_FAST(child) &&
+ IS_XSLT_NAME(child, "param"))
{
XSLT_CCTXT(style)->inode->curChildType = XSLT_FUNC_PARAM;
xsltParseAnyXSLTElem(XSLT_CCTXT(style), child);
if (cctxt->inode->inScopeNs != NULL) {
int i, j;
xmlNsPtr ns;
- xsltPointerListPtr extElemList = cctxt->inode->extElemNs;
- xsltPointerListPtr exclResultList = cctxt->inode->exclResultNs;
- xsltNsListPtr inScopeNs = cctxt->inode->inScopeNs;
+ 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 excluded result namespaces.
*/
- if (exclResultList) {
- for (j = 0; j < exclResultList->number; j++)
- if (xmlStrEqual(ns->href,
- BAD_CAST exclResultList->items[j]))
- goto skip_ns;
+ 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 (extElemList) {
- for (j = 0; j < extElemList->number; j++)
- if (xmlStrEqual(ns->href, BAD_CAST extElemList->items[j]))
+ if (extElemNs) {
+ for (j = 0; j < extElemNs->number; j++)
+ if (xmlStrEqual(ns->href, BAD_CAST extElemNs->items[j]))
goto skip_ns;
}
/*
curTempl = curTempl->next;
}
}
- if (templNode->children != NULL)
- xsltParseTemplateContent(cctxt->style, templNode);
+ if (templNode->children != NULL) {
+ xsltParseTemplateContent(cctxt->style, templNode);
+ /*
+ * MAYBE TODO: Custom behaviour: In order to stay compatible with
+ * Xalan and MSXML(.NET), we could allow whitespace
+ * to appear before an xml:param element; this whitespace
+ * will additionally become part of the "template".
+ * NOTE that this is totally deviates from the spec, but
+ * is the de facto behaviour of Xalan and MSXML(.NET).
+ * Personally I wouldn't allow this, since if we have:
+ * <xsl:template ...xml:space="preserve">
+ * <xsl:param name="foo"/>
+ * <xsl:param name="bar"/>
+ * <xsl:param name="zoo"/>
+ * ... the whitespace between every xsl:param would be
+ * added to the result tree.
+ */
+ }
templ->elem = templNode;
templ->content = templNode->children;
return(ret);
}
+#if 0
static int
xsltParseRemoveWhitespace(xmlNodePtr node)
{
}
return(0);
}
-
-static int
-xsltParseMetaInfo(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
-{
-#define XSLT_MODULE_SCOPE_GLOBAL 0
-#define XSLT_MODULE_SCOPE_SSLEVEL 1
- xmlNodePtr cur;
- xmlChar *value = NULL, *value2 = NULL;
- int moduleScope;
-
- if ((cctxt == NULL) || (node == NULL) || (node->children == NULL))
- return(-1);
-
- /*
- * Remove whitespace in case we had a xml:space.
- */
- xsltParseRemoveWhitespace(node);
-
- cur = node->children;
- while (cur != NULL) {
- if (value != NULL) {
- xmlFree(value);
- value = NULL;
- }
- if (value2 != NULL) {
- xmlFree(value2);
- value2 = NULL;
- }
- /*
- * Process the module-registration specific elements.
- */
- if ((cur->type == XML_ELEMENT_NODE) &&
- (cur->ns == NULL))
- {
- if (xmlStrEqual(cur->name, "initialize-module")) {
- /*
- * TODO: Validation of attributes.
- */
- value = xmlGetNsProp(cur, "namespace", NULL);
- if (value != NULL) {
- moduleScope = XSLT_MODULE_SCOPE_GLOBAL;
- value2 = xmlGetNsProp(cur, "scope", NULL);
- if (value != NULL) {
- if (xmlStrEqual(value2, "global"))
- moduleScope = XSLT_MODULE_SCOPE_GLOBAL;
- else if (xmlStrEqual(value2, "stylesheet-level"))
- moduleScope = XSLT_MODULE_SCOPE_SSLEVEL;
- else {
- xsltTransformError(NULL, cctxt->style, cur,
- "Attribute 'scope': Invalid value. "
- "Only the values 'global' and "
- "'stylesheet-level' are expected.\n");
- }
- }
- /*
- * Call the module initialization.
- */
- if (moduleScope == XSLT_MODULE_SCOPE_GLOBAL) {
- /*
- * Initialize the modle using global user-data
- * storage. This means that this module
- * will be initialized only *once* (regardless
- * of the number of stylesheet-modules) and the
- * user-data will be only stored in the main
- * stylesheet.
- */
- xsltStyleGetExtData(cctxt->style, BAD_CAST value);
- } else {
- /*
- * Initialize the modle using per-stylesheet
- * user-data storage. This means that this module
- * will be initialized (and user-data is stored)
- * in the stylesheet at the current stylesheet-level.
- */
- xsltStyleStylesheetLevelGetExtData(cctxt->style,
- BAD_CAST value);
- }
- goto next_item;
- }
- }
- }
- xsltParseContentError(cctxt->style, cur);
-
-next_item:
- cur = cur->next;
- }
- if (value != NULL) {
- xmlFree(value);
- value = NULL;
- }
- if (value2 != NULL) {
- xmlFree(value2);
- value2 = NULL;
- }
-
- return(0);
-}
+#endif
static int
xsltParseXSLTStylesheetElemCore(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
* with the same stylesheet level have been processed.
* Now we can safely parse the rest of the declarations.
*/
- if (IS_IN_XSLT_NS(node) && IS_XSLT_NAME(node, "include"))
+ if (IS_XSLT_ELEM_FAST(node) && IS_XSLT_NAME(node, "include"))
{
xsltDocumentPtr include;
/*
return(0);
/*
* Push the xsl:stylesheet/xsl:transform element.
- */
+ */
xsltCompilerNodePush(cctxt, node);
cctxt->inode->isRoot = 1;
+ cctxt->inode->nsChanged = 0;
+ /*
+ * Start with the dummy info for literal result elements.
+ */
+ cctxt->inode->litResElemInfo = cctxt->inodeList->litResElemInfo;
/*
* In every case, we need to have
#ifdef XSLT_REFACTORED_MANDATORY_VERSION
if (isXsltElem)
xsltTransformError(NULL, cctxt->style, node,
- "The attribute 'version' is missing.\n");
+ "The attribute 'version' is missing.\n");
cctxt->style->errors++;
#else
/* OLD behaviour. */
-xsltTransformError(NULL, cctxt->style, node,
+ xsltTransformError(NULL, cctxt->style, node,
"xsl:version is missing: document may not be a stylesheet\n");
cctxt->style->warnings++;
#endif
*/
cctxt->inode->exclResultNs =
xsltParseExclResultPrefixes(cctxt, node, NULL, 1);
-
+ /*
+ * Create/reuse info for the literal result element.
+ */
+ if (cctxt->inode->nsChanged)
+ xsltLREInfoCreate(cctxt, NULL);
/*
* Processed top-level elements:
* ----------------------------
{
xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_VARIABLE);
cur = cur->next;
- }
- /*
- * REVISIT TODO: Process Libxslt's module handling user-defined
- * data element.
- */
- cur = start;
- while ((cur != NULL) &&
- xsltParseFindTopLevelElem(cctxt, cur,
- xsltLibxsltDataElementNameMeta,
- xsltLibxsltDataElementNamespaceMeta, 0, &cur) == 1)
- {
- if (xsltParseMetaInfo(cctxt, cur) == -1)
- goto internal_err;
- cur->psvi = (void *) xsltUserDataElemMarker;
- cur = cur->next;
- }
+ }
/*
* Process all the rest of top-level elements.
*/
cur = cur->next;
continue;
}
- if (cur->psvi == xsltUserDataElemMarker) {
- cur->psvi = NULL;
- cur = cur->next;
- continue;
- }
/*
* Process all XSLT elements.
*/
- if (IS_IN_XSLT_NS(cur)) {
+ if (IS_XSLT_ELEM_FAST(cur)) {
/*
* xsl:import is only allowed at the beginning.
*/
xsltParseTopLevelXSLTElem(cctxt, cur,
XSLT_FUNC_ATTRSET);
} else if (IS_XSLT_NAME(cur, "namespace-alias")) {
- xsltNamespaceAlias(style, cur);
+ /* NOP; done already */
} else {
if (cctxt->inode->forwardsCompat) {
/*
"parsed %d templates\n", templates);
#endif
return(0);
-
-internal_err:
- xsltCompilerNodePop(cctxt, node);
- return(-1);
}
/**
static int
xsltParseXSLTStylesheetElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
{
- xmlNodePtr cur;
+ xmlNodePtr cur, start;
if ((cctxt == NULL) || (node == NULL))
return(-1);
}
if (cur == NULL)
goto exit;
+ start = cur;
/*
* Pre-process all xsl:include elements.
*/
+ cur = start;
while ((cur != NULL) &&
xsltParseFindTopLevelElem(cctxt, cur,
BAD_CAST "include", XSLT_NAMESPACE, 0, &cur) == 1)
xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_INCLUDE);
cur = cur->next;
}
+ /*
+ * Pre-process all xsl:namespace-alias elements.
+ */
+ cur = start;
+ while ((cur != NULL) &&
+ xsltParseFindTopLevelElem(cctxt, cur,
+ BAD_CAST "namespace-alias", XSLT_NAMESPACE, 0, &cur) == 1)
+ {
+ xsltNamespaceAlias(cctxt->style, cur);
+ cur = cur->next;
+ }
if (cctxt->isInclude) {
/*
return(0);
}
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP
int
xsltRestoreDocumentNamespaces(xsltNsMapPtr ns, xmlDocPtr doc)
{
}
return(0);
}
+#endif /* XSLT_REFACTORED_XSLT_NSCOMP */
/**
* xsltParseStylesheetProcess:
}
retStyle->principalData = principalData;
/*
- * Create the compilation context (only once; for the
- * principal stylesheet).
+ * Create the compilation context
+ * ------------------------------
+ * (only once; for the principal stylesheet).
* This is currently the only function where the
* compilation context is created.
- */
- if (xsltCompilerCreate(retStyle) == NULL) {
+ */
+ cctxt = xsltCompilationCtxtCreate(retStyle);
+ if (cctxt == NULL) {
xsltFreeStylesheet(retStyle);
return(NULL);
- }
- cctxt = XSLT_CCTXT(retStyle);
+ }
+ retStyle->compCtxt = (void *) cctxt;
+ cctxt->style = retStyle;
+ cctxt->dict = retStyle->dict;
cctxt->psData = principalData;
/*
* Push initial dummy node info.
*/
if (retStyle != NULL) {
if (retStyle->errors != 0) {
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP
/*
* Restore all changes made to namespace URIs of ns-decls.
*/
if (cctxt->psData->nsMap)
xsltRestoreDocumentNamespaces(cctxt->psData->nsMap, doc);
+#endif
/*
* Detach the doc from the stylesheet; otherwise the doc
* will be freed in xsltFreeStylesheet().
if (ret->compCtxt != NULL) {
/* TEST TODO: REMOVE test output*/
/* printf("MAX NODE INFO: %d\n", XSLT_CCTXT(ret)->maxNodeInfos); */
- xsltCompilerCtxtFree(XSLT_CCTXT(ret));
+ xsltCompilationCtxtFree(XSLT_CCTXT(ret));
ret->compCtxt = NULL;
}
#endif
extern "C" {
#endif
+#define XSLT_IS_TEXT_NODE(n) (((n) != NULL) && \
+ (((n)->type == XML_TEXT_NODE) || \
+ ((n)->type == XML_CDATA_SECTION_NODE)))
+
/**
* XSLT_REFACTORED:
*
- * Internal define to enable the refactored parts of Libxslt
- * mostly related to pre-computation.
+ * Internal define to enable the refactored parts of Libxslt.
*/
/* #define XSLT_REFACTORED */
#ifdef XSLT_REFACTORED
-extern const xmlChar *xsltConstNamespaceNameXSLT;
+/* TODO: REMOVE: #define XSLT_REFACTORED_EXCLRESNS */
+
+/* TODO: REMOVE: #define XSLT_REFACTORED_NSALIAS */
/**
- * IS_XSLT_ELEM_FAST:
+ * XSLT_REFACTORED_XSLT_NSCOMP
*
- * Checks that the element pertains to XSLT namespace.
+ * Internal define to enable the pointer-comparison of
+ * namespaces of XSLT elements.
*/
-#define IS_XSLT_ELEM_FAST(e) \
- (((e) != NULL) && ((e)->type == XML_ELEMENT_NODE) && \
- ((e)->ns != NULL) && ((e)->ns->href == xsltConstNamespaceNameXSLT))
+#define XSLT_REFACTORED_XSLT_NSCOMP
-#define IS_IN_XSLT_NS(e) \
- (((e)->ns != NULL) && ((e)->ns->href == xsltConstNamespaceNameXSLT))
+/**
+ * XSLT_REFACTORED_XPATHCOMP
+ *
+ * Internal define to enable the optimization of the
+ * compilation of XPath expressions.
+ */
+#define XSLT_REFACTORED_XPATHCOMP
+
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP
+
+extern const xmlChar *xsltConstNamespaceNameXSLT;
+
+#define IS_XSLT_ELEM_FAST(n) \
+ (((n) != NULL) && ((n)->ns != NULL) && \
+ ((n)->ns->href == xsltConstNamespaceNameXSLT))
#define XSLT_HAS_INTERNAL_NSMAP(s) \
(((s) != NULL) && ((s)->principal) && \
#define XSLT_GET_INTERNAL_NSMAP(s) ((s)->principal->principalData->nsMap)
+#else /* XSLT_REFACTORED_XSLT_NSCOMP */
+
+#define IS_XSLT_ELEM_FAST(n) \
+ (((n) != NULL) && ((n)->ns != NULL) && \
+ (xmlStrEqual((n)->ns->href, XSLT_NAMESPACE)))
+
+
+#endif /* XSLT_REFACTORED_XSLT_NSCOMP */
+
+
/**
* XSLT_REFACTORED_MANDATORY_VERSION:
*
XSLT_FUNC_FALLBACK,
XSLT_FUNC_MESSAGE,
XSLT_FUNC_INCLUDE,
- XSLT_FUNC_ATTRSET
+ XSLT_FUNC_ATTRSET,
+ XSLT_FUNC_LITERAL_RESULT_ELEMENT,
+ XSLT_FUNC_UNKOWN_FORWARDS_COMPAT,
#endif
} xsltStyleType;
* *
************************************************************************/
-typedef struct _xsltNsList xsltNsList;
-typedef xsltNsList *xsltNsListPtr;
-struct _xsltNsList {
+typedef struct _xsltNsListContainer xsltNsListContainer;
+typedef xsltNsListContainer *xsltNsListContainerPtr;
+struct _xsltNsListContainer {
xmlNsPtr *list;
int number;
};
*
* The in-scope namespaces.
*/
-#define XSLT_ITEM_NSINSCOPE_FIELDS xsltNsListPtr inScopeNs;
+#define XSLT_ITEM_NSINSCOPE_FIELDS xsltNsListContainerPtr inScopeNs;
/**
* XSLT_ITEM_COMMON_FIELDS:
xmlNodePtr inst; /* the node in the stylesheet's tree
corresponding to this item. */
/* Currently no navigational fields. */
- xsltNsListPtr inScopeNs;
+ xsltNsListContainerPtr inScopeNs;
};
/**
/************************************************************************
* *
+ * XSLT elements in forwards-compatible mode *
+ * *
+ ************************************************************************/
+
+typedef struct _xsltStyleItemUknown xsltStyleItemUknown;
+typedef xsltStyleItemUknown *xsltStyleItemUknownPtr;
+struct _xsltStyleItemUknown {
+ XSLT_ITEM_COMMON_FIELDS
+};
+
+
+/************************************************************************
+ * *
* Extension elements *
* *
************************************************************************/
* *
************************************************************************/
+typedef struct _xsltEffectiveNs xsltEffectiveNs;
+typedef xsltEffectiveNs *xsltEffectiveNsPtr;
+struct _xsltEffectiveNs {
+ xsltEffectiveNsPtr next; /* next item in the list */
+ const xmlChar *prefix;
+ const xmlChar *nsName;
+};
+
/*
- * Literal result elements.
- */
-typedef struct _xsltStyleItemLRElement xsltStyleItemLRElement;
-typedef xsltStyleItemLRElement *xsltStyleItemLRElementPtr;
-struct _xsltStyleItemLRElement {
+ * Info for literal result elements.
+ * This will be set on the elem->psvi field and will be
+ * shared by literal result elements, which have the same
+ * excluded result namespaces; i.e., this *won't* be created uniquely
+ * for every literal result element.
+ */
+typedef struct _xsltStyleItemLRElementInfo xsltStyleItemLRElementInfo;
+typedef xsltStyleItemLRElementInfo *xsltStyleItemLRElementInfoPtr;
+struct _xsltStyleItemLRElementInfo {
XSLT_ITEM_COMMON_FIELDS
- xsltPointerListPtr exclResultNs;
+ /*
+ * @effectiveNs is the set of effective ns-nodes
+ * on the literal result element, which will be added to the result
+ * element if not already existing in the result tree.
+ * This means that excluded namespaces (via exclude-result-prefixes,
+ * extension-element-prefixes and the XSLT namespace) not added
+ * to the set.
+ * Namespace-aliasing was applied on the @effectiveNs.
+ */
+ xsltEffectiveNsPtr effectiveNs;
+};
+
+#ifdef XSLT_REFACTORED
+
+typedef struct _xsltNsAlias xsltNsAlias;
+typedef xsltNsAlias *xsltNsAliasPtr;
+struct _xsltNsAlias {
+ xsltNsAliasPtr next; /* next in the list */
+ xmlNsPtr literalNs;
+ xmlNsPtr targetNs;
+ xmlDocPtr docOfTargetNs;
};
+#endif
+
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP
typedef struct _xsltNsMap xsltNsMap;
typedef xsltNsMap *xsltNsMapPtr;
const xmlChar *origNsName; /* the original XML namespace name */
const xmlChar *newNsName; /* the mapped XML namespace name */
};
+#endif
/************************************************************************
* *
typedef struct _xsltPrincipalStylesheetData xsltPrincipalStylesheetData;
typedef xsltPrincipalStylesheetData *xsltPrincipalStylesheetDataPtr;
+typedef struct _xsltNsList xsltNsList;
+typedef xsltNsList *xsltNsListPtr;
+struct _xsltNsList {
+ xsltNsListPtr next; /* next in the list */
+ xmlNsPtr ns;
+};
+
#define XSLT_ELEMENT_CATEGORY_XSLT 0
#define XSLT_ELEMENT_CATEGORY_EXTENSION 1
#define XSLT_ELEMENT_CATEGORY_LR 2
extension element */
xsltStyleType type;
xsltElemPreCompPtr item; /* The compiled information */
- xsltNsListPtr inScopeNs; /* The in-scope namespaces for the current
- position in the node-tree */
- xsltPointerListPtr exclResultNs; /* The current excluded
- result namespaces */
+ /* The current in-scope namespaces */
+ xsltNsListContainerPtr inScopeNs;
+ /* The current excluded result namespaces */
+ xsltPointerListPtr exclResultNs;
+ /* The current extension instruction namespaces */
xsltPointerListPtr extElemNs;
+ /* The current info for literal result elements. */
+ xsltStyleItemLRElementInfoPtr litResElemInfo;
+ /*
+ * Set to 1 if in-scope namespaces changed,
+ * or excluded result namespaces changed,
+ * or extension element namespaces changed.
+ * This will trigger creation of new infos
+ * for literal result elements.
+ */
+ int nsChanged;
int preserveWhitespace;
int stripWhitespace;
int isRoot; /* whether this is the stylesheet's root node */
/* whether the content of an extension element was processed */
int extContentHandled;
/* the type of the current child */
- xsltStyleType curChildType;
+ xsltStyleType curChildType;
};
#define XSLT_CCTXT(style) ((xsltCompilerCtxtPtr) style->compCtxt)
* mechanisms like whitespace-stripping in the stylesheet.
*/
int strict;
- xsltPrincipalStylesheetDataPtr psData;
+ xsltPrincipalStylesheetDataPtr psData;
+#ifdef XSLT_REFACTORED_XPATHCOMP
+ xmlXPathContextPtr xpathCtxt;
+#endif
+ xsltStyleItemUknownPtr unknownItem;
+ int hasNsAliases; /* Indicator if there was an xsl:namespace-alias. */
+ xsltNsAliasPtr nsAliases;
};
#else /* XSLT_REFACTORED */
/*
* Global list of in-scope namespaces.
*/
- void *inScopeNamespaces;
+ xsltPointerListPtr inScopeNamespaces;
/*
* Global list of information for [xsl:]excluded-result-prefixes.
*/
- void *exclResultNamespaces;
+ xsltPointerListPtr exclResultNamespaces;
/*
* Global list of information for [xsl:]extension-element-prefixes.
*/
- void *extElemNamespaces;
+ xsltPointerListPtr extElemNamespaces;
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP
/*
* Namespace name map to get rid of string comparison of namespace names.
*/
xsltNsMapPtr nsMap;
+#endif
};
/*
* Namespace aliases.
+ * NOTE: Not used in the refactored code.
*/
xmlHashTablePtr nsAliases; /* the namespace alias hash tables */
/*
* Namespaces.
+ * TODO: Eliminate this.
*/
xmlHashTablePtr nsHash; /* the set of namespaces in use:
ATTENTION: This is used for
void *attVTs;
/*
* if namespace-alias has an alias for the default stylesheet prefix
+ * NOTE: Not used in the refactored code.
*/
const xmlChar *defaultAlias;
/*
XSLTPUBFUN int XSLTCALL
xsltParseAnyXSLTElem (xsltCompilerCtxtPtr cctxt,
xmlNodePtr elem);
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP
XSLTPUBFUN int XSLTCALL
xsltRestoreDocumentNamespaces(
xsltNsMapPtr ns,
xmlDocPtr doc);
+#endif
#endif /* XSLT_REFACTORED */
#ifdef __cplusplus
*/
xmlXPathCompExprPtr
xsltXPathCompile(xsltStylesheetPtr style, const xmlChar *str) {
- xmlXPathContextPtr xctxt;
+ xmlXPathContextPtr xpathCtxt;
xmlXPathCompExprPtr ret;
- if (style != NULL)
- xctxt = xmlXPathNewContext(style->doc);
- else
- xctxt = xmlXPathNewContext(NULL);
- if (style != NULL)
- xctxt->dict = style->dict;
- ret = xmlXPathCtxtCompile(xctxt, str);
- xmlXPathFreeContext(xctxt);
+ if (style != NULL) {
+#ifdef XSLT_REFACTORED_XPATHCOMP
+ if (XSLT_CCTXT(style)) {
+ /*
+ * Proposed by Jerome Pesenti
+ * --------------------------
+ * For better efficiency we'll reuse the compilation
+ * context's XPath context. For the common stylesheet using
+ * XPath expressions this will reduce compilation time to
+ * about 50%.
+ *
+ * See http://mail.gnome.org/archives/xslt/2006-April/msg00037.html
+ */
+ xpathCtxt = XSLT_CCTXT(style)->xpathCtxt;
+ xpathCtxt->doc = style->doc;
+ } else
+ xpathCtxt = xmlXPathNewContext(style->doc);
+#else
+ xpathCtxt = xmlXPathNewContext(style->doc);
+#endif
+ xpathCtxt->dict = style->dict;
+ } else {
+ xpathCtxt = xmlXPathNewContext(NULL);
+ }
+ /*
+ * Compile the expression.
+ */
+ ret = xmlXPathCtxtCompile(xpathCtxt, str);
+
+#ifdef XSLT_REFACTORED_XPATHCOMP
+ if ((style == NULL) || (! XSLT_CCTXT(style))) {
+ xmlXPathFreeContext(xpathCtxt);
+ }
+#else
+ xmlXPathFreeContext(xpathCtxt);
+#endif
/*
* TODO: there is a lot of optimizations which should be possible
* like variable slot precomputations, function precomputations, etc.
*/
-
+
return(ret);
}