[libxslt] Rework attribute set resolution
- From: Nick Wellnhofer <nwellnhof src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libxslt] Rework attribute set resolution
- Date: Tue, 21 Jun 2016 12:20:31 +0000 (UTC)
commit ca9edf237f9925de4af809f0d5a0ed7e55bb6c82
Author: Nick Wellnhofer <wellnhofer aevum de>
Date: Mon Apr 18 17:53:59 2016 +0200
Rework attribute set resolution
The old code
- merged the use-attribute-sets and xsl:attributes of xsl:attribute-sets
from imported stylesheets in a single step, resulting in precedence
errors like bug #704071.
- didn't handle namespaces of use-attribute-sets properly,
- detected recursion but would still recurse infinitely leading to a
stack overflow.
Introduce a new struct xsltAttrSet that contains separate linked lists
for xsl:attributes and QNames from use-attribute-sets. Resolve
use-attribute-sets first. Merge attribute sets afterwards.
Fixes bug #704071:
https://bugzilla.gnome.org/show_bug.cgi?id=704071
libxslt/attributes.c | 646 +++++++++++++++++++++++++++-----------------------
1 files changed, 355 insertions(+), 291 deletions(-)
---
diff --git a/libxslt/attributes.c b/libxslt/attributes.c
index 8440b10..c9b2900 100644
--- a/libxslt/attributes.c
+++ b/libxslt/attributes.c
@@ -55,14 +55,6 @@
#endif
/*
- * TODO: merge attribute sets from different import precedence.
- * all this should be precomputed just before the transformation
- * starts or at first hit with a cache in the context.
- * The simple way for now would be to not allow redefinition of
- * attributes once generated in the output tree, possibly costlier.
- */
-
-/*
* Useful macros
*/
#ifdef IS_BLANK
@@ -75,6 +67,10 @@
#define IS_BLANK_NODE(n) \
(((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
+#define ATTRSET_UNRESOLVED 0
+#define ATTRSET_RESOLVING 1
+#define ATTRSET_RESOLVED 2
+
/*
* The in-memory structure corresponding to an XSLT Attribute in
@@ -87,10 +83,36 @@ typedef xsltAttrElem *xsltAttrElemPtr;
struct _xsltAttrElem {
struct _xsltAttrElem *next;/* chained list */
xmlNodePtr attr; /* the xsl:attribute definition */
- const xmlChar *set; /* or the attribute set */
- const xmlChar *ns; /* and its namespace */
};
+typedef struct _xsltUseAttrSet xsltUseAttrSet;
+typedef xsltUseAttrSet *xsltUseAttrSetPtr;
+struct _xsltUseAttrSet {
+ struct _xsltUseAttrSet *next; /* chained list */
+ const xmlChar *ncname;
+ const xmlChar *ns;
+};
+
+typedef struct _xsltAttrSet xsltAttrSet;
+typedef xsltAttrSet *xsltAttrSetPtr;
+struct _xsltAttrSet {
+ int state;
+ xsltAttrElemPtr attrs; /* list head */
+ xsltUseAttrSetPtr useAttrSets; /* list head */
+};
+
+typedef struct _xsltAttrSetContext xsltAttrSetContext;
+typedef xsltAttrSetContext *xsltAttrSetContextPtr;
+struct _xsltAttrSetContext {
+ xsltStylesheetPtr topStyle;
+ xsltStylesheetPtr style;
+};
+
+static void
+xsltResolveAttrSet(xsltAttrSetPtr set, xsltStylesheetPtr topStyle,
+ xsltStylesheetPtr style, const xmlChar *name,
+ const xmlChar *ns, int depth);
+
/************************************************************************
* *
* XSLT Attribute handling *
@@ -148,11 +170,6 @@ xsltFreeAttrElemList(xsltAttrElemPtr list) {
}
}
-#ifdef XSLT_REFACTORED
- /*
- * This was moved to xsltParseStylesheetAttributeSet().
- */
-#else
/**
* xsltAddAttrElemList:
* @list: an XSLT AttrElem list
@@ -173,9 +190,7 @@ xsltAddAttrElemList(xsltAttrElemPtr list, xmlNodePtr attr) {
cur = list;
while (cur != NULL) {
next = cur->next;
- if (cur->attr == attr)
- return(cur);
- if (cur->next == NULL) {
+ if (next == NULL) {
cur->next = xsltNewAttrElem(attr);
return(list);
}
@@ -183,92 +198,169 @@ xsltAddAttrElemList(xsltAttrElemPtr list, xmlNodePtr attr) {
}
return(list);
}
-#endif /* XSLT_REFACTORED */
/**
- * xsltMergeAttrElemList:
- * @list: an XSLT AttrElem list
- * @old: another XSLT AttrElem list
+ * xsltNewUseAttrSet:
+ * @ncname: local name
+ * @ns: namespace URI
*
- * Add all the attributes from list @old to list @list,
- * but drop redefinition of existing values.
+ * Create a new XSLT UseAttrSet
*
- * Returns the new list pointer
+ * Returns the newly allocated xsltUseAttrSetPtr or NULL in case of error.
*/
-static xsltAttrElemPtr
-xsltMergeAttrElemList(xsltStylesheetPtr style,
- xsltAttrElemPtr list, xsltAttrElemPtr old) {
+static xsltUseAttrSetPtr
+xsltNewUseAttrSet(const xmlChar *ncname, const xmlChar *ns) {
+ xsltUseAttrSetPtr cur;
+
+ cur = (xsltUseAttrSetPtr) xmlMalloc(sizeof(xsltUseAttrSet));
+ if (cur == NULL) {
+ xsltGenericError(xsltGenericErrorContext,
+ "xsltNewUseAttrSet : malloc failed\n");
+ return(NULL);
+ }
+ memset(cur, 0, sizeof(xsltUseAttrSet));
+ cur->ncname = ncname;
+ cur->ns = ns;
+ return(cur);
+}
+
+/**
+ * xsltFreeUseAttrSet:
+ * @use: an XSLT UseAttrSet
+ *
+ * Free up the memory allocated by @use
+ */
+static void
+xsltFreeUseAttrSet(xsltUseAttrSetPtr use) {
+ xmlFree(use);
+}
+
+/**
+ * xsltFreeUseAttrSetList:
+ * @list: an XSLT UseAttrSet list
+ *
+ * Free up the memory allocated by @list
+ */
+static void
+xsltFreeUseAttrSetList(xsltUseAttrSetPtr list) {
+ xsltUseAttrSetPtr next;
+
+ while (list != NULL) {
+ next = list->next;
+ xsltFreeUseAttrSet(list);
+ list = next;
+ }
+}
+
+/**
+ * xsltAddUseAttrSetList:
+ * @list: a xsltUseAttrSet list
+ * @ncname: local name
+ * @ns: namespace URI
+ *
+ * Add the use-attribute-set name to the list.
+ *
+ * Returns the new list pointer.
+ */
+static xsltUseAttrSetPtr
+xsltAddUseAttrSetList(xsltUseAttrSetPtr list, const xmlChar *ncname,
+ const xmlChar *ns) {
+ xsltUseAttrSetPtr next, cur;
+
+ if (ncname == NULL)
+ return(list);
+ if (list == NULL)
+ return(xsltNewUseAttrSet(ncname, ns));
+ cur = list;
+ while (cur != NULL) {
+ if ((cur->ncname == ncname) && (cur->ns == ns))
+ return(list);
+ next = cur->next;
+ if (next == NULL) {
+ cur->next = xsltNewUseAttrSet(ncname, ns);
+ return(list);
+ }
+ cur = next;
+ }
+ return(list);
+}
+
+/**
+ * xsltNewAttrSet:
+ *
+ * Create a new attribute set.
+ *
+ * Returns the newly allocated xsltAttrSetPtr or NULL in case of error.
+ */
+static xsltAttrSetPtr
+xsltNewAttrSet() {
+ xsltAttrSetPtr cur;
+
+ cur = (xsltAttrSetPtr) xmlMalloc(sizeof(xsltAttrSet));
+ if (cur == NULL) {
+ xsltGenericError(xsltGenericErrorContext,
+ "xsltNewAttrSet : malloc failed\n");
+ return(NULL);
+ }
+ memset(cur, 0, sizeof(xsltAttrSet));
+ return(cur);
+}
+
+/**
+ * xsltFreeAttrSet:
+ * @set: an attribute set
+ *
+ * Free memory allocated by @set
+ */
+static void
+xsltFreeAttrSet(xsltAttrSetPtr set) {
+ if (set == NULL)
+ return;
+
+ xsltFreeAttrElemList(set->attrs);
+ xsltFreeUseAttrSetList(set->useAttrSets);
+ xmlFree(set);
+}
+
+/**
+ * xsltMergeAttrSets:
+ * @set: an attribute set
+ * @other: another attribute set
+ *
+ * Add all the attributes from @other to @set,
+ * but drop redefinition of existing values.
+ */
+static void
+xsltMergeAttrSets(xsltAttrSetPtr set, xsltAttrSetPtr other) {
xsltAttrElemPtr cur;
+ xsltAttrElemPtr old = other->attrs;
int add;
while (old != NULL) {
- if ((old->attr == NULL) && (old->set == NULL)) {
- old = old->next;
- continue;
- }
/*
* Check that the attribute is not yet in the list
*/
- cur = list;
+ cur = set->attrs;
add = 1;
while (cur != NULL) {
- if ((cur->attr == NULL) && (cur->set == NULL)) {
- if (cur->next == NULL)
- break;
- cur = cur->next;
- continue;
- }
- if ((cur->set != NULL) && (cur->set == old->set)) {
- add = 0;
- break;
- }
- if (cur->set != NULL) {
- if (cur->next == NULL)
- break;
- cur = cur->next;
- continue;
- }
- if (old->set != NULL) {
- if (cur->next == NULL)
- break;
- cur = cur->next;
- continue;
- }
- if (cur->attr == old->attr) {
- xsltGenericError(xsltGenericErrorContext,
- "xsl:attribute-set : use-attribute-sets recursion detected\n");
- return(list);
- }
+ /*
+ * TODO: Compare attrs by name.
+ */
if (cur->next == NULL)
break;
cur = cur->next;
}
if (add == 1) {
- /*
- * Changed to use the string-dict, rather than duplicating
- * @set and @ns; this fixes bug #340400.
- */
if (cur == NULL) {
- list = xsltNewAttrElem(old->attr);
- if (old->set != NULL) {
- list->set = xmlDictLookup(style->dict, old->set, -1);
- if (old->ns != NULL)
- list->ns = xmlDictLookup(style->dict, old->ns, -1);
- }
+ set->attrs = xsltNewAttrElem(old->attr);
} else if (add) {
cur->next = xsltNewAttrElem(old->attr);
- if (old->set != NULL) {
- cur->next->set = xmlDictLookup(style->dict, old->set, -1);
- if (old->ns != NULL)
- cur->next->ns = xmlDictLookup(style->dict, old->ns, -1);
- }
}
}
old = old->next;
}
- return(list);
}
/************************************************************************
@@ -289,9 +381,10 @@ void
xsltParseStylesheetAttributeSet(xsltStylesheetPtr style, xmlNodePtr cur) {
const xmlChar *ncname;
const xmlChar *prefix;
+ const xmlChar *nsUri = NULL;
xmlChar *value;
xmlNodePtr child;
- xsltAttrElemPtr attrItems;
+ xsltAttrSetPtr set;
if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
return;
@@ -308,6 +401,17 @@ xsltParseStylesheetAttributeSet(xsltStylesheetPtr style, xmlNodePtr cur) {
ncname = xsltSplitQName(style->dict, value, &prefix);
xmlFree(value);
value = NULL;
+ if (prefix != NULL) {
+ xmlNsPtr ns = xmlSearchNs(style->doc, cur, prefix);
+ if (ns == NULL) {
+ xsltTransformError(NULL, style, cur,
+ "xsl:attribute-set : No namespace found for QName '%s:%s'\n",
+ prefix, ncname);
+ style->errors++;
+ return;
+ }
+ nsUri = ns->href;
+ }
if (style->attributeSets == NULL) {
#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
@@ -319,7 +423,13 @@ xsltParseStylesheetAttributeSet(xsltStylesheetPtr style, xmlNodePtr cur) {
if (style->attributeSets == NULL)
return;
- attrItems = xmlHashLookup2(style->attributeSets, ncname, prefix);
+ set = xmlHashLookup2(style->attributeSets, ncname, nsUri);
+ if (set == NULL) {
+ set = xsltNewAttrSet();
+ if (set == NULL)
+ return;
+ xmlHashAddEntry2(style->attributeSets, ncname, nsUri, set);
+ }
/*
* Parse the content. Only xsl:attribute elements are allowed.
@@ -345,71 +455,20 @@ xsltParseStylesheetAttributeSet(xsltStylesheetPtr style, xmlNodePtr cur) {
"xsl:attribute-set : unexpected child xsl:%s\n",
child->name);
} else {
-#ifdef XSLT_REFACTORED
- xsltAttrElemPtr nextAttr, curAttr;
-
- /*
- * Process xsl:attribute
- * ---------------------
- */
-
#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
xsltGenericDebug(xsltGenericDebugContext,
"add attribute to list %s\n", ncname);
#endif
- /*
- * The following was taken over from
- * xsltAddAttrElemList().
- */
- if (attrItems == NULL) {
- attrItems = xsltNewAttrElem(child);
- } else {
- curAttr = attrItems;
- while (curAttr != NULL) {
- nextAttr = curAttr->next;
- if (curAttr->attr == child) {
- /*
- * URGENT TODO: Can somebody explain
- * why attrItems is set to curAttr
- * here? Is this somehow related to
- * avoidance of recursions?
- */
- attrItems = curAttr;
- goto next_child;
- }
- if (curAttr->next == NULL)
- curAttr->next = xsltNewAttrElem(child);
- curAttr = nextAttr;
- }
- }
- /*
- * Parse the xsl:attribute and its content.
- */
- xsltParseAnyXSLTElem(XSLT_CCTXT(style), child);
-#else
-#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
- xsltGenericDebug(xsltGenericDebugContext,
- "add attribute to list %s\n", ncname);
-#endif
- /*
- * OLD behaviour:
- */
- attrItems = xsltAddAttrElemList(attrItems, child);
-#endif
+ set->attrs = xsltAddAttrElemList(set->attrs, child);
}
-#ifdef XSLT_REFACTORED
-next_child:
-#endif
child = child->next;
}
/*
- * Process attribue "use-attribute-sets".
+ * Process attribute "use-attribute-sets".
*/
- /* TODO check recursion */
- value = xmlGetNsProp(cur, (const xmlChar *)"use-attribute-sets",
- NULL);
+ value = xmlGetNsProp(cur, BAD_CAST "use-attribute-sets", NULL);
if (value != NULL) {
const xmlChar *curval, *endval;
curval = value;
@@ -423,21 +482,28 @@ next_child:
if (curval) {
const xmlChar *ncname2 = NULL;
const xmlChar *prefix2 = NULL;
- xsltAttrElemPtr refAttrItems;
+ const xmlChar *nsUri2 = NULL;
#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
xsltGenericDebug(xsltGenericDebugContext,
"xsl:attribute-set : %s adds use %s\n", ncname, curval);
#endif
ncname2 = xsltSplitQName(style->dict, curval, &prefix2);
- refAttrItems = xsltNewAttrElem(NULL);
- if (refAttrItems != NULL) {
- refAttrItems->set = ncname2;
- refAttrItems->ns = prefix2;
- attrItems = xsltMergeAttrElemList(style,
- attrItems, refAttrItems);
- xsltFreeAttrElem(refAttrItems);
- }
+ if (prefix2 != NULL) {
+ xmlNsPtr ns2 = xmlSearchNs(style->doc, cur, prefix2);
+ if (ns2 == NULL) {
+ xsltTransformError(NULL, style, cur,
+ "xsl:attribute-set : No namespace found for QName "
+ "'%s:%s' in use-attribute-sets\n",
+ prefix2, ncname2);
+ style->errors++;
+ xmlFree(value);
+ return;
+ }
+ nsUri2 = ns2->href;
+ }
+ set->useAttrSets = xsltAddUseAttrSetList(set->useAttrSets,
+ ncname2, nsUri2);
}
curval = endval;
}
@@ -445,15 +511,6 @@ next_child:
value = NULL;
}
- /*
- * Update the value
- */
- /*
- * TODO: Why is this dummy entry needed.?
- */
- if (attrItems == NULL)
- attrItems = xsltNewAttrElem(NULL);
- xmlHashUpdateEntry2(style->attributeSets, ncname, prefix, attrItems, NULL);
#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
xsltGenericDebug(xsltGenericDebugContext,
"updated attribute list %s\n", ncname);
@@ -461,143 +518,141 @@ next_child:
}
/**
- * xsltGetSAS:
- * @style: the XSLT stylesheet
- * @name: the attribute list name
- * @ns: the attribute list namespace
+ * xsltResolveUseAttrSets:
+ * @set: the attribute set
+ * @asctx: the context for attribute set resolution
+ * @depth: recursion depth
*
- * lookup an attribute set based on the style cascade
- *
- * Returns the attribute set or NULL
+ * Process "use-attribute-sets".
*/
-static xsltAttrElemPtr
-xsltGetSAS(xsltStylesheetPtr style, const xmlChar *name, const xmlChar *ns) {
- xsltAttrElemPtr values;
-
- while (style != NULL) {
- values = xmlHashLookup2(style->attributeSets, name, ns);
- if (values != NULL)
- return(values);
- style = xsltNextImport(style);
+static void
+xsltResolveUseAttrSets(xsltAttrSetPtr set, xsltStylesheetPtr topStyle,
+ int depth) {
+ xsltStylesheetPtr cur;
+ xsltAttrSetPtr other;
+ xsltUseAttrSetPtr use = set->useAttrSets;
+ xsltUseAttrSetPtr next;
+
+ while (use != NULL) {
+ /*
+ * Iterate top stylesheet and all imports.
+ */
+ cur = topStyle;
+ while (cur != NULL) {
+ if (cur->attributeSets) {
+ other = xmlHashLookup2(cur->attributeSets, use->ncname,
+ use->ns);
+ if (other != NULL) {
+ xsltResolveAttrSet(other, topStyle, cur, use->ncname,
+ use->ns, depth + 1);
+ xsltMergeAttrSets(set, other);
+ break;
+ }
+ }
+ cur = xsltNextImport(cur);
+ }
+
+ next = use->next;
+ /* Free useAttrSets early. */
+ xsltFreeUseAttrSet(use);
+ use = next;
}
- return(NULL);
+
+ set->useAttrSets = NULL;
}
/**
- * xsltResolveSASCallbackInt:
- * @style: the XSLT stylesheet
+ * xsltResolveAttrSet:
+ * @set: the attribute set
+ * @asctx: the context for attribute set resolution
+ * @name: the local name of the attirbute set
+ * @ns: the namespace of the attribute set
+ * @depth: recursion depth
*
* resolve the references in an attribute set.
*/
static void
-xsltResolveSASCallbackInt(xsltAttrElemPtr values, xsltStylesheetPtr style,
- const xmlChar *name, const xmlChar *ns,
- int depth) {
- xsltAttrElemPtr tmp;
- xsltAttrElemPtr refs;
+xsltResolveAttrSet(xsltAttrSetPtr set, xsltStylesheetPtr topStyle,
+ xsltStylesheetPtr style, const xmlChar *name,
+ const xmlChar *ns, int depth) {
+ xsltStylesheetPtr cur;
+ xsltAttrSetPtr other;
- tmp = values;
- if ((name == NULL) || (name[0] == 0))
+ if (set->state == ATTRSET_RESOLVED)
+ return;
+ if (set->state == ATTRSET_RESOLVING) {
+ xsltTransformError(NULL, topStyle, NULL,
+ "xsl:attribute-set : use-attribute-sets recursion detected"
+ " on %s\n", name);
+ topStyle->errors++;
+ set->state = ATTRSET_RESOLVED;
return;
+ }
if (depth > 100) {
- xsltGenericError(xsltGenericErrorContext,
- "xsl:attribute-set : use-attribute-sets recursion detected on %s\n",
- name);
+ xsltTransformError(NULL, topStyle, NULL,
+ "xsl:attribute-set : use-attribute-sets maximum recursion "
+ "depth exceeded on %s\n", name);
+ topStyle->errors++;
return;
}
- while (tmp != NULL) {
- if (tmp->set != NULL) {
- /*
- * Check against cycles !
- */
- if ((xmlStrEqual(name, tmp->set)) && (xmlStrEqual(ns, tmp->ns))) {
- xsltGenericError(xsltGenericErrorContext,
- "xsl:attribute-set : use-attribute-sets recursion detected on %s\n",
- name);
- } else {
+
+ set->state = ATTRSET_RESOLVING;
+
+ xsltResolveUseAttrSets(set, topStyle, depth);
+
+ /* Merge imported sets. */
+ cur = xsltNextImport(style);
+ while (cur != NULL) {
+ if (cur->attributeSets != NULL) {
+ other = xmlHashLookup2(cur->attributeSets, name, ns);
+
+ if (other != NULL) {
#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
- xsltGenericDebug(xsltGenericDebugContext,
- "Importing attribute list %s\n", tmp->set);
+ xsltGenericDebug(xsltGenericDebugContext,
+ "xsl:attribute-set : merging import for %s\n", name);
#endif
+ xsltResolveUseAttrSets(other, topStyle, depth);
+ xsltMergeAttrSets(set, other);
+ xmlHashRemoveEntry2(cur->attributeSets, name, ns, NULL);
+ xsltFreeAttrSet(other);
+ }
+ }
- refs = xsltGetSAS(style, tmp->set, tmp->ns);
- if (refs == NULL) {
- xsltGenericError(xsltGenericErrorContext,
- "xsl:attribute-set : use-attribute-sets %s reference missing %s\n",
- name, tmp->set);
- } else {
- /*
- * recurse first for cleanup
- */
- xsltResolveSASCallbackInt(refs, style, name, ns, depth + 1);
- /*
- * Then merge
- */
- xsltMergeAttrElemList(style, values, refs);
- /*
- * Then suppress the reference
- */
- tmp->set = NULL;
- tmp->ns = NULL;
- }
- }
- }
- tmp = tmp->next;
+ cur = xsltNextImport(cur);
}
+
+ set->state = ATTRSET_RESOLVED;
}
/**
- * xsltResolveSASCallback,:
- * @style: the XSLT stylesheet
+ * xsltResolveSASCallback:
+ * @set: the attribute set
+ * @asctx: the context for attribute set resolution
+ * @name: the local name of the attirbute set
+ * @ns: the namespace of the attribute set
*
* resolve the references in an attribute set.
*/
static void
-xsltResolveSASCallback(xsltAttrElemPtr values, xsltStylesheetPtr style,
+xsltResolveSASCallback(xsltAttrSetPtr set, xsltAttrSetContextPtr asctx,
const xmlChar *name, const xmlChar *ns,
ATTRIBUTE_UNUSED const xmlChar *ignored) {
- xsltResolveSASCallbackInt(values, style, name, ns, 1);
-}
+ xsltStylesheetPtr topStyle = asctx->topStyle;
+ xsltStylesheetPtr style = asctx->style;
-/**
- * xsltMergeSASCallback,:
- * @style: the XSLT stylesheet
- *
- * Merge an attribute set from an imported stylesheet.
- */
-static void
-xsltMergeSASCallback(xsltAttrElemPtr values, xsltStylesheetPtr style,
- const xmlChar *name, const xmlChar *ns,
- ATTRIBUTE_UNUSED const xmlChar *ignored) {
- int ret;
- xsltAttrElemPtr topSet;
+ xsltResolveAttrSet(set, topStyle, style, name, ns, 1);
- ret = xmlHashAddEntry2(style->attributeSets, name, ns, values);
- if (ret < 0) {
- /*
- * Add failed, this attribute set can be removed.
- */
-#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
- xsltGenericDebug(xsltGenericDebugContext,
- "attribute set %s present already in top stylesheet"
- " - merging\n", name);
-#endif
- topSet = xmlHashLookup2(style->attributeSets, name, ns);
- if (topSet==NULL) {
+ /* Move attribute sets to top stylesheet. */
+ if (style != topStyle) {
+ /*
+ * This imported stylesheet won't be visited anymore. Don't bother
+ * removing the hash entry.
+ */
+ if (xmlHashAddEntry2(topStyle->attributeSets, name, ns, set) < 0) {
xsltGenericError(xsltGenericErrorContext,
- "xsl:attribute-set : logic error merging from imports for"
- " attribute-set %s\n", name);
- } else {
- topSet = xsltMergeAttrElemList(style, topSet, values);
- xmlHashUpdateEntry2(style->attributeSets, name, ns, topSet, NULL);
- }
- xsltFreeAttrElemList(values);
-#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
- } else {
- xsltGenericDebug(xsltGenericDebugContext,
- "attribute set %s moved to top stylesheet\n",
- name);
-#endif
+ "xsl:attribute-set : internal error, can't move imported "
+ " attribute set %s\n", name);
+ }
}
}
@@ -610,15 +665,14 @@ xsltMergeSASCallback(xsltAttrElemPtr values, xsltStylesheetPtr style,
void
xsltResolveStylesheetAttributeSet(xsltStylesheetPtr style) {
xsltStylesheetPtr cur;
+ xsltAttrSetContext asctx;
#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
xsltGenericDebug(xsltGenericDebugContext,
"Resolving attribute sets references\n");
#endif
- /*
- * First aggregate all the attribute sets definitions from the imports
- */
- cur = xsltNextImport(style);
+ asctx.topStyle = style;
+ cur = style;
while (cur != NULL) {
if (cur->attributeSets != NULL) {
if (style->attributeSets == NULL) {
@@ -628,25 +682,21 @@ xsltResolveStylesheetAttributeSet(xsltStylesheetPtr style) {
#endif
style->attributeSets = xmlHashCreate(10);
}
+ asctx.style = cur;
xmlHashScanFull(cur->attributeSets,
- (xmlHashScannerFull) xsltMergeSASCallback, style);
- /*
- * the attribute lists have either been migrated to style
- * or freed directly in xsltMergeSASCallback()
- */
- xmlHashFree(cur->attributeSets, NULL);
- cur->attributeSets = NULL;
+ (xmlHashScannerFull) xsltResolveSASCallback, &asctx);
+
+ if (cur != style) {
+ /*
+ * the attribute lists have either been migrated to style
+ * or freed directly in xsltResolveSASCallback()
+ */
+ xmlHashFree(cur->attributeSets, NULL);
+ cur->attributeSets = NULL;
+ }
}
cur = xsltNextImport(cur);
}
-
- /*
- * Then resolve all the references and computes the resulting sets
- */
- if (style->attributeSets != NULL) {
- xmlHashScanFull(style->attributeSets,
- (xmlHashScannerFull) xsltResolveSASCallback, style);
- }
}
/**
@@ -1066,7 +1116,7 @@ xsltApplyAttributeSet(xsltTransformContextPtr ctxt, xmlNodePtr node,
const xmlChar *ncname = NULL;
const xmlChar *prefix = NULL;
const xmlChar *curstr, *endstr;
- xsltAttrElemPtr attrs;
+ xsltAttrSetPtr set;
xsltStylesheetPtr style;
if (attrSets == NULL) {
@@ -1106,12 +1156,24 @@ xsltApplyAttributeSet(xsltTransformContextPtr ctxt, xmlNodePtr node,
/*
* TODO: Validate the QName.
*/
+ xmlNsPtr ns;
+ const xmlChar *nsUri = NULL;
-#ifdef WITH_XSLT_DEBUG_curstrUTES
+#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
xsltGenericDebug(xsltGenericDebugContext,
- "apply curstrute set %s\n", curstr);
+ "apply attribute set %s\n", curstr);
#endif
ncname = xsltSplitQName(ctxt->dict, curstr, &prefix);
+ if (prefix != NULL) {
+ ns = xmlSearchNs(inst->doc, inst, prefix);
+ if (ns == NULL) {
+ xsltTransformError(ctxt, NULL, inst,
+ "use-attribute-set : No namespace found for QName "
+ "'%s:%s'\n", prefix, ncname);
+ return;
+ }
+ nsUri = ns->href;
+ }
style = ctxt->style;
@@ -1120,25 +1182,27 @@ xsltApplyAttributeSet(xsltTransformContextPtr ctxt, xmlNodePtr node,
(style->attributeSets != NULL) &&
(ctxt->debugStatus != XSLT_DEBUG_NONE))
{
- attrs =
- xmlHashLookup2(style->attributeSets, ncname, prefix);
- if ((attrs != NULL) && (attrs->attr != NULL))
- xslHandleDebugger(attrs->attr->parent, node, NULL,
+ set = xmlHashLookup2(style->attributeSets, ncname, nsUri);
+ if ((set != NULL) && (set->attrs != NULL) &&
+ (set->attrs->attr != NULL))
+ xslHandleDebugger(set->attrs->attr->parent, node, NULL,
ctxt);
}
#endif
/*
- * Lookup the referenced curstrute-set.
+ * Lookup the referenced attribute-set.
*/
while (style != NULL) {
- attrs =
- xmlHashLookup2(style->attributeSets, ncname, prefix);
- while (attrs != NULL) {
- if (attrs->attr != NULL) {
- xsltAttributeInternal(ctxt, node, attrs->attr,
- attrs->attr->psvi, 1);
+ set = xmlHashLookup2(style->attributeSets, ncname, nsUri);
+ if (set != NULL) {
+ xsltAttrElemPtr cur = set->attrs;
+ while (cur != NULL) {
+ if (cur->attr != NULL) {
+ xsltAttributeInternal(ctxt, node, cur->attr,
+ cur->attr->psvi, 1);
+ }
+ cur = cur->next;
}
- attrs = attrs->next;
}
style = xsltNextImport(style);
}
@@ -1157,6 +1221,6 @@ void
xsltFreeAttributeSetsHashes(xsltStylesheetPtr style) {
if (style->attributeSets != NULL)
xmlHashFree((xmlHashTablePtr) style->attributeSets,
- (xmlHashDeallocator) xsltFreeAttrElemList);
+ (xmlHashDeallocator) xsltFreeAttrSet);
style->attributeSets = NULL;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]