+Mon Jan 15 15:31:41 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
+
+ * 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 <Daniel.Veillard@imag.fr>
* test/Makefile.am test/REC*/Makefile.am: added first test
#include "pattern.h"
#include "transform.h"
-/* #define DEBUG_PROCESS */
+#define DEBUG_PROCESS
/*
* To cleanup
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:
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,
}
/**
+ * 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.
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",
}
/**
- * 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.
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;
}
} 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
}
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);
}
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);
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;