+Mon May 22 10:32:57 CEST 2006 Kasimier Buchcik <libxml2-cvs@cazic.net>
+
+ * libxslt/attributes.c libxslt/documents.c
+ libxslt/extensions.c libxslt/keys.c libxslt/pattern.c
+ libxslt/preproc.c libxslt/templates.c
+ libxslt/transform.c libxslt/variables.c
+ libxslt/xslt.c libxslt/xsltInternals.h:
+ Next tiny step of refactoring - mostly bug fixes and
+ cosmetic changes.
+ Changes outside of the refactored code:
+ 1) Optimized xsl:attribute if the content consists of
+ just 1 text node.
+ 2) Optimized computation of xsl:key. The keys will now be
+ computed for a specific document not until the first call
+ of a key() function; here only the keys with the specific
+ name used by key() are computed. This means that this
+ now avoids computation of all keys for all loaded
+ input documents (even if no key() was called on them).
+ One exception is the scenario where a key() is used in
+ a template's match pattern; in this case all keys are
+ computed for a document if there's a chance that
+ a "keyed" template could match a node (this could still
+ be optimized a bit).
+
Mon May 15 22:32:13 CEST 2006 Kasimier Buchcik <libxml2-cvs@cazic.net>
* libxslt/namespaces.c libxslt/attributes.c:
#include <libxml/hash.h>
#include <libxml/xmlerror.h>
#include <libxml/uri.h>
+#include <libxml/parserInternals.h>
#include "xslt.h"
#include "xsltInternals.h"
#include "xsltutils.h"
/*
* Useful macros
*/
+#ifdef IS_BLANK
+#undef IS_BLANK
+#endif
#define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \
((c) == 0x0D))
* xsltAttributeInternal:
* @ctxt: a XSLT process context
* @node: the node in the source tree.
- * @inst: the xslt attribute node
+ * @inst: the xsl:attribute element
* @comp: precomputed information
* @fromset: the attribute comes from an attribute-set
*
if (attr != NULL)
return;
}
- value = xsltEvalTemplateString(ctxt, node, inst); /* OPTIMIZE TODO: expensive! */
- if (value == NULL) {
- if (ns) {
- attr = xmlSetNsProp(ctxt->insert, ns, name,
- (const xmlChar *) "");
- } else {
- attr =
- xmlSetProp(ctxt->insert, name, (const xmlChar *) "");
- }
+
+ if (inst->children == NULL) {
+ /*
+ * No content.
+ */
+ attr = xmlSetNsProp(ctxt->insert, ns, name, (const xmlChar *) "");
+ } else if ((inst->children->next == NULL) &&
+ ((inst->children->type == XML_TEXT_NODE) ||
+ (inst->children->type == XML_CDATA_SECTION_NODE)))
+ {
+ xmlNodePtr origTxt = inst->children, copyTxt;
+ /*
+ * Optimization: if the content is just 1 text node, then
+ * just need to copy it over, or just assign it to the result
+ * if the string is shared.
+ * NOTE that xmlSetNsProp() will query if this is an ID attribute :-/
+ */
+ attr = xmlSetNsProp(ctxt->insert, ns, name, NULL);
+ if (attr == NULL) /* TODO: report error */
+ goto internal_err;
+ /*
+ * This was taken over from xsltCopyText() (transform.c).
+ */
+ if (ctxt->internalized &&
+ (ctxt->insert->doc != NULL) &&
+ (ctxt->insert->doc->dict == ctxt->dict))
+ {
+ copyTxt = xmlNewText(NULL);
+ if (copyTxt == NULL) /* TODO: report error */
+ goto internal_err;
+ /*
+ * This is a safe scenario where we don't need to lookup
+ * the dict.
+ */
+ copyTxt->content = origTxt->content;
+ /*
+ * Copy "disable-output-escaping" information.
+ */
+ if (origTxt->name == xmlStringTextNoenc)
+ copyTxt->name = xmlStringTextNoenc;
+ } else {
+ /*
+ * Copy the value.
+ */
+ copyTxt = xmlNewText(origTxt->content);
+ if (copyTxt == NULL) /* TODO: report error */
+ goto internal_err;
+ if (origTxt->name == xmlStringTextNoenc)
+ copyTxt->name = xmlStringTextNoenc;
+ }
+ if (copyTxt != NULL) {
+ copyTxt->doc = attr->doc;
+ xmlAddChild((xmlNodePtr) attr, copyTxt);
+ }
} else {
- if (ns) {
- attr = xmlSetNsProp(ctxt->insert, ns, name, value);
- } else {
- attr = xmlSetProp(ctxt->insert, name, value);
- }
+ /*
+ * The sequence constructor might be complex, so instantiate it.
+ */
+ value = xsltEvalTemplateString(ctxt, node, inst);
+ if (value != NULL) {
+ attr = xmlSetNsProp(ctxt->insert, ns, name, value);
+ xmlFree(value);
+ } else {
+ /*
+ * TODO: Do we have to add the empty string to the attr?
+ */
+ attr = xmlSetNsProp(ctxt->insert, ns, name,
+ (const xmlChar *) "");
+
+ }
}
error:
- if (value != NULL)
- xmlFree(value);
+internal_err:
+ return;
}
/**
memset(cur, 0, sizeof(xsltDocument));
cur->doc = doc;
if (ctxt != NULL) {
- if (!xmlStrEqual((xmlChar *)doc->name, BAD_CAST " fake node libxslt")) {
+ if (! XSLT_IS_RES_TREE_FRAG(doc)) {
cur->next = ctxt->docList;
ctxt->docList = cur;
}
+#ifdef XSLT_REFACTORED_KEYCOMP
+ /*
+ * A key with a specific name for a specific document
+ * will only be computed if there's a call to the key()
+ * function using that specific name for that specific
+ * document. I.e. computation of keys will be done in
+ * xsltGetKey() (keys.c) on an on-demand basis.
+ */
+#else
+ /*
+ * Old behaviour.
+ */
xsltInitCtxtKeys(ctxt, cur);
+#endif
}
return(cur);
}
#ifdef WITH_XSLT_DEBUG_EXTENSIONS
xsltGenericDebug(xsltGenericDebugContext,
- "Registering extension prefix %s : %s\n", prefix,
- URI);
+ "Registering extension namespace '%s'.\n", URI);
#endif
def = (xsltExtDefPtr) style->nsDefs;
#ifdef XSLT_REFACTORED
#define WITH_XSLT_DEBUG_KEYS
#endif
-typedef struct _xsltKeyDef xsltKeyDef;
-typedef xsltKeyDef *xsltKeyDefPtr;
-struct _xsltKeyDef {
- struct _xsltKeyDef *next;
- xmlNodePtr inst;
- xmlChar *name;
- xmlChar *nameURI;
- xmlChar *match;
- xmlChar *use;
- xmlXPathCompExprPtr comp;
- xmlXPathCompExprPtr usecomp;
- xmlNsPtr *nsList; /* the namespaces in scope */
- int nsNr; /* the number of namespaces in scope */
-};
-
-typedef struct _xsltKeyTable xsltKeyTable;
-typedef xsltKeyTable *xsltKeyTablePtr;
-struct _xsltKeyTable {
- struct _xsltKeyTable *next;
- xmlChar *name;
- xmlChar *nameURI;
- xmlHashTablePtr keys;
-};
-
/************************************************************************
* *
const xmlChar *nameURI, const xmlChar *value) {
xmlNodeSetPtr ret;
xsltKeyTablePtr table;
+#ifdef XSLT_REFACTORED_KEYCOMP
+ int found = 0;
+#endif
if ((ctxt == NULL) || (name == NULL) || (value == NULL) ||
(ctxt->document == NULL))
#endif
table = (xsltKeyTablePtr) ctxt->document->keys;
while (table != NULL) {
- if (xmlStrEqual(table->name, name) &&
- (((nameURI == NULL) && (table->nameURI == NULL)) ||
- ((nameURI != NULL) && (table->nameURI != NULL) &&
- (xmlStrEqual(table->nameURI, nameURI))))) {
+ if (((nameURI != NULL) == (table->nameURI != NULL)) &&
+ xmlStrEqual(table->name, name) &&
+ xmlStrEqual(table->nameURI, nameURI))
+ {
+#ifdef XSLT_REFACTORED_KEYCOMP
+ found = 1;
+#endif
ret = (xmlNodeSetPtr)xmlHashLookup(table->keys, value);
return(ret);
}
table = table->next;
}
+#ifdef XSLT_REFACTORED_KEYCOMP
+ if (! found) {
+ xsltStylesheetPtr style = ctxt->style;
+ xsltKeyDefPtr keyd;
+ /*
+ * This might be the first call to the key with the specified
+ * name and the specified document.
+ * Find all keys with a matching name and compute them for the
+ * current tree.
+ */
+ found = 0;
+ while (style != NULL) {
+ keyd = (xsltKeyDefPtr) style->keys;
+ while (keyd != NULL) {
+ if (((nameURI != NULL) == (keyd->nameURI != NULL)) &&
+ xmlStrEqual(keyd->name, name) &&
+ xmlStrEqual(keyd->nameURI, nameURI))
+ {
+ found = 1;
+ xsltInitCtxtKey(ctxt, ctxt->document, keyd);
+ }
+ keyd = keyd->next;
+ }
+ style = xsltNextImport(style);
+ }
+ if (found) {
+ /*
+ * The key was computed, so look it up.
+ */
+ table = (xsltKeyTablePtr) ctxt->document->keys;
+ while (table != NULL) {
+ if (((nameURI != NULL) == (table->nameURI != NULL)) &&
+ xmlStrEqual(table->name, name) &&
+ xmlStrEqual(table->nameURI, nameURI))
+ {
+ ret = (xmlNodeSetPtr)xmlHashLookup(table->keys, value);
+ return(ret);
+ }
+ table = table->next;
+ }
+
+ }
+ }
+#endif
return(NULL);
}
ctxt->xpathCtxt->namespaces = oldNamespaces;
return(ret);
}
+
/**
* xsltInitCtxtKey:
* @ctxt: an XSLT transformation context
*
* Computes the key tables this key and for the current input document.
*/
-static void
+int
xsltInitCtxtKey(xsltTransformContextPtr ctxt, xsltDocumentPtr doc,
xsltKeyDefPtr keyd) {
int i;
int oldNsNr;
xmlNsPtr *oldNamespaces;
+ doc->nbKeysComputed++;
/*
* Evaluate the nodelist
*/
ctxt->node = oldNode;
if (res != NULL)
xmlXPathFreeObject(res);
+ return(0);
}
/**
*
* Computes all the keys tables for the current input document.
* Should be done before global varibales are initialized.
+ * NOTE: Not used anymore in the refactored code.
*/
void
xsltInitCtxtKeys(xsltTransformContextPtr ctxt, xsltDocumentPtr doc) {
int isRVT;
doc = node->doc;
- if ((doc != NULL) &&
- (doc->name != NULL) &&
- (doc->name[0] == ' ') &&
- (xmlStrEqual(BAD_CAST doc->name,
- BAD_CAST " fake node libxslt")))
+ if (XSLT_IS_RES_TREE_FRAG(doc))
isRVT = 1;
else
isRVT = 0;
}
doc = node->doc;
- if ((doc != NULL) &&
- (doc->name != NULL) &&
- (doc->name[0] == ' ') &&
- (xmlStrEqual(BAD_CAST doc->name,
- BAD_CAST " fake node libxslt")))
+ if (XSLT_IS_RES_TREE_FRAG(doc))
isRVT = 1;
else
isRVT = 0;
return;
}
NEXT;
- /* TODO: support namespace in keys */
+ /* URGENT TODO: support namespace in keys */
PUSH(XSLT_OP_KEY, lit, lit2, novar);
} else if (xmlStrEqual(name, (const xmlChar *)"processing-instruction")) {
NEXT;
return(0);
}
+#ifdef XSLT_REFACTORED_KEYCOMP
+static int
+xsltComputeAllKeys(xsltTransformContextPtr ctxt,
+ xsltDocumentPtr document)
+{
+ xsltStylesheetPtr style, style2;
+ xsltKeyDefPtr keyd, keyd2;
+ xsltKeyTablePtr table;
+
+ if ((ctxt == NULL) || (document == NULL))
+ return(-1);
+
+ if (document->nbKeysComputed == ctxt->nbKeys)
+ return(0);
+ /*
+ * TODO: This could be further optimized
+ */
+ style = ctxt->style;
+ while (style) {
+ keyd = (xsltKeyDefPtr) style->keys;
+ while (keyd != NULL) {
+ /*
+ * Check if keys with this QName have been already
+ * computed.
+ */
+ table = (xsltKeyTablePtr) document->keys;
+ while (table) {
+ if (((keyd->nameURI != NULL) == (table->nameURI != NULL)) &&
+ xmlStrEqual(keyd->name, table->name) &&
+ xmlStrEqual(keyd->nameURI, table->nameURI))
+ {
+ break;
+ }
+ table = table->next;
+ }
+ if (table == NULL) {
+ /*
+ * Keys with this QName have not been yet computed.
+ */
+ style2 = ctxt->style;
+ while (style2 != NULL) {
+ keyd2 = (xsltKeyDefPtr) style2->keys;
+ while (keyd2 != NULL) {
+ if (((keyd2->nameURI != NULL) ==
+ (keyd->nameURI != NULL)) &&
+ xmlStrEqual(keyd2->name, keyd->name) &&
+ xmlStrEqual(keyd2->nameURI, keyd->nameURI))
+ {
+ xsltInitCtxtKey(ctxt, document, keyd2);
+ if (document->nbKeysComputed == ctxt->nbKeys)
+ return(0);
+ }
+ keyd2 = keyd2->next;
+ }
+ style2 = xsltNextImport(style2);
+ }
+ }
+ keyd = keyd->next;
+ }
+ style = xsltNextImport(style);
+ }
+ return(0);
+}
+#endif
+
/**
* xsltGetTemplate:
* @ctxt: a XSLT process context
}
}
+#ifdef XSLT_REFACTORED_KEYCOMP
+keyed_match:
+#endif
if (keyed) {
list = curstyle->keyMatch;
while ((list != NULL) &&
list = list->next;
}
}
+#ifdef XSLT_REFACTORED_KEYCOMP
+ else if (ctxt->hasTemplKeyPatterns &&
+ (ctxt->document->nbKeysComputed < ctxt->nbKeys))
+ {
+ /*
+ * Compute all remaining keys for this document.
+ *
+ * REVISIT TODO: I think this could be further optimized.
+ */
+ xsltComputeAllKeys(ctxt, ctxt->document);
+
+ switch (node->type) {
+ case XML_ELEMENT_NODE:
+ if (node->psvi != NULL) keyed = 1;
+ break;
+ case XML_ATTRIBUTE_NODE:
+ if (((xmlAttrPtr) node)->psvi != NULL) keyed = 1;
+ break;
+ case XML_TEXT_NODE:
+ case XML_CDATA_SECTION_NODE:
+ case XML_COMMENT_NODE:
+ case XML_PI_NODE:
+ if (node->psvi != NULL) keyed = 1;
+ break;
+ case XML_DOCUMENT_NODE:
+ case XML_HTML_DOCUMENT_NODE:
+ if (((xmlDocPtr) node)->psvi != NULL) keyed = 1;
+ break;
+ default:
+ break;
+ }
+ if (keyed)
+ goto keyed_match;
+ }
+#endif /* XSLT_REFACTORED_KEYCOMP */
if (ret != NULL)
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);
- }
+ case XSLT_FUNC_LITERAL_RESULT_ELEMENT:
break;
case XSLT_FUNC_COPY:
break;
if (parent->children == NULL)
return(NULL);
+ /*
+ * This creates a temporary element-node to add the resulting
+ * text content to.
+ * OPTIMIZE TODO: Keep such an element-node in the transformation
+ * context to avoid creating it every time.
+ */
insert = xmlNewDocNode(ctxt->output, NULL,
(const xmlChar *)"fake", NULL);
if (insert == NULL) {
}
oldInsert = ctxt->insert;
ctxt->insert = insert;
-
+ /* OPTIMIZE TODO: if parent->children consists only of text-nodes. */
xsltApplyOneTemplate(ctxt, node, parent->children, NULL, NULL);
ctxt->insert = oldInsert;
((target->ns != NULL) &&
(xmlHashLookup2(ctxt->style->cdataSection,
target->name, target->ns->href) != NULL)))) {
- /*
+ /* OPTIMIZE TODO: xsltCopyText() is also used for attribute content.
* nodes which must be output as CDATA due to the stylesheet
*/
copy = xmlNewCDataBlock(ctxt->output, cur->content,
return NULL;
if (cur->name == xmlStringTextNoenc)
copy->name = xmlStringTextNoenc;
- /*
+ /* OPTIMIZE TODO: get rid of xmlDictOwns() in safe cases; e.g. attribute values don't need the lookup
* Must confirm that content is in dict
* (bug 302821)
*/
case XML_XINCLUDE_START:
case XML_XINCLUDE_END:
return(NULL);
- }
- if ((node->name != NULL) && (node->name[0] == ' ') &&
- (xmlStrEqual(node->name, (const xmlChar *) " fake node libxslt"))) {
+ }
+ if (XSLT_IS_RES_TREE_FRAG(node)) {
if (node->children != NULL)
copy = xsltCopyTreeList(ctxt, node->children, insert, 0);
else
}
}
+#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);
+}
+
/**
-* xsltTransLREAcquireInScopeNs:
+* xsltTransLREAcquireResultInScopeNs:
* @ctxt: the transformation context
* @cur: the literal result element
* @ns: the namespace
* 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)
+static xmlNsPtr
+xsltTransLREAcquireResultInScopeNs(xsltTransformContextPtr ctxt,
+ xmlNodePtr cur, xmlNsPtr literalNs,
+ xmlNodePtr resultElem)
{
xmlNsPtr ns;
int prefixOccupied = 0;
- if ((ctxt == NULL) || (cur == NULL) ||
- (resultElem == NULL) || (literalNs == NULL))
+ if ((ctxt == NULL) || (cur == NULL) || (resultElem == NULL))
return(NULL);
/*
* 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.
*/
-#if 0
ns = xmlSearchNsByHref(resultElem->doc, resultElem,
literalNs->href);
if (ns != NULL)
return(ns);
-#endif
/*
* Create the ns-decl on the current result element.
*/
return(NULL);
}
+#endif /* XSLT_REFACTORED */
+
/**
* xsltApplyOneTemplate:
* @ctxt: a XSLT process context
* declarations; thus lookup if there is already
* such a ns-decl in the result.
*/
- ns = xmlSearchNs(copy->doc, copy,
- effNs->prefix);
+ 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);
+ ns = xmlNewNs(copy, effNs->nsName, effNs->prefix);
if (ns == NULL) {
xsltTransformError(ctxt, NULL, cur,
"Internal error in xsltApplyOneTemplateInt(): "
* 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;
-
+ copy->ns = xsltTransLREAcquireResultInScopeNs(ctxt,
+ cur, cur->ns, 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.
+ *
* REVISIT TODO: 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
}
}
/*
case XML_HTML_DOCUMENT_NODE:
break;
case XML_ELEMENT_NODE:
- if (xmlStrEqual(node->name, BAD_CAST " fake node libxslt"))
- return;
+ /*
+ * NOTE: The "fake" is a doc-node, not an element node.
+ * OLD:
+ * if (xmlStrEqual(node->name, BAD_CAST " fake node libxslt"))
+ * return;
+ */
#ifdef WITH_XSLT_DEBUG_PROCESS
XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
if (comp->use != NULL) {
xsltApplyAttributeSet(ctxt, node, inst, comp->use);
} else {
+ /*
+ * 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) {
if ((list != NULL) && (ctxt->document->keys != NULL)) {
if ((list->nodeNr != 0) &&
(list->nodeTab[0]->doc != NULL) &&
- (xmlStrEqual((xmlChar *)list->nodeTab[0]->doc->name,
- (const xmlChar *) " fake node libxslt")) &&
+
+ XSLT_IS_RES_TREE_FRAG(list->nodeTab[0]->doc) &&
+
(list->nodeTab[0]->doc->_private == NULL)) {
list->nodeTab[0]->doc->_private = xsltNewDocument(
ctxt, list->nodeTab[0]->doc);
return;
}
+#ifdef XSLT_REFACTORED_KEYCOMP
+static int
+xsltCountKeys(xsltTransformContextPtr ctxt)
+{
+ xsltStylesheetPtr style;
+ xsltKeyDefPtr keyd;
+
+ if (ctxt == NULL)
+ return(-1);
+
+ /*
+ * Do we have those nastly templates with a key() in the match pattern?
+ */
+ ctxt->hasTemplKeyPatterns = 0;
+ style = ctxt->style;
+ while (style != NULL) {
+ if (style->keyMatch != NULL) {
+ ctxt->hasTemplKeyPatterns = 1;
+ break;
+ }
+ style = xsltNextImport(style);
+ }
+ /*
+ * Count number of key declarations.
+ */
+ ctxt->nbKeys = 0;
+ style = ctxt->style;
+ while (style != NULL) {
+ keyd = style->keys;
+ while (keyd) {
+ ctxt->nbKeys++;
+ keyd = keyd->next;
+ }
+ style = xsltNextImport(style);
+ }
+ return(ctxt->nbKeys);
+}
+#endif /* XSLT_REFACTORED_KEYCOMP */
+
/**
* xsltApplyStylesheetInternal:
* @style: a parsed XSLT stylesheet
if (params != NULL)
xsltEvalUserParams(ctxt, params);
xsltEvalGlobalVariables(ctxt);
+#ifdef XSLT_REFACTORED_KEYCOMP
+ xsltCountKeys(ctxt);
+#endif
ctxt->node = (xmlNodePtr) doc;
varsPush(ctxt, NULL);
ctxt->varsBase = ctxt->varsNr - 1;
#define WITH_XSLT_DEBUG_VARIABLE
#endif
+#ifdef XSLT_REFACTORED
+const xmlChar *xsltDocFragFake = (const xmlChar *) " fake node libxslt";
+#endif
+
/************************************************************************
* *
* Result Value Tree interfaces *
{
xmlDocPtr container;
+ /*
+ * TODO: Couldn't we use an XML_DOCUMENT_FRAG_NODE for this?
+ */
if (ctxt == NULL) return(NULL);
container = xmlNewDoc(NULL);
"reusing transformation dict for RVT\n");
#endif
- container->name = (char *) xmlStrdup(BAD_CAST " fake node libxslt");
+ XSLT_MARK_RES_TREE_FRAG(container);
container->doc = container;
container->parent = NULL;
return(container);
}
static xsltNsMapPtr
-xsltNewNamespaceMapItem(xsltCompilerCtxtPtr cctxt,
+xsltNewNamespaceMapItem(xsltCompilerCtxtPtr cctxt,
xmlDocPtr doc,
- xmlNodePtr elem,
- xmlNsPtr ns)
+ xmlNsPtr ns,
+ xmlNodePtr elem)
{
xsltNsMapPtr ret;
- if ((cctxt == NULL) || (doc == NULL) || (elem == NULL) ||
- (ns == NULL))
+ if ((cctxt == NULL) || (doc == NULL) || (ns == NULL))
return(NULL);
ret = (xsltNsMapPtr) xmlMalloc(sizeof(xsltNsMap));
{
if (cctxt == NULL)
return;
+#ifdef WITH_XSLT_DEBUG_PARSING
+ xsltGenericDebug(xsltGenericDebugContext,
+ "Freeing compilation context\n");
+ xsltGenericDebug(xsltGenericDebugContext,
+ "### Max inodes: %d\n", cctxt->maxNodeInfos);
+ xsltGenericDebug(xsltGenericDebugContext,
+ "### Max LREs : %d\n", cctxt->maxLREs);
+#endif
/*
* Free node-infos.
*/
}
if (cctxt->tmpList != NULL)
xsltPointerListFree(cctxt->tmpList);
+#ifdef XSLT_REFACTORED_XPATHCOMP
if (cctxt->xpathCtxt != NULL)
xmlXPathFreeContext(cctxt->xpathCtxt);
+#endif
if (cctxt->nsAliases != NULL)
xsltFreeNsAliasList(cctxt->nsAliases);
if (ret->tmpList == NULL) {
goto internal_err;
}
+#ifdef XSLT_REFACTORED_XPATHCOMP
/*
* 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;
+#endif
return(ret);
return(NULL);
}
+static void
+xsltLREEffectiveNsNodesFree(xsltEffectiveNsPtr first)
+{
+ xsltEffectiveNsPtr tmp;
+
+ while (first != NULL) {
+ tmp = first;
+ first = first->nextInStore;
+ xmlFree(tmp);
+ }
+}
static void
xsltFreePrincipalStylesheetData(xsltPrincipalStylesheetDataPtr data)
xsltPointerListFree(list);
data->extElemNamespaces = NULL;
}
+ if (data->effectiveNs) {
+ xsltLREEffectiveNsNodesFree(data->effectiveNs);
+ data->effectiveNs = NULL;
+ }
#ifdef XSLT_REFACTORED_XSLT_NSCOMP
xsltFreeNamespaceMap(data->nsMap);
#endif
}
memset(ns, 0, sizeof(xmlNs));
ns->type = XML_LOCAL_NAMESPACE;
+ /*
+ * URGENT TODO: revisit this.
+ */
+#ifdef LIBXML_NAMESPACE_DICT
+ if (doc->dict)
+ ns->href = xmlDictLookup(doc->dict, XML_XML_NAMESPACE, -1);
+ else
+ ns->href = xmlStrdup(XML_XML_NAMESPACE);
+#else
ns->href = xmlStrdup(XML_XML_NAMESPACE);
+#endif
ns->prefix = xmlStrdup((const xmlChar *)"xml");
doc->oldNs = ns;
return (ns);
static int
xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt,
xsltStyleItemLRElementInfoPtr item,
- xmlNodePtr elem)
+ xmlNodePtr elem,
+ int isLRE)
{
- xmlNsPtr ns;
+ xmlNsPtr ns, tmpns;
xsltEffectiveNsPtr effNs, lastEffNs = NULL;
- int i;
+ int i, j, holdByElem;
xsltPointerListPtr extElemNs = cctxt->inode->extElemNs;
xsltPointerListPtr exclResultNs = cctxt->inode->exclResultNs;
(item == NULL) || (item->effectiveNs != NULL))
return(-1);
- if (elem->nsDef == NULL)
+ if (item->inScopeNs == NULL)
return(0);
extElemNs = cctxt->inode->extElemNs;
exclResultNs = cctxt->inode->exclResultNs;
- for (ns = elem->nsDef; ns != NULL; ns = ns->next) {
+ for (i = 0; i < item->inScopeNs->number; i++) {
+ ns = item->inScopeNs->list[i];
/*
* Skip namespaces designated as excluded namespaces
* -------------------------------------------------
* Exclude excluded result namespaces.
*/
if (exclResultNs) {
- for (i = 0; i < exclResultNs->number; i++)
- if (xmlStrEqual(ns->href, BAD_CAST exclResultNs->items[i]))
+ 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 (i = 0; i < extElemNs->number; i++)
- if (xmlStrEqual(ns->href, BAD_CAST extElemNs->items[i]))
+ for (j = 0; j < extElemNs->number; j++)
+ if (xmlStrEqual(ns->href, BAD_CAST extElemNs->items[j]))
goto skip_ns;
}
/*
+ * OPTIMIZE TODO: This information may not be needed.
+ */
+ if (isLRE && (elem->nsDef != NULL)) {
+ holdByElem = 0;
+ tmpns = elem->nsDef;
+ do {
+ if (tmpns == ns) {
+ holdByElem = 1;
+ break;
+ }
+ tmpns = tmpns->next;
+ } while (tmpns != NULL);
+ } else
+ holdByElem = 0;
+ /*
* Apply namespace aliasing
* ------------------------
*
* TODO: What to do with xmlns="" ?
*/
if ((alias->literalNs != NULL) &&
- (alias->literalNs->href == ns->href))
+ (xmlStrEqual(alias->literalNs->href, ns->href)))
{
/*
* Recognized as an namespace alias; convert it to
alias = alias->next;
} while (alias != NULL);
}
+
/*
* Add the effective namespace declaration.
*/
cctxt->style->errors++;
return(-1);
}
+ if (cctxt->psData->effectiveNs == NULL) {
+ cctxt->psData->effectiveNs = effNs;
+ effNs->nextInStore = NULL;
+ } else {
+ effNs->nextInStore = cctxt->psData->effectiveNs;
+ cctxt->psData->effectiveNs = effNs;
+ }
+
effNs->next = NULL;
effNs->prefix = ns->prefix;
effNs->nsName = ns->href;
+ effNs->holdByElem = holdByElem;
if (lastEffNs == NULL)
item->effectiveNs = effNs;
else
lastEffNs->next = effNs;
- lastEffNs = effNs;
+ lastEffNs = effNs;
skip_ns:
{}
/**
* xsltLREInfoCreate:
*
+ * @isLRE: indicates if the given @elem is a literal result element
+ *
* Creates a new info for a literal result element.
*/
static int
xsltLREInfoCreate(xsltCompilerCtxtPtr cctxt,
- xmlNodePtr elem)
+ xmlNodePtr elem,
+ int isLRE)
{
xsltStyleItemLRElementInfoPtr item;
*/
item->inScopeNs = cctxt->inode->inScopeNs;
- if (elem && (elem->nsDef != NULL))
- xsltLREBuildEffectiveNsNodes(cctxt, item, elem);
+ if (elem)
+ xsltLREBuildEffectiveNsNodes(cctxt, item, elem, isLRE);
cctxt->inode->litResElemInfo = item;
cctxt->inode->nsChanged = 0;
+ cctxt->maxLREs++;
return(0);
}
xsltCompilerNodeInfoPtr
xsltCompilerNodePush(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
{
- xsltCompilerNodeInfoPtr inode;
+ xsltCompilerNodeInfoPtr inode, iprev;
if ((cctxt->inode != NULL) && (cctxt->inode->next != NULL)) {
inode = cctxt->inode->next;
* Create an initial literal result element info for
* the root of the stylesheet.
*/
- xsltLREInfoCreate(cctxt, NULL);
+ xsltLREInfoCreate(cctxt, NULL, 0);
}
}
cctxt->depth++;
inode->extContentHandled = 0;
inode->isRoot = 0;
- if (inode->prev != NULL) {
+ if (inode->prev != NULL) {
+ iprev = inode->prev;
/*
* Inherit the following information:
* ---------------------------------
*
* In-scope namespaces
*/
- inode->inScopeNs = inode->prev->inScopeNs;
+ inode->inScopeNs = iprev->inScopeNs;
/*
* Info for literal result elements
*/
- inode->litResElemInfo = inode->prev->litResElemInfo;
- inode->nsChanged = inode->prev->nsChanged;
+ inode->litResElemInfo = iprev->litResElemInfo;
+ inode->nsChanged = iprev->nsChanged;
/*
* Excluded result namespaces
*/
- inode->exclResultNs = inode->prev->exclResultNs;
+ inode->exclResultNs = iprev->exclResultNs;
/*
* Extension instruction namespaces
*/
- inode->extElemNs = inode->prev->extElemNs;
+ inode->extElemNs = iprev->extElemNs;
/*
* Whitespace preservation
*/
- inode->preserveWhitespace = inode->prev->preserveWhitespace;
+ inode->preserveWhitespace = iprev->preserveWhitespace;
/*
* Forwards-compatible mode
*/
- inode->forwardsCompat = inode->prev->forwardsCompat;
+ inode->forwardsCompat = iprev->forwardsCompat;
} else {
inode->inScopeNs = NULL;
inode->exclResultNs = NULL;
static xsltPointerListPtr
xsltParseExclResultPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
xsltPointerListPtr def,
- int isXsltElem)
+ int instrCategory)
{
xsltPointerListPtr list = NULL;
xmlChar *value = NULL;
if ((cctxt == NULL) || (node == NULL))
return(NULL);
- if (isXsltElem)
+ if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
value = xmlGetNsProp(node, BAD_CAST "exclude-result-prefixes", NULL);
else
value = xmlGetNsProp(node, BAD_CAST "exclude-result-prefixes",
static xsltPointerListPtr
xsltParseExtElemPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
xsltPointerListPtr def,
- int isXsltElem)
+ int instrCategory)
{
xsltPointerListPtr list = NULL;
+ xmlAttrPtr attr;
xmlChar *value;
int i;
if ((cctxt == NULL) || (node == NULL))
return(NULL);
- if (isXsltElem)
- value = xmlGetNsProp(node, BAD_CAST "extension-element-prefixes", NULL);
+ if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
+ attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes", NULL);
else
- value = xmlGetNsProp(node, BAD_CAST "extension-element-prefixes",
+ attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes",
XSLT_NAMESPACE);
+ if (attr == NULL)
+ return(def);
- if (value == NULL)
+ if ((attr->children != NULL) &&
+ (attr->children->content != NULL))
+ value = attr->children->content;
+ else {
+ xsltTransformError(NULL, cctxt->style, node,
+ "Attribute 'extension-element-prefixes': Invalid value.\n");
+ cctxt->style->errors++;
return(def);
+ }
+
if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,
BAD_CAST value) != 0)
cctxt->inode->nsChanged = 1;
exit:
- if (value != NULL)
- xmlFree(value);
+ if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
+ /*
+ * Remove the XSLT attribute from the literal result element.
+ */
+ xmlUnlinkNode((xmlNodePtr) attr);
+ xmlFreeProp(attr);
+ }
if (list != NULL)
return(list);
else
*/
static int
xsltParseAttrXSLTVersion(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
- int isXsltElem)
+ int instrCategory)
{
xmlChar *value;
+ xmlAttrPtr attr;
if ((cctxt == NULL) || (node == NULL))
return(-1);
- if (isXsltElem)
- value = xmlGetNsProp(node, BAD_CAST "version", NULL);
+ if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
+ attr = xmlHasNsProp(node, BAD_CAST "version", NULL);
else
- value = xmlGetNsProp(node, BAD_CAST "version", XSLT_NAMESPACE);
+ attr = xmlHasNsProp(node, BAD_CAST "version", XSLT_NAMESPACE);
- if (value == NULL)
+ if (attr == NULL)
return(0);
+
+ if ((attr->children != NULL) &&
+ (attr->children->content != NULL))
+ value = attr->children->content;
+ else {
+ xsltTransformError(NULL, cctxt->style, node,
+ "Attribute 'version': Invalid value.\n");
+ cctxt->style->errors++;
+ return(1);
+ }
if (! xmlStrEqual(value, (const xmlChar *)"1.0")) {
cctxt->inode->forwardsCompat = 1;
} else {
cctxt->inode->forwardsCompat = 0;
}
- xmlFree(value);
+
+ if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
+ /*
+ * Remove the XSLT attribute from the literal result element.
+ */
+ xmlUnlinkNode((xmlNodePtr) attr);
+ xmlFreeProp(attr);
+ }
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)
{
if (IS_XSLT_ELEM(cur)) {
#ifdef XSLT_REFACTORED_XSLT_NSCOMP
if (cur->ns->href != nsNameXSLT) {
- nsMapItem = xsltNewNamespaceMapItem(cctxt,
- doc, cur, cur->ns);
+ nsMapItem = xsltNewNamespaceMapItem(cctxt,
+ doc, cur->ns, cur);
if (nsMapItem == NULL)
goto internal_err;
cur->ns->href = nsNameXSLT;
findSpaceAttr = 0;
attr = cur->properties;
do {
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP
+ if ((attr->ns) && (attr->ns->href != nsNameXSLT) &&
+ xmlStrEqual(attr->ns->href, nsNameXSLT))
+ {
+ nsMapItem = xsltNewNamespaceMapItem(cctxt,
+ doc, attr->ns, cur);
+ if (nsMapItem == NULL)
+ goto internal_err;
+ attr->ns->href = nsNameXSLT;
+ }
+#endif
if (internalize) {
/*
* Internalize the attribute's value; the goal is to
if (cur->properties)
cctxt->inode->extElemNs =
xsltParseExtElemPrefixes(cctxt,
- cur, cctxt->inode->extElemNs, 0);
+ cur, cctxt->inode->extElemNs,
+ XSLT_ELEMENT_CATEGORY_LRE);
/*
* Eval if we have an extension instruction here.
*/
* xsl:version NMTOKEN #IMPLIED
*/
cur->psvi = NULL;
- cctxt->inode->category = XSLT_ELEMENT_CATEGORY_LR;
+ cctxt->inode->category = XSLT_ELEMENT_CATEGORY_LRE;
if (cur->properties != NULL) {
/*
* Attribute "xsl:exclude-result-prefixes".
*/
cctxt->inode->exclResultNs =
xsltParseExclResultPrefixes(cctxt, cur,
- cctxt->inode->exclResultNs, 0);
+ cctxt->inode->exclResultNs,
+ XSLT_ELEMENT_CATEGORY_LRE);
/*
* Attribute "xsl:version".
*/
- xsltParseAttrXSLTVersion(cctxt, cur, 0);
+ xsltParseAttrXSLTVersion(cctxt, cur,
+ XSLT_ELEMENT_CATEGORY_LRE);
+ /*
+ * Report invalid XSLT attributes.
+ */
+ if (cur->properties) {
+ xmlAttrPtr attr = cur->properties;
+
+ do {
+ if (IS_XSLT_ATTR_FAST(attr) &&
+ (! xmlStrEqual(attr->name,
+ BAD_CAST "use-attribute-sets")))
+ {
+ xsltTransformError(NULL, cctxt->style, cur,
+ "Unknown XSLT attribute '%s'.\n",
+ attr->name);
+ cctxt->style->errors++;
+ }
+ attr = attr->next;
+ } while (attr != NULL);
+ }
}
/*
* Create/reuse info for the literal result element.
*/
if (cctxt->inode->nsChanged)
- xsltLREInfoCreate(cctxt, cur);
+ xsltLREInfoCreate(cctxt, cur, 1);
cur->psvi = cctxt->inode->litResElemInfo;
/*
* Apply ns-aliasing on the element and on its attributes.
error:
xsltCompilerNodePop(cctxt, templNode);
-
return;
}
cctxt->inode->isRoot = 1;
cctxt->inode->nsChanged = 0;
/*
- * Start with the dummy info for literal result elements.
+ * Start with the naked dummy info for literal result elements.
*/
cctxt->inode->litResElemInfo = cctxt->inodeList->litResElemInfo;
* exclude-result-prefixes = tokens
* version = number (mandatory)
*/
- if (xsltParseAttrXSLTVersion(cctxt, node, 1) == 0) {
+ if (xsltParseAttrXSLTVersion(cctxt, node,
+ XSLT_ELEMENT_CATEGORY_XSLT) == 0)
+ {
/*
* Attribute "version".
* XSLT 1.0: "An xsl:stylesheet element *must* have a version
* Attribute "extension-element-prefixes".
*/
cctxt->inode->extElemNs =
- xsltParseExtElemPrefixes(cctxt, node, NULL, 1);
+ xsltParseExtElemPrefixes(cctxt, node, NULL,
+ XSLT_ELEMENT_CATEGORY_XSLT);
/*
* Attribute "exclude-result-prefixes".
*/
cctxt->inode->exclResultNs =
- xsltParseExclResultPrefixes(cctxt, node, NULL, 1);
+ xsltParseExclResultPrefixes(cctxt, node, NULL,
+ XSLT_ELEMENT_CATEGORY_XSLT);
/*
* Create/reuse info for the literal result element.
*/
if (cctxt->inode->nsChanged)
- xsltLREInfoCreate(cctxt, NULL);
+ xsltLREInfoCreate(cctxt, node, 0);
/*
* Processed top-level elements:
* ----------------------------
function(style, cur);
#ifdef WITH_XSLT_DEBUG_PARSING
xsltGenericDebug(xsltGenericDebugContext,
- "xsltParseStylesheetTop : found foreign element %s\n",
- cur->name);
+ "xsltParseXSLTStylesheetElemCore : User-defined "
+ "data element '%s'.\n", cur->name);
#endif
}
}
}
exit:
- xsltCompilerNodePop(cctxt, node);
+
#ifdef WITH_XSLT_DEBUG_PARSING
xsltGenericDebug(xsltGenericDebugContext,
- "parsed %d templates\n", templates);
-#endif
+ "### END of parsing top-level elements of doc '%s'.\n",
+ node->doc->URL);
+ xsltGenericDebug(xsltGenericDebugContext,
+ "### Templates: %d\n", templates);
+#ifdef XSLT_REFACTORED
+ xsltGenericDebug(xsltGenericDebugContext,
+ "### Max inodes: %d\n", cctxt->maxNodeInfos);
+ xsltGenericDebug(xsltGenericDebugContext,
+ "### Max LREs : %d\n", cctxt->maxLREs);
+#endif /* XSLT_REFACTORED */
+#endif /* WITH_XSLT_DEBUG_PARSING */
+
+ xsltCompilerNodePop(cctxt, node);
return(0);
}
return(-1);
if (node->children == NULL)
- goto exit;
+ goto exit;
+
/*
* Process top-level elements:
* xsl:import (must be first)
}
/*
* Pre-process all xsl:namespace-alias elements.
+ * URGENT TODO: This won't work correctly: the order of included
+ * aliases and aliases defined here is significant.
*/
cur = start;
while ((cur != NULL) &&
* Now parse the rest of the top-level elements.
*/
xsltParseXSLTStylesheetElemCore(cctxt, node);
-exit:
+exit:
+
return(0);
}
if ((cctxt == NULL) || (node == NULL))
return(-1);
- /*
- *
- */
- if (xsltParseAttrXSLTVersion(cctxt, node, 0) == 0) {
+
+ if (xsltParseAttrXSLTVersion(cctxt, node, 0) == XSLT_ELEMENT_CATEGORY_LRE)
+ {
/*
* TODO: Adjust report, since this might be an
* embedded stylesheet.
while (ns != NULL) {
if ((ns->doc == doc) && (ns->ns != NULL)) {
ns->ns->href = ns->origNsName;
- ns->ns = NULL;
- ns->origNsName = NULL;
+ ns->origNsName = NULL;
+ ns->ns = NULL;
}
ns = ns->next;
}
*/
retStyle->doc = NULL;
/*
- * Cleanup the doc if its the main doc.
+ * Cleanup the doc if its the main stylesheet.
*/
- if (parentStyle == NULL)
+ if (parentStyle == NULL) {
xsltCleanupStylesheetTree(doc, xmlDocGetRootElement(doc));
+ if (retStyle->compCtxt != NULL) {
+ xsltCompilationCtxtFree(retStyle->compCtxt);
+ retStyle->compCtxt = NULL;
+ }
+ }
xsltFreeStylesheet(retStyle);
retStyle = NULL;
* xsltParseStylesheetImportedDoc().
*/
if (ret->compCtxt != NULL) {
- /* TEST TODO: REMOVE test output*/
- /* printf("MAX NODE INFO: %d\n", XSLT_CCTXT(ret)->maxNodeInfos); */
xsltCompilationCtxtFree(XSLT_CCTXT(ret));
ret->compCtxt = NULL;
}
#include <libxml/xpath.h>
#include <libxml/xmlerror.h>
#include <libxml/dict.h>
+#include <libxml/xmlstring.h>
#include <libxslt/xslt.h>
#include "xsltexports.h"
#include "numbersInternals.h"
extern "C" {
#endif
-#define XSLT_IS_TEXT_NODE(n) (((n) != NULL) && \
+#define XSLT_IS_TEXT_NODE(n) ((n != NULL) && \
(((n)->type == XML_TEXT_NODE) || \
((n)->type == XML_CDATA_SECTION_NODE)))
+
+#if 0
+
+extern const xmlChar *xsltDocFragFake;
+
+#define XSLT_MARK_RES_TREE_FRAG(n) (n)->psvi = (void *) xsltDocFragFake;
+
+#define XSLT_IS_RES_TREE_FRAG(n) \
+ ((n != NULL) && ((n)->type == XML_DOCUMENT_NODE) && \
+ ((n)->psvi == xsltDocFragFake))
+
+#else
+
+#define XSLT_MARK_RES_TREE_FRAG(n) \
+ (n)->name = (char *) xmlStrdup(BAD_CAST " fake node libxslt");
+
+#define XSLT_IS_RES_TREE_FRAG(n) \
+ ((n != NULL) && ((n)->type == XML_DOCUMENT_NODE) && \
+ ((n)->name != NULL) && ((n)->name[0] == ' ') && \
+ xmlStrEqual(BAD_CAST (n)->name, BAD_CAST " fake node libxslt"))
+
+#endif
+
+/**
+ * XSLT_REFACTORED_KEYCOMP:
+ *
+ * Internal define to enable on-demand xsl:key computation.
+ */
+#define XSLT_REFACTORED_KEYCOMP
+
/**
* XSLT_REFACTORED:
*
* Internal define to enable the refactored parts of Libxslt.
*/
/* #define XSLT_REFACTORED */
+/* ==================================================================== */
#ifdef XSLT_REFACTORED
-
/* TODO: REMOVE: #define XSLT_REFACTORED_EXCLRESNS */
/* TODO: REMOVE: #define XSLT_REFACTORED_NSALIAS */
(((n) != NULL) && ((n)->ns != NULL) && \
((n)->ns->href == xsltConstNamespaceNameXSLT))
+#define IS_XSLT_ATTR_FAST(a) \
+ (((a) != NULL) && ((a)->ns != NULL) && \
+ ((a)->ns->href == xsltConstNamespaceNameXSLT))
+
#define XSLT_HAS_INTERNAL_NSMAP(s) \
(((s) != NULL) && ((s)->principal) && \
((s)->principal->principalData) && \
(((n) != NULL) && ((n)->ns != NULL) && \
(xmlStrEqual((n)->ns->href, XSLT_NAMESPACE)))
+#define IS_XSLT_ATTR_FAST(a) \
+ (((a) != NULL) && ((a)->ns != NULL) && \
+ (xmlStrEqual((a)->ns->href, XSLT_NAMESPACE)))
+
#endif /* XSLT_REFACTORED_XSLT_NSCOMP */
xmlNodePtr content; /* the template replacement value */
xmlNodePtr elem; /* the source element */
+ /*
+ * TODO: @inheritedNsNr and @inheritedNs won't be used in the
+ * refactored code.
+ */
int inheritedNsNr; /* number of inherited namespaces */
xmlNsPtr *inheritedNs;/* inherited non-excluded namespaces */
void *keys; /* key tables storage */
struct _xsltDocument *includes; /* subsidiary includes */
int preproc; /* pre-processing already done */
+ int nbKeysComputed;
+};
+
+/**
+ * xsltKeyDef:
+ *
+ * Representation of an xsl:key.
+ */
+typedef struct _xsltKeyDef xsltKeyDef;
+typedef xsltKeyDef *xsltKeyDefPtr;
+struct _xsltKeyDef {
+ struct _xsltKeyDef *next;
+ xmlNodePtr inst;
+ xmlChar *name;
+ xmlChar *nameURI;
+ xmlChar *match;
+ xmlChar *use;
+ xmlXPathCompExprPtr comp;
+ xmlXPathCompExprPtr usecomp;
+ xmlNsPtr *nsList; /* the namespaces in scope */
+ int nsNr; /* the number of namespaces in scope */
+};
+
+/**
+ * xsltKeyTable:
+ *
+ * Holds the computed keys for key definitions of the same QName.
+ * Is owned by an xsltDocument.
+ */
+typedef struct _xsltKeyTable xsltKeyTable;
+typedef xsltKeyTable *xsltKeyTablePtr;
+struct _xsltKeyTable {
+ struct _xsltKeyTable *next;
+ xmlChar *name;
+ xmlChar *nameURI;
+ xmlHashTablePtr keys;
};
/*
typedef struct _xsltEffectiveNs xsltEffectiveNs;
typedef xsltEffectiveNs *xsltEffectiveNsPtr;
struct _xsltEffectiveNs {
+ xsltEffectiveNsPtr nextInStore; /* storage next */
xsltEffectiveNsPtr next; /* next item in the list */
const xmlChar *prefix;
const xmlChar *nsName;
+ /*
+ * Indicates if eclared on the literal result element; dunno if really
+ * needed.
+ */
+ int holdByElem;
};
/*
* Namespace-aliasing was applied on the @effectiveNs.
*/
xsltEffectiveNsPtr effectiveNs;
+
};
#ifdef XSLT_REFACTORED
#define XSLT_ELEMENT_CATEGORY_XSLT 0
#define XSLT_ELEMENT_CATEGORY_EXTENSION 1
-#define XSLT_ELEMENT_CATEGORY_LR 2
+#define XSLT_ELEMENT_CATEGORY_LRE 2
/**
* xsltCompilerNodeInfo:
int isInclude;
int hasForwardsCompat; /* whether forwards-compatible mode was used
in a parsing episode */
- int maxNodeInfos; /* just for the interest */
+ int maxNodeInfos; /* TEMP TODO: just for the interest */
+ int maxLREs; /* TEMP TODO: just for the interest */
/*
* In order to keep the old behaviour, applying strict rules of
* the spec can be turned off. This has effect only on special
#endif
xsltStyleItemUknownPtr unknownItem;
int hasNsAliases; /* Indicator if there was an xsl:namespace-alias. */
- xsltNsAliasPtr nsAliases;
+ xsltNsAliasPtr nsAliases;
};
#else /* XSLT_REFACTORED */
* Global list of information for [xsl:]extension-element-prefixes.
*/
xsltPointerListPtr extElemNamespaces;
+ xsltEffectiveNsPtr effectiveNs;
#ifdef XSLT_REFACTORED_XSLT_NSCOMP
/*
* Namespace name map to get rid of string comparison of namespace names.
* all document text strings are internalized
*/
int internalized;
+ int nbKeys;
+ int hasTemplKeyPatterns;
};
/**
#endif
#endif /* XSLT_REFACTORED */
+/************************************************************************
+ * *
+ * Transformation-time functions for *internal* use only *
+ * *
+ ************************************************************************/
+XSLTPUBFUN int XSLTCALL
+ xsltInitCtxtKey (xsltTransformContextPtr ctxt,
+ xsltDocumentPtr doc,
+ xsltKeyDefPtr keyd);
+
#ifdef __cplusplus
}
#endif