From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Sun, 29 Oct 2017 01:04:54 +0200 Subject: [PATCH] Make generate-id deterministic Origin: upstream, https://bugzilla.gnome.org/attachment.cgi?id=306475 Bug: https://bugzilla.gnome.org/show_bug.cgi?id=751621 Bug-Debian: https://bugs.debian.org/823857 --- libxslt/functions.c | 91 ++++++++++++++++++++++++++++++++++++++++- libxslt/functions.h | 7 ++++ libxslt/transform.c | 8 ++++ libxslt/xsltInternals.h | 2 + 4 files changed, 107 insertions(+), 1 deletion(-) diff --git a/libxslt/functions.c b/libxslt/functions.c index ed2b002362dc..9c4408b325bd 100644 --- a/libxslt/functions.c +++ b/libxslt/functions.c @@ -662,6 +662,63 @@ xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) xmlXPathFreeObject(decimalObj); } +/** + * 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 @@ -713,7 +770,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) { snprintf((char *)str, sizeof(str), "idp%ld", val); } else { diff --git a/libxslt/functions.h b/libxslt/functions.h index 5455b7f47802..31163613f6e9 100644 --- a/libxslt/functions.h +++ b/libxslt/functions.h @@ -63,6 +63,13 @@ XSLTPUBFUN void XSLTCALL xsltFunctionAvailableFunction (xmlXPathParserContextPtr ctxt, 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 cb43bb47d997..bc1c6afcfdd8 100644 --- a/libxslt/transform.c +++ b/libxslt/transform.c @@ -705,6 +705,7 @@ xsltNewTransformContext(xsltStylesheetPtr style, xmlDocPtr doc) { cur->traceCode = (unsigned long*) &xsltDefaultTrace; cur->xinclude = xsltGetXIncludeDefault(); cur->keyInitLevel = 0; + cur->nextid = 0; return(cur); @@ -6037,6 +6038,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 14343d2751c8..9d3ff5fc0c06 100644 --- a/libxslt/xsltInternals.h +++ b/libxslt/xsltInternals.h @@ -1786,6 +1786,8 @@ struct _xsltTransformContext { int maxTemplateVars; unsigned long opLimit; unsigned long opCount; + + unsigned long nextid;/* for generating stable ids */ }; /**