From: Daniel Veillard Date: Mon, 15 Jan 2001 14:34:02 +0000 (+0000) Subject: Hack, debug, read, hack, debug, read .... X-Git-Tag: v1.1.28~1535 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d783a443286649ef8451c2bcb25fef5467803060;p=platform%2Fupstream%2Flibxslt.git Hack, debug, read, hack, debug, read .... - transform.c, xslt.c, xsltproc.c: lots of fixes, added support of xslt:if and xslt:attribute, need libxml2 interfaces present only in CVS. Daniel --- diff --git a/ChangeLog b/ChangeLog index 4678f82..ccf0e54 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Mon Jan 15 15:31:41 CET 2001 Daniel Veillard + + * transform.c, xslt.c, xsltproc.c: lots of fixes, added + support of xslt:if and xslt:attribute, need libxml2 interfaces + present only in CVS. + Sat Jan 13 23:26:21 CET 2001 Daniel Veillard * test/Makefile.am test/REC*/Makefile.am: added first test diff --git a/libxslt/transform.c b/libxslt/transform.c index 8d2d337..8af973e 100644 --- a/libxslt/transform.c +++ b/libxslt/transform.c @@ -29,7 +29,7 @@ #include "pattern.h" #include "transform.h" -/* #define DEBUG_PROCESS */ +#define DEBUG_PROCESS /* * To cleanup @@ -143,6 +143,92 @@ xsltFreeTransformContext(xsltTransformContextPtr ctxt) { void xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node); void xsltForEach(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst); +void xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst); + +/** + * xsltAttribute: + * @ctxt: a XSLT process context + * @node: the node in the source tree. + * @inst: the xslt attribute node + * + * Process the xslt attribute node on the source node + */ +void +xsltAttribute(xsltTransformContextPtr ctxt, xmlNodePtr node, + xmlNodePtr inst) { + xmlChar *prop = NULL; + xmlChar *ncname = NULL; + xmlChar *prefix = NULL; + xmlChar *value = NULL; + xmlNsPtr ns = NULL; + xmlAttrPtr attr; + + + if (ctxt->insert == NULL) + return; + if (ctxt->insert->children != NULL) { + xsltGenericError(xsltGenericErrorContext, + "xslt:attribute : node has already children\n"); + return; + } + prop = xmlGetNsProp(inst, (const xmlChar *)"namespace", XSLT_NAMESPACE); + if (prop != NULL) { + /* TODO: attribute value template */ + TODO + xmlFree(prop); + return; + } + prop = xmlGetNsProp(inst, (const xmlChar *)"name", XSLT_NAMESPACE); + if (prop == NULL) { + xsltGenericError(xsltGenericErrorContext, + "xslt:attribute : name is missing\n"); + goto error; + } + + ncname = xmlSplitQName2(prop, &prefix); + if (ncname == NULL) { + ncname = prop; + prop = NULL; + prefix = NULL; + } + if (xmlStrEqual(ncname, (const xmlChar *) "xmlns")) { + xsltGenericError(xsltGenericErrorContext, + "xslt:attribute : xmlns forbidden\n"); + goto error; + } + if ((prefix != NULL) && (ns == NULL)) { + ns = xmlSearchNs(ctxt->insert->doc, ctxt->insert, prefix); + if (ns == NULL) { + xsltGenericError(xsltGenericErrorContext, + "no namespace bound to prefix %s\n", prefix); + } + } + + value = xmlNodeListGetString(inst->doc, inst->children, 1); + if (value == NULL) { + if (ns) + attr = xmlSetNsProp(ctxt->insert, ncname, ns->href, + (const xmlChar *)""); + else + attr = xmlSetProp(ctxt->insert, ncname, (const xmlChar *)""); + } else { + /* TODO: attribute value template */ + if (ns) + attr = xmlSetNsProp(ctxt->insert, ncname, ns->href, value); + else + attr = xmlSetProp(ctxt->insert, ncname, value); + } + +error: + if (prop != NULL) + xmlFree(prop); + if (ncname != NULL) + xmlFree(ncname); + if (prefix != NULL) + xmlFree(prefix); + if (value != NULL) + xmlFree(value); +} /** * xsltValueOf: @@ -469,10 +555,18 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node, ctxt->insert = insert; xsltValueOf(ctxt, node, cur); ctxt->insert = oldInsert; + } else if (IS_XSLT_NAME(cur, "if")) { + ctxt->insert = insert; + xsltIf(ctxt, node, cur); + ctxt->insert = oldInsert; } else if (IS_XSLT_NAME(cur, "for-each")) { ctxt->insert = insert; xsltForEach(ctxt, node, cur); ctxt->insert = oldInsert; + } else if (IS_XSLT_NAME(cur, "attribute")) { + ctxt->insert = insert; + xsltAttribute(ctxt, node, cur); + ctxt->insert = oldInsert; } else { #ifdef DEBUG_PROCESS xsltGenericError(xsltGenericErrorContext, @@ -551,6 +645,86 @@ skip_children: } /** + * xsltIf: + * @ctxt: a XSLT process context + * @node: the node in the source tree. + * @inst: the xslt if node + * + * Process the xslt if node on the source node + */ +void +xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr node, + xmlNodePtr inst) { + xmlChar *prop; + xmlXPathObjectPtr res, tmp; + xmlXPathParserContextPtr xpathParserCtxt; + int doit; + + if ((ctxt == NULL) || (node == NULL) || (inst == NULL)) + return; + + prop = xmlGetNsProp(inst, (const xmlChar *)"test", XSLT_NAMESPACE); + if (prop == NULL) { + xsltGenericError(xsltGenericErrorContext, + "xsltIf: test is not defined\n"); + return; + } +#ifdef DEBUG_PROCESS + xsltGenericError(xsltGenericErrorContext, + "xsltIf: test %s\n", prop); +#endif + + if (ctxt->xpathCtxt == NULL) { + xmlXPathInit(); + ctxt->xpathCtxt = xmlXPathNewContext(ctxt->doc); + if (ctxt->xpathCtxt == NULL) + goto error; + } + xpathParserCtxt = xmlXPathNewParserContext(prop, ctxt->xpathCtxt); + if (xpathParserCtxt == NULL) + goto error; + ctxt->xpathCtxt->node = node; + valuePush(xpathParserCtxt, xmlXPathNewNodeSet(node)); + xmlXPathEvalExpr(xpathParserCtxt); + xmlXPathBooleanFunction(xpathParserCtxt, 1); + res = valuePop(xpathParserCtxt); + do { + tmp = valuePop(xpathParserCtxt); + if (tmp != NULL) { + xmlXPathFreeObject(tmp); + } + } while (tmp != NULL); + + if (res != NULL) { + if (res->type == XPATH_BOOLEAN) + doit = res->boolval; + else { +#ifdef DEBUG_PROCESS + xsltGenericError(xsltGenericErrorContext, + "xsltIf: test didn't evaluate to a boolean\n"); +#endif + goto error; + } + } + +#ifdef DEBUG_PROCESS + xsltGenericError(xsltGenericErrorContext, + "xsltIf: test evaluate to %d\n", doit); +#endif + if (doit) { + xsltApplyOneTemplate(ctxt, ctxt->node, inst->children); + } + +error: + if (xpathParserCtxt != NULL) + xmlXPathFreeParserContext(xpathParserCtxt); + if (prop != NULL) + xmlFree(prop); + if (res != NULL) + xmlXPathFreeObject(res); +} + +/** * xsltForEach: * @ctxt: a XSLT process context * @node: the node in the source tree. @@ -702,8 +876,9 @@ xsltApplyStylesheet(xsltStylesheetPtr style, xmlDocPtr doc) { goto error; } else if (xmlStrEqual(style->method, (const xmlChar *) "text")) { ctxt->type = XSLT_OUTPUT_TEXT; - TODO - goto error; + res = xmlNewDoc(style->version); + if (res == NULL) + goto error; } else { xsltGenericError(xsltGenericErrorContext, "xsltApplyStylesheet: insupported method %s\n", diff --git a/libxslt/xslt.c b/libxslt/xslt.c index c6dee96..e400d65 100644 --- a/libxslt/xslt.c +++ b/libxslt/xslt.c @@ -467,80 +467,21 @@ xsltParseStylesheetStripSpace(xsltStylesheetPtr style, xmlNodePtr cur) { } /** - * xsltParseStylesheetTemplate: + * xsltParseTemplateContent: * @style: the XSLT stylesheet - * @template: the "template" element + * @ret: the "template" structure + * @template: the container node (can be a document for literal results) * - * parse an XSLT stylesheet template building the associated structures + * parse an XSLT template element content + * Clean-up the template content from unwanted ignorable blank nodes + * and process xslt:text */ void -xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) { - xsltTemplatePtr ret; +xsltParseTemplateContent(xsltStylesheetPtr style, xsltTemplatePtr ret, + xmlNodePtr template) { xmlNodePtr cur, delete; - xmlChar *prop; - - if (template == NULL) - return; - - - /* - * Create and link the structure - */ - ret = xsltNewTemplate(); - if (ret == NULL) - return; - ret->next = style->templates; - style->templates = ret; - /* - * Get arguments - */ - prop = xmlGetNsProp(template, (const xmlChar *)"match", XSLT_NAMESPACE); - if (prop != NULL) { - if (ret->match != NULL) xmlFree(ret->match); - ret->match = prop; - } - - prop = xmlGetNsProp(template, (const xmlChar *)"name", XSLT_NAMESPACE); - if (prop != NULL) { - xmlChar *ncname; - xmlChar *prefix = NULL; - - if (ret->name != NULL) xmlFree(ret->name); - ret->name = NULL; - if (ret->nameURI != NULL) xmlFree(ret->nameURI); - ret->nameURI = NULL; - - ncname = xmlSplitQName2(prop, &prefix); - if (ncname != NULL) { - if (prefix != NULL) { - xmlNsPtr ns; - - ns = xmlSearchNs(cur->doc, cur, prefix); - if (ns == NULL) { - xsltGenericError(xsltGenericErrorContext, - "no namespace bound to prefix %s\n", prefix); - xmlFree(prefix); - xmlFree(ncname); - ret->name = prop; - } else { - ret->nameURI = xmlStrdup(ns->href); - ret->name = ncname; - xmlFree(prefix); - xmlFree(prop); - } - } else { - ret->name = ncname; - xmlFree(prop); - } - } else { - ret->name = prop; - } - } - - /* - * Clean-up the template content from unwanted ignorable blank nodes * This content comes from the stylesheet * For stylesheets, the set of whitespace-preserving * element names consists of just xsl:text. @@ -558,8 +499,21 @@ xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) { delete = NULL; } if (IS_XSLT_ELEM(cur)) { - if (IS_XSLT_NAME(cur, "text")) + if (IS_XSLT_NAME(cur, "text")) { + if (cur->children != NULL) { + if ((cur->children->type != XML_TEXT_NODE) || + (cur->children->next != NULL)) { + xsltGenericError(xsltGenericErrorContext, + "xsltParseStylesheetTemplate: xslt:text content problem\n"); + } else { + xmlNodePtr text = cur->children; + xmlUnlinkNode(text); + xmlAddPrevSibling(cur, text); + } + } + delete = cur; goto skip_children; + } } else if (cur->type == XML_TEXT_NODE) { if (IS_BLANK_NODE(cur)) { delete = cur; @@ -597,6 +551,15 @@ skip_children: } } while (cur != NULL); } + if (delete != NULL) { +#ifdef DEBUG_PARSING + xsltGenericError(xsltGenericErrorContext, + "xsltParseStylesheetTemplate: removing ignorable blank node\n"); +#endif + xmlUnlinkNode(delete); + xmlFreeNode(delete); + delete = NULL; + } /* * Find and handle the params @@ -651,10 +614,83 @@ skip_children: } ret->content = template->children; +} + +/** + * xsltParseStylesheetTemplate: + * @style: the XSLT stylesheet + * @template: the "template" element + * + * parse an XSLT stylesheet template building the associated structures + */ + +void +xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) { + xsltTemplatePtr ret; + xmlChar *prop; + + if (template == NULL) + return; + + /* + * Create and link the structure + */ + ret = xsltNewTemplate(); + if (ret == NULL) + return; + ret->next = style->templates; + style->templates = ret; + + /* + * Get arguments + */ + prop = xmlGetNsProp(template, (const xmlChar *)"match", XSLT_NAMESPACE); + if (prop != NULL) { + if (ret->match != NULL) xmlFree(ret->match); + ret->match = prop; + } + + prop = xmlGetNsProp(template, (const xmlChar *)"name", XSLT_NAMESPACE); + if (prop != NULL) { + xmlChar *ncname; + xmlChar *prefix = NULL; + + if (ret->name != NULL) xmlFree(ret->name); + ret->name = NULL; + if (ret->nameURI != NULL) xmlFree(ret->nameURI); + ret->nameURI = NULL; + + ncname = xmlSplitQName2(prop, &prefix); + if (ncname != NULL) { + if (prefix != NULL) { + xmlNsPtr ns; + + ns = xmlSearchNs(template->doc, template, prefix); + if (ns == NULL) { + xsltGenericError(xsltGenericErrorContext, + "no namespace bound to prefix %s\n", prefix); + xmlFree(prefix); + xmlFree(ncname); + ret->name = prop; + } else { + ret->nameURI = xmlStrdup(ns->href); + ret->name = ncname; + xmlFree(prefix); + xmlFree(prop); + } + } else { + ret->name = ncname; + xmlFree(prop); + } + } else { + ret->name = prop; + } + } /* - * Register pattern + * parse the content and register the pattern */ + xsltParseTemplateContent(style, ret, template); xsltAddTemplate(style, ret); } @@ -794,14 +830,45 @@ xsltParseStylesheetDoc(xmlDocPtr doc) { xsltParseStylesheetTop(ret, cur); } else { + xmlChar *prop; + xsltTemplatePtr template; + /* - * the document itself is the template. + * the document itself might be the template, check xsl:version */ + prop = xmlGetNsProp(cur, (const xmlChar *)"version", XSLT_NAMESPACE); + if (prop == NULL) { + xsltGenericError(xsltGenericErrorContext, + "xsltParseStylesheetDoc : document is not a stylesheet\n"); + xsltFreeStylesheet(ret); + return(NULL); + } + #ifdef DEBUG_PARSING xsltGenericError(xsltGenericErrorContext, "xsltParseStylesheetDoc : document is stylesheet\n"); #endif - TODO + + /* TODO: check the version */ + xmlFree(prop); + + /* + * Create and link the template + */ + template = xsltNewTemplate(); + if (template == NULL) { + xsltFreeStylesheet(ret); + return(NULL); + } + template->next = ret->templates; + ret->templates = template; + template->match = xmlStrdup((const xmlChar *)"/"); + + /* + * parse the content and register the pattern + */ + xsltParseTemplateContent(ret, template, (xmlNodePtr) doc); + xsltAddTemplate(ret, template); } return(ret); diff --git a/libxslt/xsltproc.c b/libxslt/xsltproc.c index ccb060b..644884c 100644 --- a/libxslt/xsltproc.c +++ b/libxslt/xsltproc.c @@ -32,7 +32,7 @@ main(int argc, char **argv) { if ((argv[i][0] != '-') || (strcmp(argv[i], "-") == 0)) { cur = xsltParseStylesheetFile((const xmlChar *)argv[i]); if (cur != NULL) { - if (cur->indent) + if (cur->indent == 1) xmlIndentTreeOutput = 1; else xmlIndentTreeOutput = 0;