diff options
-rw-r--r-- | ChangeLog | 12 | ||||
-rw-r--r-- | FEATURES | 20 | ||||
-rw-r--r-- | INSTALL | 2 | ||||
-rw-r--r-- | README | 10 | ||||
-rw-r--r-- | TODO | 26 | ||||
-rw-r--r-- | libxslt/functions.c | 239 | ||||
-rw-r--r-- | libxslt/transform.c | 23 | ||||
-rw-r--r-- | libxslt/variables.h | 3 | ||||
-rw-r--r-- | libxslt/xslt.c | 5 | ||||
-rw-r--r-- | libxslt/xslt.h | 2 | ||||
-rw-r--r-- | libxslt/xsltInternals.h | 1 | ||||
-rw-r--r-- | libxslt/xsltutils.c | 5 |
12 files changed, 299 insertions, 49 deletions
@@ -1,3 +1,15 @@ +Thu Jan 25 19:36:45 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr> + + * FEATURES TODO README INSTALL: updated + * libxslt/xslt.h: added URL and version/vendor :-) + * libxslt/transform.c: fixed a problem in xsl:attribute, removed + attempt to support older libxml2 version. + * libxslt/variables.h libxslt/xsltInternals.h: update to structures + and macros to add/register new document created by document() + * libxslt/functions.c: implemented current(), unparsed-entity-uri() + system-property(), element-available() and function-available(). + A crippled version of document() has been added too. + Thu Jan 25 12:13:04 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr> * functions.[ch]: Bjorn Reese <breese@mail1.stofanet.dk> provided @@ -186,7 +186,9 @@ General: ======== YES (w.o import) Conflict Resolution for Template Rules + YES Whitespace Stripping + YES Built-in Template Rules YES match="*|/" YES match="text()|@*" @@ -194,6 +196,10 @@ YES match="processing-instruction()|comment()" NO Namespace NO Mode +NO Extension Elements + +NO Extension Functions + YES Attribute Value Templates YES Result Tree Fragments @@ -201,14 +207,14 @@ YES Result Tree Fragments Functions: ========== -NO node-set document(object, node-set?) +PARTIAL node-set document(object, node-set?) NO node-set key(string, object) YES string format-number(number, string, string?) -NO node-set current() -NO string unparsed-entity-uri(string) -NO string generate-id(node-set?) -NO object system-property(string) -NO boolean element-available(string) -NO boolean function-available(string) +YES node-set current() +YES string unparsed-entity-uri(string) +YES string generate-id(node-set?) +YES object system-property(string) +YES boolean element-available(string) +YES boolean function-available(string) Daniel.Veillard@imag.fr @@ -3,7 +3,7 @@ Requirements: ============= -this library requires libxml2 which you can grab from +this library requires libxml2 >= 2.2.12 which you can grab from either the GNOME FTP or the xmlsoft.org server: ftp://xmlsoft.org/ @@ -1,10 +1,14 @@ - XSLT support for libxml + XSLT support for libxml2 http://xmlsoft.org/ - Requires libxml2 with XPath support. -Currently unusable, very early steps ... + Requires libxml2 >= 2.2.12 with XPath support. It won't even compile +otherwise. + Check the FEATURES file for informations about completeness + Check the Changelog too to keep track of progresses. + + report bugs to xml@rpmfind.net or on the bugzilla.gnome.org base. Daniel Veillard @@ -3,6 +3,13 @@ * TODO * * * ******** + +Doc: + - put a page at http://xmlsoft.org/XSLT/ + - generate/transform the DocBook to HTML + - add HTML to package + - manpage and doc for xsltproc + Design: - should transforms for a given stylesheet be thread clean, or can a stylesheet be enriched with document specific @@ -15,10 +22,10 @@ Import: -> provide functions to circulate in the import tree of stylesheets Extra functions: - -> make a separate module. -> document() should not be a problem since Result Tree Fragments are implemnted - -> others + => started, incomplete + -> missing key support ID and Key support: -> Id should be simple, key will probably requires some hash tables. @@ -36,10 +43,7 @@ Error handling: and lack of optionnal features. Support Attribute value templates: - -> starts to be urgent. Design it in flexible ways but try to optimize - to handle most of it at the stylesheet parse time ... - => Done for the most part need to check all attributes in XSLT constructs - using them and use the dedicated readin function. + -> optimization by checking their existence at stylesheet parse time. Sorting: -> add support for imbricated sorts @@ -59,6 +63,16 @@ Contextual error reporting: * * ******** +Extra functions: + -> make a separate module. + => done functions.[ch] + +Support Attribute value templates: + -> starts to be urgent. Design it in flexible ways but try to optimize + to handle most of it at the stylesheet parse time ... + => Done for the most part need to check all attributes in XSLT constructs + using them and use the dedicated readin function. + Separate util module: -> macros, config, verbosity ? => xsltutils.[ch] diff --git a/libxslt/functions.c b/libxslt/functions.c index ca041c2b..67556c6b 100644 --- a/libxslt/functions.c +++ b/libxslt/functions.c @@ -42,6 +42,7 @@ #include <libxml/xpath.h> #include <libxml/xpathInternals.h> #include <libxml/parserInternals.h> +#include <libxml/uri.h> #include "xslt.h" #include "xsltInternals.h" #include "xsltutils.h" @@ -110,7 +111,80 @@ isinf(double number) */ void xsltDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs){ - TODO /* function */ + xmlDocPtr doc; + xmlXPathObjectPtr obj; + xmlChar *base, *URI; + + + if ((nargs < 1) || (nargs > 2)) { + xsltGenericError(xsltGenericErrorContext, + "document() : invalid number of args %d\n", nargs); + ctxt->error = XPATH_INVALID_ARITY; + return; + } + if (ctxt->value == NULL) { + xsltGenericError(xsltGenericErrorContext, + "document() : invalid arg value\n"); + ctxt->error = XPATH_INVALID_TYPE; + return; + } + if (ctxt->value->type == XPATH_NODESET) { + TODO + xsltGenericError(xsltGenericErrorContext, + "document() : with node-sets args not yet supported\n"); + return; + } + /* + * Make sure it's converted to a string + */ + xmlXPathStringFunction(ctxt, 1); + if (ctxt->value->type != XPATH_STRING) { + xsltGenericError(xsltGenericErrorContext, + "document() : invalid arg expecting a string\n"); + ctxt->error = XPATH_INVALID_TYPE; + return; + } + obj = valuePop(ctxt); + if (obj->stringval == NULL) { + valuePush(ctxt, xmlXPathNewNodeSet(NULL)); + } else { + base = xmlNodeGetBase(ctxt->context->doc, ctxt->context->node); + URI = xmlBuildURI(obj->stringval, base); + if (base != NULL) + xmlFree(base); + if (URI == NULL) { + valuePush(ctxt, xmlXPathNewNodeSet(NULL)); + } else { + doc = xmlParseDoc(URI); + if (doc == NULL) + valuePush(ctxt, xmlXPathNewNodeSet(NULL)); + else { + xsltTransformContextPtr tctxt; + + /* + * link it to the context for cleanup when done + */ + tctxt = (xsltTransformContextPtr) ctxt->context->extra; + if (tctxt == NULL) { + xsltGenericError(xsltGenericErrorContext, + "document() : internal error tctxt == NULL\n"); + xmlFreeDoc(doc); + valuePush(ctxt, xmlXPathNewNodeSet(NULL)); + } else { + /* + * Keep a link from the context to be able to deallocate + */ + doc->next = (xmlNodePtr) tctxt->extraDocs; + tctxt->extraDocs = doc; + + /* TODO: use XPointer of HTML location for fragment ID */ + /* pbm #xxx can lead to location sets, not nodesets :-) */ + valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr) doc)); + } + } + } + } + xmlXPathFreeObject(obj); } /** @@ -136,7 +210,40 @@ xsltKeyFunction(xmlXPathParserContextPtr ctxt, int nargs){ */ void xsltUnparsedEntityURIFunction(xmlXPathParserContextPtr ctxt, int nargs){ - TODO /* function */ + xmlXPathObjectPtr obj; + xmlChar *str; + + if (nargs != 1) { + xsltGenericError(xsltGenericErrorContext, + "system-property() : expects one string arg\n"); + ctxt->error = XPATH_INVALID_ARITY; + return; + } + if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) { + xsltGenericError(xsltGenericErrorContext, + "generate-id() : invalid arg expecting a string\n"); + ctxt->error = XPATH_INVALID_TYPE; + return; + } + obj = valuePop(ctxt); + str = obj->stringval; + if (str == NULL) { + valuePush(ctxt, xmlXPathNewString((const xmlChar *)"")); + } else { + xmlEntityPtr entity; + + entity = xmlGetDocEntity(ctxt->context->doc, str); + if (entity == NULL) { + valuePush(ctxt, xmlXPathNewString((const xmlChar *)"")); + } else { + if (entity->URI != NULL) + valuePush(ctxt, xmlXPathNewString(entity->URI)); + else + valuePush(ctxt, xmlXPathNewString( + xmlStrdup((const xmlChar *)""))); + } + } + xmlXPathFreeObject(obj); } /** @@ -376,6 +483,7 @@ xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) break; default: XP_ERROR(XPATH_INVALID_ARITY); + return; } valuePush(ctxt, @@ -398,7 +506,54 @@ xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) */ void xsltGenerateIdFunction(xmlXPathParserContextPtr ctxt, int nargs){ - TODO /* function */ + xmlNodePtr cur = NULL; + unsigned int val; + xmlChar str[20]; + + if (nargs == 0) { + cur = ctxt->context->node; + } else if (nargs == 1) { + xmlXPathObjectPtr obj; + xmlNodeSetPtr nodelist; + int i, ret; + + if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) { + ctxt->error = XPATH_INVALID_TYPE; + xsltGenericError(xsltGenericErrorContext, + "generate-id() : invalid arg expecting a node-set\n"); + return; + } + obj = valuePop(ctxt); + nodelist = obj->nodesetval; + if ((nodelist == NULL) || (nodelist->nodeNr <= 0)) { + ctxt->error = XPATH_INVALID_TYPE; + xsltGenericError(xsltGenericErrorContext, + "generate-id() : got an empty node-set\n"); + xmlXPathFreeObject(obj); + return; + } + cur = nodelist->nodeTab[0]; + for (i = 2;i <= nodelist->nodeNr;i++) { + ret = xmlXPathCmpNodes(cur, nodelist->nodeTab[i]); + if (ret == -1) + cur = nodelist->nodeTab[i]; + } + xmlXPathFreeObject(obj); + } else { + xsltGenericError(xsltGenericErrorContext, + "generate-id() : invalid number of args %d\n", nargs); + ctxt->error = XPATH_INVALID_ARITY; + return; + } + /* + * Okay this is ugly but should work, use the NodePtr address + * to forge the ID + */ + val = (unsigned int) cur; + val >>= 2; + val |= 0xFFFFFF; + sprintf((char *)str, "id%10d", val); + valuePush(ctxt, xmlXPathNewString(str)); } /** @@ -411,7 +566,39 @@ xsltGenerateIdFunction(xmlXPathParserContextPtr ctxt, int nargs){ */ void xsltSystemPropertyFunction(xmlXPathParserContextPtr ctxt, int nargs){ - TODO /* function */ + xmlXPathObjectPtr obj; + xmlChar *str; + + if (nargs != 1) { + xsltGenericError(xsltGenericErrorContext, + "system-property() : expects one string arg\n"); + ctxt->error = XPATH_INVALID_ARITY; + return; + } + if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) { + xsltGenericError(xsltGenericErrorContext, + "generate-id() : invalid arg expecting a string\n"); + ctxt->error = XPATH_INVALID_TYPE; + return; + } + obj = valuePop(ctxt); + str = obj->stringval; + if (str == NULL) { + valuePush(ctxt, xmlXPathNewString((const xmlChar *)"")); + } else if (!xmlStrcmp(str, (const xmlChar *)"xsl:version")) { + valuePush(ctxt, xmlXPathNewString( + (const xmlChar *)XSLT_DEFAULT_VERSION)); + } else if (!xmlStrcmp(str, (const xmlChar *)"xsl:vendor")) { + valuePush(ctxt, xmlXPathNewString( + (const xmlChar *)XSLT_DEFAULT_VENDOR)); + } else if (!xmlStrcmp(str, (const xmlChar *)"xsl:vendor-url")) { + valuePush(ctxt, xmlXPathNewString( + (const xmlChar *)XSLT_DEFAULT_URL)); + } else { + /* TODO cheated with the QName resolution */ + valuePush(ctxt, xmlXPathNewString((const xmlChar *)"")); + } + xmlXPathFreeObject(obj); } /** @@ -424,7 +611,23 @@ xsltSystemPropertyFunction(xmlXPathParserContextPtr ctxt, int nargs){ */ void xsltElementAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){ - TODO /* function */ + xmlXPathObjectPtr obj; + + if (nargs != 1) { + xsltGenericError(xsltGenericErrorContext, + "element-available() : expects one string arg\n"); + ctxt->error = XPATH_INVALID_ARITY; + return; + } + if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) { + xsltGenericError(xsltGenericErrorContext, + "element-available invalid arg expecting a string\n"); + ctxt->error = XPATH_INVALID_TYPE; + return; + } + obj = valuePop(ctxt); + xmlXPathFreeObject(obj); + valuePush(ctxt, xmlXPathNewBoolean(0)); } /** @@ -437,7 +640,23 @@ xsltElementAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){ */ void xsltFunctionAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){ - TODO /* function */ + xmlXPathObjectPtr obj; + + if (nargs != 1) { + xsltGenericError(xsltGenericErrorContext, + "function-available() : expects one string arg\n"); + ctxt->error = XPATH_INVALID_ARITY; + return; + } + if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) { + xsltGenericError(xsltGenericErrorContext, + "function-available invalid arg expecting a string\n"); + ctxt->error = XPATH_INVALID_TYPE; + return; + } + obj = valuePop(ctxt); + xmlXPathFreeObject(obj); + valuePush(ctxt, xmlXPathNewBoolean(0)); } /** @@ -450,7 +669,13 @@ xsltFunctionAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){ */ void xsltCurrentFunction(xmlXPathParserContextPtr ctxt, int nargs){ - TODO /* function */ + if (nargs != 0) { + xsltGenericError(xsltGenericErrorContext, + "document() : function uses no argument\n"); + ctxt->error = XPATH_INVALID_ARITY; + return; + } + valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node)); } /** diff --git a/libxslt/transform.c b/libxslt/transform.c index 8a42a990..81eb3c96 100644 --- a/libxslt/transform.c +++ b/libxslt/transform.c @@ -77,8 +77,16 @@ xsltNewTransformContext(void) { */ void xsltFreeTransformContext(xsltTransformContextPtr ctxt) { + xmlDocPtr doc, next; + if (ctxt == NULL) return; + doc = ctxt->extraDocs; + while (doc != NULL) { + next = (xmlDocPtr) doc->next; + xmlFreeDoc(doc); + doc = next; + } if (ctxt->xpathCtxt != NULL) xmlXPathFreeContext(ctxt->xpathCtxt); xsltFreeVariableHashes(ctxt); @@ -373,29 +381,16 @@ xsltAttribute(xsltTransformContextPtr ctxt, xmlNodePtr node, } } - value = xmlNodeListGetString(inst->doc, inst->children, 1); + value = xsltEvalTemplateString(ctxt, node, inst); if (value == NULL) { if (ns) { -#if LIBXML_VERSION > 20211 attr = xmlSetNsProp(ctxt->insert, ns, ncname, (const xmlChar *)""); -#else - xsltGenericError(xsltGenericErrorContext, - "xsl:attribute: recompile against newer libxml version\n"); - attr = xmlSetProp(ctxt->insert, ncname, (const xmlChar *)""); -#endif } else attr = xmlSetProp(ctxt->insert, ncname, (const xmlChar *)""); } else { - /* TODO: attribute value template */ if (ns) { -#if LIBXML_VERSION > 20211 attr = xmlSetNsProp(ctxt->insert, ns, ncname, value); -#else - xsltGenericError(xsltGenericErrorContext, - "xsl:attribute: recompile against newer libxml version\n"); - attr = xmlSetProp(ctxt->insert, ncname, value); -#endif } else attr = xmlSetProp(ctxt->insert, ncname, value); diff --git a/libxslt/variables.h b/libxslt/variables.h index cf4b3834..bc3e450c 100644 --- a/libxslt/variables.h +++ b/libxslt/variables.h @@ -21,7 +21,8 @@ extern "C" { #define XSLT_REGISTER_VARIABLE_LOOKUP(ctxt) \ xmlXPathRegisterVariableLookup((ctxt)->xpathCtxt, \ xsltXPathVariableLookup, (void *)(ctxt)); \ - xsltRegisterAllFunctions((ctxt)->xpathCtxt) + xsltRegisterAllFunctions((ctxt)->xpathCtxt); \ + (ctxt)->xpathCtxt->extra = ctxt /* * Interfaces for the variable module. diff --git a/libxslt/xslt.c b/libxslt/xslt.c index 7f051efd..4d4898c9 100644 --- a/libxslt/xslt.c +++ b/libxslt/xslt.c @@ -493,12 +493,7 @@ xsltParseTemplateContent(xsltStylesheetPtr style, xsltTemplatePtr ret, XSLT_NAMESPACE); if (prop != NULL) { if (xmlStrEqual(prop, (const xmlChar *)"yes")) { -#if LIBXML_VERSION > 20211 text->name = xmlStringTextNoenc; -#else - xsltGenericError(xsltGenericErrorContext, -"xsl:text disable-output-escaping need newer > 20211 libxml version\n"); -#endif } else if (!xmlStrEqual(prop, (const xmlChar *)"no")){ xsltGenericError(xsltGenericErrorContext, diff --git a/libxslt/xslt.h b/libxslt/xslt.h index 02d35243..2c658367 100644 --- a/libxslt/xslt.h +++ b/libxslt/xslt.h @@ -19,6 +19,8 @@ extern "C" { * Constants. */ #define XSLT_DEFAULT_VERSION "1.0" +#define XSLT_DEFAULT_VENDOR "libxslt" +#define XSLT_DEFAULT_URL "http://xmlsoft.org/XSLT/" #define XSLT_NAMESPACE ((xmlChar *) "http://www.w3.org/1999/XSL/Transform") #ifdef __cplusplus diff --git a/libxslt/xsltInternals.h b/libxslt/xsltInternals.h index da00c133..7a645851 100644 --- a/libxslt/xsltInternals.h +++ b/libxslt/xsltInternals.h @@ -142,6 +142,7 @@ struct _xsltTransformContext { xmlXPathContextPtr xpathCtxt; /* the XPath context */ void *variablesHash; /* hash table or wherever variables informations are stored */ + xmlDocPtr extraDocs; /* extra docs parsed by document() */ }; /* diff --git a/libxslt/xsltutils.c b/libxslt/xsltutils.c index 1858d6e5..ba2457a1 100644 --- a/libxslt/xsltutils.c +++ b/libxslt/xsltutils.c @@ -222,12 +222,7 @@ xsltSaveResultTo(xmlOutputBufferPtr buf, xmlDocPtr result, (xmlStrEqual(style->method, (const xmlChar *) "html"))) || ((root != NULL) && (xmlStrEqual(root->name, (const xmlChar *) "html")))){ -#if LIBXML_VERSION > 20211 htmlDocContentDumpOutput(buf, result, (const char *) encoding); -#else - xsltGenericError(xsltGenericErrorContext, - "HTML output requires libxml version > 2.2.11\n"); -#endif } else if ((style->method != NULL) && (xmlStrEqual(style->method, (const xmlChar *) "text"))) { xmlNodePtr cur; |