This makes generated IDs deterministic. Written by Daniel Veillard. This should be fixed in next release (2.29). See https://bugzilla.gnome.org/show_bug.cgi?id=751621. diff --git a/libxslt/functions.c b/libxslt/functions.c index 6448bde..5b00a6d 100644 --- a/libxslt/functions.c +++ b/libxslt/functions.c @@ -651,6 +651,63 @@ xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) } /** + * xsltCleanupIds: + * @ctxt: the transformation context + * @root: the root of the resulting document + * + * This clean up ids which may have been saved in Element contents + * by xsltGenerateIdFunction() to provide stable IDs on elements. + * + * Returns the number of items cleaned or -1 in case of error + */ +int +xsltCleanupIds(xsltTransformContextPtr ctxt, xmlNodePtr root) { + xmlNodePtr cur; + int count = 0; + + if ((ctxt == NULL) || (root == NULL)) + return(-1); + if (root->type != XML_ELEMENT_NODE) + return(-1); + + cur = root; + while (cur != NULL) { + if (cur->type == XML_ELEMENT_NODE) { + if (cur->content != NULL) { + cur->content = NULL; + count++; + } + if (cur->children != NULL) { + cur = cur->children; + continue; + } + } + if (cur->next != NULL) { + cur = cur->next; + continue; + } + do { + cur = cur->parent; + if (cur == NULL) + break; + if (cur == (xmlNodePtr) root) { + cur = NULL; + break; + } + if (cur->next != NULL) { + cur = cur->next; + break; + } + } while (cur != NULL); + } + +fprintf(stderr, "Attributed %d IDs for element, cleaned up %d\n", + ctxt->nextid, count); + + return(count); +} + +/** * xsltGenerateIdFunction: * @ctxt: the XPath Parser context * @nargs: the number of arguments @@ -701,7 +758,39 @@ xsltGenerateIdFunction(xmlXPathParserContextPtr ctxt, int nargs){ if (obj) xmlXPathFreeObject(obj); - val = (long)((char *)cur - (char *)&base_address); + /* + * Try to provide stable ID for generated document: + * - usually ID are computed to be placed on elements via attributes + * so using the element as the node for the ID + * - the cur->content should be a correct placeholder for this, we use + * it to hold element node numbers in xmlXPathOrderDocElems to + * speed up XPath too + * - xsltCleanupIds() clean them up before handing the XSLT output + * to the API client. + * - other nodes types use the node address method but that should + * not end up in resulting document ID + * - we can enable this by default without risk of performance issues + * only the one pass xsltCleanupIds() is added + */ + if (cur->type == XML_ELEMENT_NODE) { + if (cur->content == NULL) { + xsltTransformContextPtr tctxt; + + tctxt = xsltXPathGetTransformContext(ctxt); + if (tctxt == NULL) { + val = (long)((char *)cur - (char *)&base_address); + } else { + tctxt->nextid++; + val = tctxt->nextid; + cur->content = (void *) (val); + } + } else { + val = (long) cur->content; + } + } else { + val = (long)((char *)cur - (char *)&base_address); + } + if (val >= 0) { sprintf((char *)str, "idp%ld", val); } else { diff --git a/libxslt/functions.h b/libxslt/functions.h index e0e0bf9..4a1e163 100644 --- a/libxslt/functions.h +++ b/libxslt/functions.h @@ -64,6 +64,13 @@ XSLTPUBFUN void XSLTCALL int nargs); /* + * Cleanup for ID generation + */ +XSLTPUBFUN int XSLTCALL + xsltCleanupIds (xsltTransformContextPtr ctxt, + xmlNodePtr root); + +/* * And the registration */ diff --git a/libxslt/transform.c b/libxslt/transform.c index 24f9eb2..2bdf6bf 100644 --- a/libxslt/transform.c +++ b/libxslt/transform.c @@ -700,6 +700,7 @@ xsltNewTransformContext(xsltStylesheetPtr style, xmlDocPtr doc) { cur->traceCode = (unsigned long*) &xsltDefaultTrace; cur->xinclude = xsltGetXIncludeDefault(); cur->keyInitLevel = 0; + cur->nextid = 0; return(cur); @@ -6092,6 +6093,13 @@ xsltApplyStylesheetInternal(xsltStylesheetPtr style, xmlDocPtr doc, if (root != NULL) { const xmlChar *doctype = NULL; + /* + * cleanup ids which may have been saved in Elements content ptrs + */ + if (ctxt->nextid != 0) { + xsltCleanupIds(ctxt, root); + } + if ((root->ns != NULL) && (root->ns->prefix != NULL)) doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name); if (doctype == NULL) diff --git a/libxslt/xsltInternals.h b/libxslt/xsltInternals.h index 95e8fe6..8eedae4 100644 --- a/libxslt/xsltInternals.h +++ b/libxslt/xsltInternals.h @@ -1782,6 +1782,8 @@ struct _xsltTransformContext { int maxTemplateVars; unsigned long opLimit; unsigned long opCount; + + unsigned long nextid;/* for generating stable ids */ }; /** href='/guix/commit/scripts?id=dadee6cd6e775741d85e8b968e7f1ce3123385a4'>Run 'guix' with '--no-auto-compile'....