1
0
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:
Daniel Veillard
2001-01-22 10:52:35 +00:00
parent 935ed1d25f
commit b94fc73a64
12 changed files with 676 additions and 94 deletions

View File

@@ -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
View File

@@ -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

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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")) {

View File

@@ -21,7 +21,9 @@ extern "C" {
*/
xmlDocPtr xsltApplyStylesheet (xsltStylesheetPtr style,
xmlDocPtr doc);
void xsltApplyOneTemplate (xsltTransformContextPtr ctxt,
xmlNodePtr node,
xmlNodePtr list);
#ifdef __cplusplus
}
#endif

View File

@@ -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)
if (cur->nameURI == NULL) {
if (cur->type == XSLT_ELEM_PARAM)
ret = cur;
else
return(cur);
}
} else {
if ((cur->nameURI != NULL) &&
(xmlStrEqual(cur->nameURI, nameURI)))
(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);

View File

@@ -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);

View File

@@ -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,7 +565,6 @@ skip_children:
/*
* Find and handle the params
*/
cur = template->children;
while (cur != NULL) {
/ *
@@ -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

View File

@@ -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
}

View File

@@ -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 */

View File

@@ -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>