GNOME Bugzilla – Bug 549552
document('') not working as expected, when loading xsl from memory
Last modified: 2008-08-27 14:32:09 UTC
Please describe the problem: (libxslt-1.1.24) Using the document()-function with an empty document-URI as first parameter (i.e. document('')) works perfectly, if the stylesheet is loaded from a file (e.g. with xsltproc on the command line). Calling document('') does not return the expected result, if we load the stylesheet from memory (reproducible with the included test program). The difference is: if we load the stylesheet from memory, the document-URI is empty. But if I understand the spec correctly (http://www.w3.org/TR/xslt#document, 12.1), the empty parameter from the document-function is a special feature, which should work, even if the stylesheet's document-URI is empty: "[...]; thus document("") refers to the root node of the stylesheet; the tree representation of the stylesheet is exactly the same as if the XML document containing the stylesheet was the initial source document." Steps to reproduce: #include <string.h> #include "libxslt/libxslt.h" #include "libxslt/xslt.h" #include "libxslt/xsltInternals.h" int main(int argc, char ** argv) { xmlDocPtr xsldoc = NULL; xmlDocPtr xmldoc = NULL; xsltStylesheetPtr sheetp = NULL; xsltStylesheetPtr resdoc = NULL; int size = 0; xmlChar * buf = NULL; char * s1; char * s2; s1 = strdup("<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"> \ \ <xsl:template match=\"/\"> \ <v><xsl:copy-of select=\"document('')/*[1]/@version\"/></v> \ </xsl:template> \ \ </xsl:stylesheet> \ "); s2 = strdup("<a/>"); xsldoc = xmlParseMemory(s1, strlen(BAD_CAST s1)); sheetp = xsltParseStylesheetDoc(xsldoc); xmldoc = xmlParseMemory(s2, strlen(BAD_CAST s2)); resdoc = xsltApplyStylesheet(sheetp, xmldoc, NULL); xmlDocDumpMemory(resdoc, &buf, &size); printf(buf); } Actual results: The test program outputs: <?xml version="1.0"?> <v/> Expected results: processing exactly the same stylesheet on the command line with xsltproc outputs the expected result: ~/tmp/1)> xsltproc a.xsl a.xml <?xml version="1.0"?> <v>1.0</v> Does this happen every time? Yes Other information:
In a nutshell impossible to fix by libxslt itself. Once the XML is parsed from memeory, we don't keep the memory string around. The XSLT just get the xsldoc pointer to the parsed tree, never the original XML input. Since there is no URI to refetch it we just can't magically regenerate the information. Don't parse from memory if you don't absolutely have to. Also note that sometime the parser never get a full string of the XML when parsing it, for example when building from a push parser context. What you are asking for is impossible purely from libxml2/libxslt with the code as shown. You can still try to add support by yourself, by keeping the XmL content around, add a unique URI when parsing the XML from memory (using xmlReadMemory not the ancient xmlParseMemory) and setting up a private entity loader (libxml2 doc/examples/io1.c) which then provide the requested content when asked for it by libxslt. I don't think it's a libxml2/libxslt bug as you asked libxslt to generate informations it never ever got. Daniel
Then I wonder why it works when I set the stylesheet's document-URI to a non-existent file right after parsing the xsl: xsldoc->URL = strdup("file:///tmp/bogus/mogus"); This is actually our workaround for this problem. The problem with this workaround is, that we get an I/O warning. Here's the full test program with the workaround: #include <string.h> #include "libxslt/libxslt.h" #include "libxslt/xslt.h" #include "libxslt/xsltInternals.h" int main(int argc, char ** argv) { xmlDocPtr xsldoc = NULL; xmlDocPtr xmldoc = NULL; xsltStylesheetPtr sheetp = NULL; xsltStylesheetPtr resdoc = NULL; int size = 0; xmlChar * buf = NULL; char * s1; char * s2; char * uri; s1 = strdup("<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"> \ \ <xsl:template match=\"/\"> \ <v><xsl:value-of select=\"document('')/*[1]/@version\"/></v> \ </xsl:template> \ \ </xsl:stylesheet> \ "); s2 = strdup("<a/>"); xsldoc = xmlParseMemory(s1, strlen(BAD_CAST s1)); xsldoc->URL = strdup("file:///tmp/bogus/mogus"); sheetp = xsltParseStylesheetDoc(xsldoc); xmldoc = xmlParseMemory(s2, strlen(BAD_CAST s2)); resdoc = xsltApplyStylesheet(sheetp, xmldoc, NULL); xmlDocDumpMemory(resdoc, &buf, &size); printf(buf); } Output: ~/tmp/libxslt-1.1.24)> ./a.out I/O warning : failed to load external entity "file:///tmp/bogus/mogus" <?xml version="1.0"?> <v>1.0</v>