mirror of
https://gitlab.gnome.org/GNOME/libxslt
synced 2025-11-08 11:02:18 +03:00
Furious hacking session, making serious progresses, the hardest stuff
now seems in place !!! * xsltproc.c: removed bug * tests/REC2/html.xml: added newline after doctype * libxslt/variables.[ch] libxslt/xsltInternals.h: added param support, result tree fragment support (requires just commited extensions to libxml2 XPath !!!) * transform.c: added call-template, with-param support * libxslt/pattern.[ch]: xsltFindTemplate() needed for call-template * TODO: updated, added a DONE section and started migrating stuff :-) Daniel
This commit is contained in:
11
ChangeLog
11
ChangeLog
@@ -1,3 +1,14 @@
|
||||
Mon Jan 22 11:46:44 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
|
||||
|
||||
* xsltproc.c: removed bug
|
||||
* tests/REC2/html.xml: added newline after doctype
|
||||
* libxslt/variables.[ch] libxslt/xsltInternals.h: added param
|
||||
support, result tree fragment support (requires just commited
|
||||
extensions to libxml2 XPath !!!)
|
||||
* transform.c: added call-template, with-param support
|
||||
* libxslt/pattern.[ch]: xsltFindTemplate() needed for call-template
|
||||
* TODO: updated, added a DONE section and started migrating stuff :-)
|
||||
|
||||
Sun Jan 21 12:03:16 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
|
||||
|
||||
* Makefile.am tests/Makefile.am tests/REC1/Makefile.am
|
||||
|
||||
35
TODO
35
TODO
@@ -1,3 +1,8 @@
|
||||
********
|
||||
* *
|
||||
* TODO *
|
||||
* *
|
||||
********
|
||||
Design:
|
||||
- should transforms for a given stylesheet be thread clean,
|
||||
or can a stylesheet be enriched with document specific
|
||||
@@ -18,15 +23,6 @@ Pattern scanner:
|
||||
-> handle unions
|
||||
-> compute priority
|
||||
|
||||
Separate util module:
|
||||
-> macros, config, verbosity ?
|
||||
|
||||
Support for disable-output-escaping="yes":
|
||||
-> looks problematic, libxml has no support for anything like this,
|
||||
and unless adding a new node type :-( or tweaking text node and
|
||||
output routines this is gonna be messy ... must be handled at libxml
|
||||
level.
|
||||
|
||||
Error handling:
|
||||
-> check the version stuff, design a separate module for error interfacing
|
||||
and default handling, parsing vs. runtime, fatal / compat / warning,
|
||||
@@ -35,6 +31,8 @@ Error handling:
|
||||
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.
|
||||
|
||||
Sorting:
|
||||
-> add support for imbricated sorts
|
||||
@@ -45,4 +43,23 @@ Validity:
|
||||
-> should we add validation by default ? Make this an option
|
||||
-> redirrect validity errors
|
||||
|
||||
Contextual error reporting:
|
||||
-> provide a couple of functions providing context analysis, not urgent
|
||||
|
||||
********
|
||||
* *
|
||||
* DONE *
|
||||
* *
|
||||
********
|
||||
|
||||
Separate util module:
|
||||
-> macros, config, verbosity ?
|
||||
=> xsltutils.[ch]
|
||||
|
||||
Support for disable-output-escaping="yes":
|
||||
-> looks problematic, libxml has no support for anything like this,
|
||||
and unless adding a new node type :-( or tweaking text node and
|
||||
output routines this is gonna be messy ... must be handled at libxml
|
||||
level.
|
||||
=> Done with a trick, text node name is different, requires > 2.2.11
|
||||
|
||||
|
||||
@@ -974,12 +974,33 @@ int
|
||||
xsltAddTemplate(xsltStylesheetPtr style, xsltTemplatePtr cur) {
|
||||
xsltCompMatchPtr pat, list;
|
||||
const xmlChar *name;
|
||||
xmlChar *p, *pattern, tmp;
|
||||
|
||||
if ((style == NULL) || (cur == NULL))
|
||||
return(-1);
|
||||
|
||||
p = cur->match;
|
||||
if (p == NULL)
|
||||
return(-1);
|
||||
|
||||
next_pattern:
|
||||
if (*p == 0)
|
||||
return(0);
|
||||
/*
|
||||
* get a compiled form of the pattern
|
||||
*/
|
||||
/* TODO : handle | in patterns as multple pat !!! */
|
||||
pat = xsltCompilePattern(cur->match);
|
||||
pattern = p;
|
||||
while ((*p != 0) && (*p != '|')) {
|
||||
/* TODO: handle string escaping "a | b" in patterns ... */
|
||||
p++;
|
||||
}
|
||||
|
||||
tmp = *p;
|
||||
*p = 0;
|
||||
pat = xsltCompilePattern(pattern);
|
||||
*p = tmp;
|
||||
if (tmp != 0)
|
||||
p++;
|
||||
if (pat == NULL)
|
||||
return(-1);
|
||||
pat->template = cur;
|
||||
@@ -1080,6 +1101,8 @@ xsltAddTemplate(xsltStylesheetPtr style, xsltTemplatePtr cur) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (*p != 0)
|
||||
goto next_pattern;
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -1174,3 +1197,36 @@ xsltFreeTemplateHashes(xsltStylesheetPtr style) {
|
||||
(xmlHashDeallocator) xsltFreeCompMatchList);
|
||||
}
|
||||
|
||||
/**
|
||||
* xsltFindTemplate:
|
||||
* @style: an XSLT stylesheet
|
||||
* @name: the template name
|
||||
* @nameURI: the template name URI
|
||||
*
|
||||
* Finds the named template.
|
||||
*
|
||||
* Returns the xsltTemplatePtr or NULL if not found
|
||||
*/
|
||||
xsltTemplatePtr
|
||||
xsltFindTemplate(xsltStylesheetPtr style, const xmlChar *name,
|
||||
const xmlChar *nameURI) {
|
||||
xsltTemplatePtr cur;
|
||||
|
||||
if ((style == NULL) || (name == NULL))
|
||||
return(NULL);
|
||||
|
||||
/* TODO: apply stylesheet import order */
|
||||
cur = style->templates;
|
||||
while (cur != NULL) {
|
||||
if (xmlStrEqual(name, cur->name)) {
|
||||
if (((nameURI == NULL) && (cur->nameURI == NULL)) ||
|
||||
((nameURI != NULL) && (cur->nameURI != NULL) &&
|
||||
(xmlStrEqual(nameURI, cur->nameURI)))) {
|
||||
return(cur);
|
||||
}
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,9 @@ int xsltAddTemplate (xsltStylesheetPtr style,
|
||||
xsltTemplatePtr xsltGetTemplate (xsltStylesheetPtr style,
|
||||
xmlNodePtr node);
|
||||
void xsltFreeTemplateHashes (xsltStylesheetPtr style);
|
||||
xsltTemplatePtr xsltFindTemplate (xsltStylesheetPtr style,
|
||||
const xmlChar *name,
|
||||
const xmlChar *nameURI);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -295,7 +295,7 @@ xsltAttribute(xsltTransformContextPtr ctxt, xmlNodePtr node,
|
||||
if (value == NULL) {
|
||||
if (ns) {
|
||||
#if LIBXML_VERSION > 20211
|
||||
attr = xmlSetNsProp(ctxt->insert, ncname, ns->href,
|
||||
attr = xmlSetNsProp(ctxt->insert, ns, ncname,
|
||||
(const xmlChar *)"");
|
||||
#else
|
||||
xsltGenericError(xsltGenericErrorContext,
|
||||
@@ -585,6 +585,89 @@ xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* xsltCallTemplate:
|
||||
* @ctxt: a XSLT process context
|
||||
* @node: the node in the source tree.
|
||||
* @inst: the xslt call-template node
|
||||
*
|
||||
* Process the xslt call-template node on the source node
|
||||
*/
|
||||
void
|
||||
xsltCallTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
|
||||
xmlNodePtr inst) {
|
||||
xmlChar *prop = NULL;
|
||||
xmlChar *ncname = NULL;
|
||||
xmlChar *prefix = NULL;
|
||||
xmlNsPtr ns = NULL;
|
||||
xsltTemplatePtr template;
|
||||
xmlNodePtr cur;
|
||||
int has_param = 0;
|
||||
|
||||
|
||||
if (ctxt->insert == NULL)
|
||||
return;
|
||||
prop = xmlGetNsProp(inst, (const xmlChar *)"name", XSLT_NAMESPACE);
|
||||
if (prop == NULL) {
|
||||
xsltGenericError(xsltGenericErrorContext,
|
||||
"xslt:call-template : name is missing\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
ncname = xmlSplitQName2(prop, &prefix);
|
||||
if (ncname == NULL) {
|
||||
ncname = prop;
|
||||
prop = NULL;
|
||||
prefix = NULL;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (ns != NULL)
|
||||
template = xsltFindTemplate(ctxt->style, ncname, ns->href);
|
||||
else
|
||||
template = xsltFindTemplate(ctxt->style, ncname, NULL);
|
||||
if (template == NULL) {
|
||||
xsltGenericError(xsltGenericDebugContext,
|
||||
"xslt:call-template: template %s not found\n", cur->name);
|
||||
goto error;
|
||||
}
|
||||
cur = inst->children;
|
||||
while (cur != NULL) {
|
||||
if (IS_XSLT_ELEM(cur)) {
|
||||
if (IS_XSLT_NAME(cur, "with-param")) {
|
||||
if (has_param == 0) {
|
||||
xsltPushStack(ctxt);
|
||||
has_param = 1;
|
||||
}
|
||||
xsltParseStylesheetParam(ctxt, cur);
|
||||
} else {
|
||||
xsltGenericError(xsltGenericDebugContext,
|
||||
"xslt:call-template: misplaced xslt:%s\n", cur->name);
|
||||
}
|
||||
} else {
|
||||
xsltGenericError(xsltGenericDebugContext,
|
||||
"xslt:call-template: misplaced %s element\n", cur->name);
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
xsltApplyOneTemplate(ctxt, node, template->content);
|
||||
|
||||
error:
|
||||
if (has_param == 1)
|
||||
xsltPopStack(ctxt);
|
||||
if (prop != NULL)
|
||||
xmlFree(prop);
|
||||
if (ncname != NULL)
|
||||
xmlFree(ncname);
|
||||
if (prefix != NULL)
|
||||
xmlFree(prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* xsltApplyTemplates:
|
||||
* @ctxt: a XSLT process context
|
||||
@@ -803,8 +886,21 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
|
||||
} else if (IS_XSLT_NAME(cur, "variable")) {
|
||||
if (has_variables == 0) {
|
||||
xsltPushStack(ctxt);
|
||||
has_variables = 1;
|
||||
}
|
||||
xsltParseStylesheetVariable(ctxt, cur);
|
||||
} else if (IS_XSLT_NAME(cur, "param")) {
|
||||
if (has_variables == 0) {
|
||||
xsltPushStack(ctxt);
|
||||
has_variables = 1;
|
||||
}
|
||||
xsltParseStylesheetParam(ctxt, cur);
|
||||
} else if (IS_XSLT_NAME(cur, "call-template")) {
|
||||
if (has_variables == 0) {
|
||||
xsltPushStack(ctxt);
|
||||
has_variables = 1;
|
||||
}
|
||||
xsltCallTemplate(ctxt, node, cur);
|
||||
} else {
|
||||
#ifdef DEBUG_PROCESS
|
||||
xsltGenericError(xsltGenericDebugContext,
|
||||
@@ -1120,6 +1216,7 @@ xsltApplyStylesheet(xsltStylesheetPtr style, xmlDocPtr doc) {
|
||||
return(NULL);
|
||||
ctxt->doc = doc;
|
||||
ctxt->style = style;
|
||||
xsltEvalGlobalVariables(ctxt);
|
||||
if ((style->method != NULL) &&
|
||||
(!xmlStrEqual(style->method, (const xmlChar *) "xml"))) {
|
||||
if (xmlStrEqual(style->method, (const xmlChar *) "html")) {
|
||||
|
||||
@@ -21,7 +21,9 @@ extern "C" {
|
||||
*/
|
||||
xmlDocPtr xsltApplyStylesheet (xsltStylesheetPtr style,
|
||||
xmlDocPtr doc);
|
||||
|
||||
void xsltApplyOneTemplate (xsltTransformContextPtr ctxt,
|
||||
xmlNodePtr node,
|
||||
xmlNodePtr list);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -18,12 +18,14 @@
|
||||
#include <libxml/valid.h>
|
||||
#include <libxml/hash.h>
|
||||
#include <libxml/xmlerror.h>
|
||||
#include <libxml/xpath.h>
|
||||
#include <libxml/xpathInternals.h>
|
||||
#include <libxml/parserInternals.h>
|
||||
#include "xslt.h"
|
||||
#include "xsltInternals.h"
|
||||
#include "xsltutils.h"
|
||||
#include "variables.h"
|
||||
#include "transform.h"
|
||||
|
||||
#define DEBUG_VARIABLE
|
||||
|
||||
@@ -31,24 +33,6 @@
|
||||
* Types are private:
|
||||
*/
|
||||
|
||||
|
||||
typedef enum {
|
||||
XSLT_ELEM_VARIABLE=1,
|
||||
XSLT_ELEM_PARAM
|
||||
} xsltElem;
|
||||
|
||||
typedef struct _xsltStackElem xsltStackElem;
|
||||
typedef xsltStackElem *xsltStackElemPtr;
|
||||
struct _xsltStackElem {
|
||||
struct _xsltStackElem *next;/* chained list */
|
||||
xsltElem elem; /* type of the element */
|
||||
int computed; /* was the evaluation done */
|
||||
xmlChar *name; /* the local part of the name QName */
|
||||
xmlChar *nameURI; /* the URI part of the name QName */
|
||||
xmlXPathObjectPtr value; /* The value if computed */
|
||||
xmlChar *select; /* the eval string */
|
||||
};
|
||||
|
||||
typedef struct _xsltStack xsltStack;
|
||||
typedef xsltStack *xsltStackPtr;
|
||||
struct _xsltStack {
|
||||
@@ -138,6 +122,7 @@ xsltFreeStackElemList(xsltStackElemPtr elem) {
|
||||
int
|
||||
xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) {
|
||||
xsltStackPtr stack;
|
||||
xsltStackElemPtr cur;
|
||||
|
||||
if ((ctxt == NULL) || (elem == NULL))
|
||||
return(-1);
|
||||
@@ -158,6 +143,20 @@ xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) {
|
||||
}
|
||||
/* TODO: check that there is no conflict with existing values
|
||||
* at that level */
|
||||
cur = stack->elems[stack->cur];
|
||||
while (cur != NULL) {
|
||||
if (xmlStrEqual(elem->name, cur->name)) {
|
||||
if (((elem->nameURI == NULL) && (cur->nameURI == NULL)) ||
|
||||
((elem->nameURI != NULL) && (cur->nameURI != NULL) &&
|
||||
(xmlStrEqual(elem->nameURI, cur->nameURI)))) {
|
||||
xsltGenericError(xsltGenericErrorContext,
|
||||
"redefinition of param or variable %s\n", elem->name);
|
||||
xsltFreeStackElem(elem);
|
||||
}
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
elem->next = stack->elems[stack->cur];
|
||||
stack->elems[stack->cur] = elem;
|
||||
return(0);
|
||||
@@ -233,6 +232,7 @@ xsltPopStack(xsltTransformContextPtr ctxt) {
|
||||
xsltStackElemPtr
|
||||
xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
|
||||
const xmlChar *nameURI) {
|
||||
xsltStackElemPtr ret = NULL;
|
||||
xsltStackPtr stack;
|
||||
int i;
|
||||
xsltStackElemPtr cur;
|
||||
@@ -248,20 +248,29 @@ xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
|
||||
cur = stack->elems[i];
|
||||
while (cur != NULL) {
|
||||
if (xmlStrEqual(cur->name, name)) {
|
||||
/* TODO: double check param binding */
|
||||
if (nameURI == NULL) {
|
||||
if (cur->nameURI == NULL)
|
||||
return(cur);
|
||||
if (cur->nameURI == NULL) {
|
||||
if (cur->type == XSLT_ELEM_PARAM)
|
||||
ret = cur;
|
||||
else
|
||||
return(cur);
|
||||
}
|
||||
} else {
|
||||
if ((cur->nameURI != NULL) &&
|
||||
(xmlStrEqual(cur->nameURI, nameURI)))
|
||||
return(cur);
|
||||
(xmlStrEqual(cur->nameURI, nameURI))) {
|
||||
if (cur->type == XSLT_ELEM_PARAM)
|
||||
ret = cur;
|
||||
else
|
||||
return(cur);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
}
|
||||
return(NULL);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
@@ -270,13 +279,192 @@ xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
|
||||
* *
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* xsltEvalVariable:
|
||||
* @ctxt: the XSLT transformation context
|
||||
* @elem: the variable or parameter.
|
||||
*
|
||||
* Evaluate a variable value.
|
||||
*
|
||||
* Returns 0 in case of success, -1 in case of error
|
||||
*/
|
||||
int
|
||||
xsltEvalVariables(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) {
|
||||
xmlXPathParserContextPtr xpathParserCtxt;
|
||||
|
||||
if ((ctxt == NULL) || (elem == NULL))
|
||||
return(-1);
|
||||
|
||||
if (ctxt->xpathCtxt == NULL) {
|
||||
xmlXPathInit();
|
||||
ctxt->xpathCtxt = xmlXPathNewContext(ctxt->doc);
|
||||
if (ctxt->xpathCtxt == NULL)
|
||||
return(-1);
|
||||
XSLT_REGISTER_VARIABLE_LOOKUP(ctxt);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_VARIABLE
|
||||
xsltGenericDebug(xsltGenericDebugContext,
|
||||
"Evaluating variable %s\n", elem->name);
|
||||
#endif
|
||||
if (elem->select != NULL) {
|
||||
xmlXPathObjectPtr result, tmp;
|
||||
|
||||
xpathParserCtxt = xmlXPathNewParserContext(elem->select,
|
||||
ctxt->xpathCtxt);
|
||||
if (xpathParserCtxt == NULL)
|
||||
return(-1);
|
||||
ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
|
||||
xmlXPathEvalExpr(xpathParserCtxt);
|
||||
result = valuePop(xpathParserCtxt);
|
||||
do {
|
||||
tmp = valuePop(xpathParserCtxt);
|
||||
if (tmp != NULL) {
|
||||
xmlXPathFreeObject(tmp);
|
||||
}
|
||||
} while (tmp != NULL);
|
||||
|
||||
if (result == NULL) {
|
||||
xsltGenericError(xsltGenericErrorContext,
|
||||
"Evaluating global variable %s failed\n");
|
||||
}
|
||||
if (xpathParserCtxt != NULL)
|
||||
xmlXPathFreeParserContext(xpathParserCtxt);
|
||||
if (result != NULL) {
|
||||
if (elem->value != NULL)
|
||||
xmlXPathFreeObject(elem->value);
|
||||
elem->value = result;
|
||||
elem->computed = 1;
|
||||
}
|
||||
} else {
|
||||
if (elem->tree == NULL) {
|
||||
elem->value = xmlXPathNewCString("");
|
||||
elem->computed = 1;
|
||||
} else {
|
||||
/*
|
||||
* This is a result tree fragment.
|
||||
*/
|
||||
xmlNodePtr container;
|
||||
xmlNodePtr oldInsert, oldNode;
|
||||
|
||||
container = xmlNewDocNode(ctxt->output, NULL,
|
||||
(const xmlChar *) "fake", NULL);
|
||||
if (container == NULL)
|
||||
return(-1);
|
||||
oldInsert = ctxt->insert;
|
||||
oldNode = ctxt->node;
|
||||
ctxt->insert = container;
|
||||
|
||||
xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree);
|
||||
|
||||
ctxt->insert = oldInsert;
|
||||
ctxt->node = oldNode;
|
||||
elem->value = xmlXPathNewValueTree(container);
|
||||
elem->computed = 1;
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
/**
|
||||
* xsltEvalGlobalVariables:
|
||||
* @ctxt: the XSLT transformation context
|
||||
*
|
||||
* Evaluate the global variables of a stylesheet. This need to be
|
||||
* done on parsed stylesheets before starting to apply transformations
|
||||
*
|
||||
* Returns 0 in case of success, -1 in case of error
|
||||
*/
|
||||
int
|
||||
xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
|
||||
xsltStackElemPtr elem;
|
||||
xsltStylesheetPtr style;
|
||||
|
||||
if (ctxt == NULL)
|
||||
return(-1);
|
||||
|
||||
if (ctxt->xpathCtxt == NULL) {
|
||||
xmlXPathInit();
|
||||
ctxt->xpathCtxt = xmlXPathNewContext(ctxt->doc);
|
||||
if (ctxt->xpathCtxt == NULL)
|
||||
return(-1);
|
||||
XSLT_REGISTER_VARIABLE_LOOKUP(ctxt);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_VARIABLE
|
||||
xsltGenericDebug(xsltGenericDebugContext,
|
||||
"Evaluating global variables\n");
|
||||
#endif
|
||||
ctxt->node = (xmlNodePtr) ctxt->doc;
|
||||
style = ctxt->style;
|
||||
/* TODO: handle the stylesheet cascade */
|
||||
if (style != NULL) {
|
||||
elem = style->variables;
|
||||
|
||||
while (elem != NULL) {
|
||||
xsltEvalVariables(ctxt, elem);
|
||||
elem = elem->next;
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* xsltRegisterGlobalVariable:
|
||||
* @style: the XSLT transformation context
|
||||
* @name: the variable name
|
||||
* @ns_uri: the variable namespace URI
|
||||
* @select: the expression which need to be evaluated to generate a value
|
||||
* @tree: the subtree if select is NULL
|
||||
* @param: this is a parameter actually
|
||||
*
|
||||
* Register a new variable value. If @value is NULL it unregisters
|
||||
* the variable
|
||||
*
|
||||
* Returns 0 in case of success, -1 in case of error
|
||||
*/
|
||||
int
|
||||
xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name,
|
||||
const xmlChar *ns_uri, const xmlChar *select,
|
||||
xmlNodePtr tree, int param) {
|
||||
xsltStackElemPtr elem;
|
||||
if (style == NULL)
|
||||
return(-1);
|
||||
if (name == NULL)
|
||||
return(-1);
|
||||
|
||||
#ifdef DEBUG_VARIABLE
|
||||
if (param)
|
||||
xsltGenericDebug(xsltGenericDebugContext,
|
||||
"Defineing global param %s\n", name);
|
||||
else
|
||||
xsltGenericDebug(xsltGenericDebugContext,
|
||||
"Defineing global variable %s\n", name);
|
||||
#endif
|
||||
elem = xsltNewStackElem();
|
||||
if (elem == NULL)
|
||||
return(-1);
|
||||
if (param)
|
||||
elem->type = XSLT_ELEM_PARAM;
|
||||
else
|
||||
elem->type = XSLT_ELEM_VARIABLE;
|
||||
elem->name = xmlStrdup(name);
|
||||
elem->select = xmlStrdup(select);
|
||||
if (ns_uri)
|
||||
elem->nameURI = xmlStrdup(ns_uri);
|
||||
elem->tree = tree;
|
||||
elem->next = style->variables;
|
||||
style->variables = elem;
|
||||
return(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* xsltRegisterVariable:
|
||||
* @ctxt: the XSLT transformation context
|
||||
* @name: the variable name
|
||||
* @ns_uri: the variable namespace URI
|
||||
* @select: the expression which need to be evaluated to generate a value
|
||||
* @value: the variable value if select is NULL
|
||||
* @tree: the tree if select is NULL
|
||||
* @param: this is a parameter actually
|
||||
*
|
||||
* Register a new variable value. If @value is NULL it unregisters
|
||||
* the variable
|
||||
@@ -286,7 +474,7 @@ xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
|
||||
int
|
||||
xsltRegisterVariable(xsltTransformContextPtr ctxt, const xmlChar *name,
|
||||
const xmlChar *ns_uri, const xmlChar *select,
|
||||
xmlXPathObjectPtr value) {
|
||||
xmlNodePtr tree, int param) {
|
||||
xsltStackElemPtr elem;
|
||||
if (ctxt == NULL)
|
||||
return(-1);
|
||||
@@ -300,46 +488,17 @@ xsltRegisterVariable(xsltTransformContextPtr ctxt, const xmlChar *name,
|
||||
elem = xsltNewStackElem();
|
||||
if (elem == NULL)
|
||||
return(-1);
|
||||
if (param)
|
||||
elem->type = XSLT_ELEM_PARAM;
|
||||
else
|
||||
elem->type = XSLT_ELEM_VARIABLE;
|
||||
elem->name = xmlStrdup(name);
|
||||
elem->select = xmlStrdup(select);
|
||||
if (ns_uri)
|
||||
elem->nameURI = xmlStrdup(ns_uri);
|
||||
elem->value = value;
|
||||
elem->tree = tree;
|
||||
xsltAddStackElem(ctxt, elem);
|
||||
if (elem->select != NULL) {
|
||||
xmlXPathObjectPtr result, tmp;
|
||||
xmlXPathParserContextPtr xpathParserCtxt;
|
||||
|
||||
xpathParserCtxt = xmlXPathNewParserContext(elem->select,
|
||||
ctxt->xpathCtxt);
|
||||
if (xpathParserCtxt == NULL)
|
||||
goto error;
|
||||
ctxt->xpathCtxt->node = ctxt->node;
|
||||
xmlXPathEvalExpr(xpathParserCtxt);
|
||||
result = valuePop(xpathParserCtxt);
|
||||
do {
|
||||
tmp = valuePop(xpathParserCtxt);
|
||||
if (tmp != NULL) {
|
||||
xmlXPathFreeObject(tmp);
|
||||
}
|
||||
} while (tmp != NULL);
|
||||
|
||||
if (result == NULL) {
|
||||
#ifdef DEBUG_PROCESS
|
||||
xsltGenericDebug(xsltGenericDebugContext,
|
||||
"Evaluating variable %s failed\n");
|
||||
#endif
|
||||
}
|
||||
if (xpathParserCtxt != NULL)
|
||||
xmlXPathFreeParserContext(xpathParserCtxt);
|
||||
if (result != NULL) {
|
||||
if (elem->value != NULL)
|
||||
xmlXPathFreeObject(elem->value);
|
||||
elem->value = result;
|
||||
elem->computed = 1;
|
||||
}
|
||||
}
|
||||
error:
|
||||
xsltEvalVariables(ctxt, elem);
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -372,7 +531,7 @@ xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
|
||||
xsltGenericDebug(xsltGenericDebugContext,
|
||||
"uncomputed variable %s\n", name);
|
||||
#endif
|
||||
TODO /* Variable value computation needed */
|
||||
xsltEvalVariables(ctxt, elem);
|
||||
}
|
||||
if (elem->value != NULL)
|
||||
return(xmlXPathObjectCopy(elem->value));
|
||||
@@ -408,12 +567,212 @@ xsltFreeVariableHashes(xsltTransformContextPtr ctxt) {
|
||||
xmlFree(stack);
|
||||
}
|
||||
|
||||
/**
|
||||
* xsltParseStylesheetParam:
|
||||
* @ctxt: the XSLT transformation context
|
||||
* @cur: the "param" element
|
||||
*
|
||||
* parse an XSLT transformation param declaration and record
|
||||
* its value.
|
||||
*/
|
||||
|
||||
void
|
||||
xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
|
||||
xmlChar *name, *ncname, *prefix;
|
||||
xmlChar *select;
|
||||
xmlNodePtr tree = NULL;
|
||||
|
||||
if ((cur == NULL) || (ctxt == NULL))
|
||||
return;
|
||||
|
||||
name = xmlGetNsProp(cur, (const xmlChar *)"name", XSLT_NAMESPACE);
|
||||
if (name == NULL) {
|
||||
xsltGenericError(xsltGenericErrorContext,
|
||||
"xsl:param : missing name attribute\n");
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_VARIABLE
|
||||
xsltGenericDebug(xsltGenericDebugContext,
|
||||
"Parsing param %s\n", name);
|
||||
#endif
|
||||
|
||||
select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE);
|
||||
if (select == NULL) {
|
||||
tree = cur->children;
|
||||
} else {
|
||||
if (cur->children != NULL)
|
||||
xsltGenericError(xsltGenericErrorContext,
|
||||
"xsl:param : content shuld be empty since select is present \n");
|
||||
}
|
||||
|
||||
ncname = xmlSplitQName2(name, &prefix);
|
||||
|
||||
if (ncname != NULL) {
|
||||
if (prefix != NULL) {
|
||||
xmlNsPtr ns;
|
||||
|
||||
ns = xmlSearchNs(cur->doc, cur, prefix);
|
||||
if (ns == NULL) {
|
||||
xsltGenericError(xsltGenericErrorContext,
|
||||
"xsl:param : no namespace bound to prefix %s\n", prefix);
|
||||
} else {
|
||||
xsltRegisterVariable(ctxt, ncname, ns->href, select, tree, 1);
|
||||
}
|
||||
xmlFree(prefix);
|
||||
} else {
|
||||
xsltRegisterVariable(ctxt, ncname, NULL, select, tree, 1);
|
||||
}
|
||||
xmlFree(ncname);
|
||||
} else {
|
||||
xsltRegisterVariable(ctxt, name, NULL, select, tree, 1);
|
||||
}
|
||||
|
||||
xmlFree(name);
|
||||
if (select != NULL)
|
||||
xmlFree(select);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* xsltParseGlobalVariable:
|
||||
* @style: the XSLT stylesheet
|
||||
* @cur: the "variable" element
|
||||
*
|
||||
* parse an XSLT transformation variable declaration and record
|
||||
* its value.
|
||||
*/
|
||||
|
||||
void
|
||||
xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur) {
|
||||
xmlChar *name, *ncname, *prefix;
|
||||
xmlChar *select;
|
||||
xmlNodePtr tree = NULL;
|
||||
|
||||
if ((cur == NULL) || (style == NULL))
|
||||
return;
|
||||
|
||||
name = xmlGetNsProp(cur, (const xmlChar *)"name", XSLT_NAMESPACE);
|
||||
if (name == NULL) {
|
||||
xsltGenericError(xsltGenericErrorContext,
|
||||
"xsl:variable : missing name attribute\n");
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_VARIABLE
|
||||
xsltGenericDebug(xsltGenericDebugContext,
|
||||
"Parsing global variable %s\n", name);
|
||||
#endif
|
||||
|
||||
select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE);
|
||||
if (select == NULL) {
|
||||
tree = cur->children;
|
||||
} else {
|
||||
if (cur->children != NULL)
|
||||
xsltGenericError(xsltGenericErrorContext,
|
||||
"xsl:variable : content shuld be empty since select is present \n");
|
||||
}
|
||||
|
||||
ncname = xmlSplitQName2(name, &prefix);
|
||||
|
||||
if (ncname != NULL) {
|
||||
if (prefix != NULL) {
|
||||
xmlNsPtr ns;
|
||||
|
||||
ns = xmlSearchNs(cur->doc, cur, prefix);
|
||||
if (ns == NULL) {
|
||||
xsltGenericError(xsltGenericErrorContext,
|
||||
"xsl:variable : no namespace bound to prefix %s\n", prefix);
|
||||
} else {
|
||||
xsltRegisterGlobalVariable(style, ncname, ns->href, select, tree, 0);
|
||||
}
|
||||
xmlFree(prefix);
|
||||
} else {
|
||||
xsltRegisterGlobalVariable(style, ncname, NULL, select, tree, 0);
|
||||
}
|
||||
xmlFree(ncname);
|
||||
} else {
|
||||
xsltRegisterGlobalVariable(style, name, NULL, select, tree, 0);
|
||||
}
|
||||
|
||||
xmlFree(name);
|
||||
if (select != NULL)
|
||||
xmlFree(select);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* xsltParseGlobalParam:
|
||||
* @style: the XSLT stylesheet
|
||||
* @cur: the "param" element
|
||||
*
|
||||
* parse an XSLT transformation param declaration and record
|
||||
* its value.
|
||||
*/
|
||||
|
||||
void
|
||||
xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) {
|
||||
xmlChar *name, *ncname, *prefix;
|
||||
xmlChar *select;
|
||||
xmlNodePtr tree = NULL;
|
||||
|
||||
if ((cur == NULL) || (style == NULL))
|
||||
return;
|
||||
|
||||
name = xmlGetNsProp(cur, (const xmlChar *)"name", XSLT_NAMESPACE);
|
||||
if (name == NULL) {
|
||||
xsltGenericError(xsltGenericErrorContext,
|
||||
"xsl:param : missing name attribute\n");
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_VARIABLE
|
||||
xsltGenericDebug(xsltGenericDebugContext,
|
||||
"Parsing global param %s\n", name);
|
||||
#endif
|
||||
|
||||
select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE);
|
||||
if (select == NULL) {
|
||||
tree = cur->children;
|
||||
} else {
|
||||
if (cur->children != NULL)
|
||||
xsltGenericError(xsltGenericErrorContext,
|
||||
"xsl:param : content shuld be empty since select is present \n");
|
||||
}
|
||||
|
||||
ncname = xmlSplitQName2(name, &prefix);
|
||||
|
||||
if (ncname != NULL) {
|
||||
if (prefix != NULL) {
|
||||
xmlNsPtr ns;
|
||||
|
||||
ns = xmlSearchNs(cur->doc, cur, prefix);
|
||||
if (ns == NULL) {
|
||||
xsltGenericError(xsltGenericErrorContext,
|
||||
"xsl:param : no namespace bound to prefix %s\n", prefix);
|
||||
} else {
|
||||
xsltRegisterGlobalVariable(style, ncname, ns->href, select, tree, 1);
|
||||
}
|
||||
xmlFree(prefix);
|
||||
} else {
|
||||
xsltRegisterGlobalVariable(style, ncname, NULL, select, tree, 1);
|
||||
}
|
||||
xmlFree(ncname);
|
||||
} else {
|
||||
xsltRegisterGlobalVariable(style, name, NULL, select, tree, 1);
|
||||
}
|
||||
|
||||
xmlFree(name);
|
||||
if (select != NULL)
|
||||
xmlFree(select);
|
||||
}
|
||||
|
||||
/**
|
||||
* xsltParseStylesheetVariable:
|
||||
* @ctxt: the XSLT transformation context
|
||||
* @template: the "variable" name
|
||||
* @cur: the "variable" element
|
||||
*
|
||||
* parse an XSLT transformation context variable name and record
|
||||
* parse an XSLT transformation variable declaration and record
|
||||
* its value.
|
||||
*/
|
||||
|
||||
@@ -421,7 +780,7 @@ void
|
||||
xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
|
||||
xmlChar *name, *ncname, *prefix;
|
||||
xmlChar *select;
|
||||
xmlXPathObjectPtr value = NULL;
|
||||
xmlNodePtr tree = NULL;
|
||||
|
||||
if ((cur == NULL) || (ctxt == NULL))
|
||||
return;
|
||||
@@ -440,10 +799,7 @@ xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
|
||||
|
||||
select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE);
|
||||
if (select == NULL) {
|
||||
if (cur->children == NULL)
|
||||
value = xmlXPathNewCString("");
|
||||
else
|
||||
value = xmlXPathNewNodeSet(cur->children);
|
||||
tree = cur->children;
|
||||
} else {
|
||||
if (cur->children != NULL)
|
||||
xsltGenericError(xsltGenericErrorContext,
|
||||
@@ -461,15 +817,15 @@ xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
|
||||
xsltGenericError(xsltGenericErrorContext,
|
||||
"xsl:variable : no namespace bound to prefix %s\n", prefix);
|
||||
} else {
|
||||
xsltRegisterVariable(ctxt, ncname, ns->href, select, value);
|
||||
xsltRegisterVariable(ctxt, ncname, ns->href, select, tree, 0);
|
||||
}
|
||||
xmlFree(prefix);
|
||||
} else {
|
||||
xsltRegisterVariable(ctxt, ncname, NULL, select, value);
|
||||
xsltRegisterVariable(ctxt, ncname, NULL, select, tree, 0);
|
||||
}
|
||||
xmlFree(ncname);
|
||||
} else {
|
||||
xsltRegisterVariable(ctxt, name, NULL, select, value);
|
||||
xsltRegisterVariable(ctxt, name, NULL, select, tree, 0);
|
||||
}
|
||||
|
||||
xmlFree(name);
|
||||
|
||||
@@ -25,10 +25,17 @@ extern "C" {
|
||||
* Interfaces for the variable module.
|
||||
*/
|
||||
|
||||
int xsltEvalGlobalVariables (xsltTransformContextPtr ctxt);
|
||||
void xsltPushStack (xsltTransformContextPtr ctxt);
|
||||
void xsltPopStack (xsltTransformContextPtr ctxt);
|
||||
void xsltParseGlobalVariable (xsltStylesheetPtr style,
|
||||
xmlNodePtr cur);
|
||||
void xsltParseGlobalParam (xsltStylesheetPtr style,
|
||||
xmlNodePtr cur);
|
||||
void xsltParseStylesheetVariable (xsltTransformContextPtr ctxt,
|
||||
xmlNodePtr cur);
|
||||
void xsltParseStylesheetParam (xsltTransformContextPtr ctxt,
|
||||
xmlNodePtr cur);
|
||||
void xsltFreeVariableHashes (xsltTransformContextPtr ctxt);
|
||||
xmlXPathObjectPtr xsltVariableLookup (xsltTransformContextPtr ctxt,
|
||||
const xmlChar *name,
|
||||
@@ -37,7 +44,8 @@ int xsltRegisterVariable (xsltTransformContextPtr ctxt,
|
||||
const xmlChar *name,
|
||||
const xmlChar *ns_uri,
|
||||
const xmlChar *select,
|
||||
xmlXPathObjectPtr value);
|
||||
xmlNodePtr tree,
|
||||
int param);
|
||||
xmlXPathObjectPtr xsltXPathVariableLookup (void *ctxt,
|
||||
const xmlChar *name,
|
||||
const xmlChar *ns_uri);
|
||||
|
||||
@@ -165,6 +165,8 @@ xsltFreeStylesheet(xsltStylesheetPtr sheet) {
|
||||
xsltFreeTemplateList(sheet->templates);
|
||||
if (sheet->doc != NULL)
|
||||
xmlFreeDoc(sheet->doc);
|
||||
if (sheet->variables != NULL)
|
||||
xsltFreeStackElemList(sheet->variables);
|
||||
if (sheet->stripSpaces != NULL)
|
||||
xmlHashFree(sheet->stripSpaces, NULL);
|
||||
|
||||
@@ -563,12 +565,11 @@ skip_children:
|
||||
|
||||
/*
|
||||
* Find and handle the params
|
||||
*/
|
||||
cur = template->children;
|
||||
while (cur != NULL) {
|
||||
/*
|
||||
/ *
|
||||
* Remove Blank nodes found at this level.
|
||||
*/
|
||||
* /
|
||||
if (IS_BLANK_NODE(cur)) {
|
||||
xmlNodePtr blank = cur;
|
||||
|
||||
@@ -578,11 +579,12 @@ skip_children:
|
||||
continue;
|
||||
}
|
||||
if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) {
|
||||
TODO /* Handle param */
|
||||
xsltParseGlobalParam(style, cur);
|
||||
} else
|
||||
break;
|
||||
cur = cur->next;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
* Browse the remaining of the template
|
||||
|
||||
@@ -19,12 +19,33 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* The in-memory structure corresponding to an XSLT Stylesheet
|
||||
* NOTE: most of the content is simply linked from the doc tree
|
||||
* structure, no specific allocation is made.
|
||||
* The in-memory structure corresponding to an XSLT Variable
|
||||
* or Param
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
XSLT_ELEM_VARIABLE=1,
|
||||
XSLT_ELEM_PARAM
|
||||
} xsltElem;
|
||||
|
||||
typedef struct _xsltStackElem xsltStackElem;
|
||||
typedef xsltStackElem *xsltStackElemPtr;
|
||||
struct _xsltStackElem {
|
||||
struct _xsltStackElem *next;/* chained list */
|
||||
xsltElem type; /* type of the element */
|
||||
int computed; /* was the evaluation done */
|
||||
xmlChar *name; /* the local part of the name QName */
|
||||
xmlChar *nameURI; /* the URI part of the name QName */
|
||||
xmlChar *select; /* the eval string */
|
||||
xmlNodePtr tree; /* the tree if no eval string */
|
||||
xmlXPathObjectPtr value; /* The value if computed */
|
||||
};
|
||||
|
||||
/*
|
||||
* The in-memory structure corresponding to an XSLT Template
|
||||
*/
|
||||
#define XSLT_PAT_NO_PRIORITY -12345789
|
||||
|
||||
typedef struct _xsltTemplate xsltTemplate;
|
||||
@@ -42,6 +63,8 @@ struct _xsltTemplate {
|
||||
|
||||
/*
|
||||
* The in-memory structure corresponding to an XSLT Stylesheet
|
||||
* NOTE: most of the content is simply linked from the doc tree
|
||||
* structure, no specific allocation is made.
|
||||
*/
|
||||
typedef struct _xsltStylesheet xsltStylesheet;
|
||||
typedef xsltStylesheet *xsltStylesheetPtr;
|
||||
@@ -59,6 +82,11 @@ struct _xsltStylesheet {
|
||||
xmlHashTablePtr stripSpaces;/* the hash table of the strip-space
|
||||
preserve space and cdata-section elements */
|
||||
|
||||
/*
|
||||
* Global variable or parameters
|
||||
*/
|
||||
xsltStackElemPtr variables; /* linked list of param and variables */
|
||||
|
||||
/*
|
||||
* Template descriptions
|
||||
*/
|
||||
@@ -114,6 +142,7 @@ struct _xsltTransformContext {
|
||||
xsltStylesheetPtr xsltParseStylesheetFile (const xmlChar* filename);
|
||||
void xsltFreeStylesheet (xsltStylesheetPtr sheet);
|
||||
int xsltIsBlank (xmlChar *str);
|
||||
void xsltFreeStackElemList (xsltStackElemPtr elem);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ static int repeat = 0;
|
||||
int
|
||||
main(int argc, char **argv) {
|
||||
int i;
|
||||
xsltStylesheetPtr cur;
|
||||
xsltStylesheetPtr cur = NULL;
|
||||
xmlDocPtr doc, res;
|
||||
|
||||
/* --repeat : repeat 100 times, for timing or profiling */
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"><html lang="en">
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
|
||||
<html lang="en">
|
||||
<head><title>Sales Results By Division</title></head>
|
||||
<body><table border="1">
|
||||
<tr>
|
||||
|
||||
Reference in New Issue
Block a user