* gnu/packages/patches/libxslt-generated-ids.patch: New file. * gnu/packages/patches/libxslt-remove-date-timestamps.patch: Likewise. * gnu/packages/xml.scm (libxslt)[source]: Use them. * gnu/local.mk (dist_patch_DATA): Add them.
		
			
				
	
	
		
			173 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			173 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
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
 | 
						|
@@ -1786,6 +1786,8 @@ struct _xsltTransformContext {
 | 
						|
     int funcLevel;      /* Needed to catch recursive functions issues */
 | 
						|
     int maxTemplateDepth;
 | 
						|
     int maxTemplateVars;
 | 
						|
+
 | 
						|
+    unsigned long nextid;/* for generating stable ids */
 | 
						|
 };
 | 
						|
 
 | 
						|
 /**
 |