| Index: third_party/libxslt/libxslt/attributes.c
|
| diff --git a/third_party/libxslt/libxslt/attributes.c b/third_party/libxslt/libxslt/attributes.c
|
| index 8440b1031592ab61ddbf2bda003a4e2428ae41fb..9165ab13781948ac3dadd066ccfd2a0343021dca 100644
|
| --- a/third_party/libxslt/libxslt/attributes.c
|
| +++ b/third_party/libxslt/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,174 @@ 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);
|
| - }
|
| + xsltStylePreCompPtr curComp = cur->attr->psvi;
|
| + xsltStylePreCompPtr oldComp = old->attr->psvi;
|
| +
|
| + if ((curComp->name == oldComp->name) &&
|
| + (curComp->ns == oldComp->ns)) {
|
| + add = 0;
|
| + break;
|
| + }
|
| 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 +386,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;
|
| @@ -305,9 +403,29 @@ xsltParseStylesheetAttributeSet(xsltStylesheetPtr style, xmlNodePtr cur) {
|
| return;
|
| }
|
|
|
| + if (xmlValidateQName(value, 0)) {
|
| + xsltTransformError(NULL, style, cur,
|
| + "xsl:attribute-set : The name '%s' is not a valid QName.\n",
|
| + value);
|
| + style->errors++;
|
| + xmlFree(value);
|
| + return;
|
| + }
|
| +
|
| ncname = xsltSplitQName(style->dict, value, &prefix);
|
| xmlFree(value);
|
| value = NULL;
|
| + if (prefix != NULL) {
|
| + xmlNsPtr ns = xmlSearchNs(style->doc, cur, prefix);
|
| + if (ns == NULL) {
|
| + xsltTransformError(NULL, style, cur,
|
| + "xsl:attribute-set : No namespace found for QName '%s:%s'\n",
|
| + prefix, ncname);
|
| + style->errors++;
|
| + return;
|
| + }
|
| + nsUri = ns->href;
|
| + }
|
|
|
| if (style->attributeSets == NULL) {
|
| #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
|
| @@ -319,7 +437,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 +469,36 @@ 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);
|
| + xsltStylePreCompute(style, child);
|
| + if (child->children != NULL) {
|
| +#ifdef XSLT_REFACTORED
|
| + xsltParseSequenceConstructor(XSLT_CCTXT(style),
|
| + child->children);
|
| #else
|
| -#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "add attribute to list %s\n", ncname);
|
| -#endif
|
| - /*
|
| - * OLD behaviour:
|
| - */
|
| - attrItems = xsltAddAttrElemList(attrItems, child);
|
| + xsltParseTemplateContent(style, child);
|
| #endif
|
| + }
|
| + if (child->psvi == NULL) {
|
| + xsltTransformError(NULL, style, child,
|
| + "xsl:attribute-set : internal error, attribute %s not "
|
| + "compiled\n", child->name);
|
| + }
|
| + else {
|
| + set->attrs = xsltAddAttrElemList(set->attrs, child);
|
| + }
|
| }
|
|
|
| -#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 +512,38 @@ 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
|
| +
|
| + if (xmlValidateQName(curval, 0)) {
|
| + xsltTransformError(NULL, style, cur,
|
| + "xsl:attribute-set : The name '%s' in "
|
| + "use-attribute-sets is not a valid QName.\n", curval);
|
| + style->errors++;
|
| + xmlFree(value);
|
| + return;
|
| + }
|
| +
|
| ncname2 = xsltSplitQName(style->dict, curval, &prefix2);
|
| - 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 +551,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 +558,141 @@ next_child:
|
| }
|
|
|
| /**
|
| - * xsltGetSAS:
|
| - * @style: the XSLT stylesheet
|
| - * @name: the attribute list name
|
| - * @ns: the attribute list namespace
|
| - *
|
| - * lookup an attribute set based on the style cascade
|
| + * xsltResolveUseAttrSets:
|
| + * @set: the attribute set
|
| + * @asctx: the context for attribute set resolution
|
| + * @depth: recursion depth
|
| *
|
| - * 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 +705,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,43 +722,37 @@ 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);
|
| - }
|
| }
|
|
|
| /**
|
| - * xsltAttributeInternal:
|
| + * xsltAttribute:
|
| * @ctxt: a XSLT process context
|
| * @node: the current node in the source tree
|
| * @inst: the xsl:attribute element
|
| * @comp: precomputed information
|
| - * @fromAttributeSet: the attribute comes from an attribute-set
|
| *
|
| * Process the xslt attribute node on the source node
|
| */
|
| -static void
|
| -xsltAttributeInternal(xsltTransformContextPtr ctxt,
|
| - xmlNodePtr contextNode,
|
| - xmlNodePtr inst,
|
| - xsltStylePreCompPtr castedComp,
|
| - int fromAttributeSet)
|
| +void
|
| +xsltAttribute(xsltTransformContextPtr ctxt,
|
| + xmlNodePtr contextNode,
|
| + xmlNodePtr inst,
|
| + xsltStylePreCompPtr castedComp)
|
| {
|
| #ifdef XSLT_REFACTORED
|
| xsltStyleItemAttributePtr comp =
|
| @@ -704,7 +792,7 @@ xsltAttributeInternal(xsltTransformContextPtr ctxt,
|
|
|
| if (comp == NULL) {
|
| xsltTransformError(ctxt, NULL, inst,
|
| - "Internal error in xsltAttributeInternal(): "
|
| + "Internal error in xsltAttribute(): "
|
| "The XSLT 'attribute' instruction was not compiled.\n");
|
| return;
|
| }
|
| @@ -869,19 +957,6 @@ xsltAttributeInternal(xsltTransformContextPtr ctxt,
|
| nsName = ns->href;
|
| }
|
|
|
| - if (fromAttributeSet) {
|
| - /*
|
| - * This tries to ensure that xsl:attribute(s) coming
|
| - * from an xsl:attribute-set won't override attribute of
|
| - * literal result elements or of explicit xsl:attribute(s).
|
| - * URGENT TODO: This might be buggy, since it will miss to
|
| - * overwrite two equal attributes both from attribute sets.
|
| - */
|
| - attr = xmlHasNsProp(targetElem, name, nsName);
|
| - if (attr != NULL)
|
| - return;
|
| - }
|
| -
|
| /*
|
| * Find/create a matching ns-decl in the result tree.
|
| */
|
| @@ -1032,21 +1107,6 @@ error:
|
| }
|
|
|
| /**
|
| - * xsltAttribute:
|
| - * @ctxt: a XSLT process context
|
| - * @node: the node in the source tree.
|
| - * @inst: the xslt attribute node
|
| - * @comp: precomputed information
|
| - *
|
| - * Process the xslt attribute node on the source node
|
| - */
|
| -void
|
| -xsltAttribute(xsltTransformContextPtr ctxt, xmlNodePtr node,
|
| - xmlNodePtr inst, xsltStylePreCompPtr comp) {
|
| - xsltAttributeInternal(ctxt, node, inst, comp, 0);
|
| -}
|
| -
|
| -/**
|
| * xsltApplyAttributeSet:
|
| * @ctxt: the XSLT stylesheet
|
| * @node: the node in the source tree.
|
| @@ -1066,7 +1126,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) {
|
| @@ -1103,15 +1163,32 @@ xsltApplyAttributeSet(xsltTransformContextPtr ctxt, xmlNodePtr node,
|
| endstr++;
|
| curstr = xmlDictLookup(ctxt->dict, curstr, endstr - curstr);
|
| if (curstr) {
|
| - /*
|
| - * 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
|
| +
|
| + if (xmlValidateQName(curstr, 0)) {
|
| + xsltTransformError(ctxt, NULL, inst,
|
| + "The name '%s' in use-attribute-sets is not a valid "
|
| + "QName.\n", curstr);
|
| + return;
|
| + }
|
| +
|
| ncname = xsltSplitQName(ctxt->dict, curstr, &prefix);
|
| + if (prefix != NULL) {
|
| + ns = xmlSearchNs(inst->doc, inst, prefix);
|
| + if (ns == NULL) {
|
| + xsltTransformError(ctxt, NULL, inst,
|
| + "use-attribute-set : No namespace found for QName "
|
| + "'%s:%s'\n", prefix, ncname);
|
| + return;
|
| + }
|
| + nsUri = ns->href;
|
| + }
|
|
|
| style = ctxt->style;
|
|
|
| @@ -1120,27 +1197,28 @@ 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. All attribute sets were
|
| + * moved to the top stylesheet so there's no need to iterate
|
| + * imported stylesheets
|
| */
|
| - 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) {
|
| + xsltAttribute(ctxt, node, cur->attr,
|
| + cur->attr->psvi);
|
| }
|
| - attrs = attrs->next;
|
| + cur = cur->next;
|
| }
|
| - style = xsltNextImport(style);
|
| }
|
| }
|
| curstr = endstr;
|
| @@ -1157,6 +1235,6 @@ void
|
| xsltFreeAttributeSetsHashes(xsltStylesheetPtr style) {
|
| if (style->attributeSets != NULL)
|
| xmlHashFree((xmlHashTablePtr) style->attributeSets,
|
| - (xmlHashDeallocator) xsltFreeAttrElemList);
|
| + (xmlHashDeallocator) xsltFreeAttrSet);
|
| style->attributeSets = NULL;
|
| }
|
|
|