From e181896ae107292f615c75f7d808106d7fbe4490 Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Wed, 10 Jan 2001 15:32:17 +0000 Subject: [PATCH] Still not working but makes more noise and leaks memory now: - libxslt/xslt*: completeted the structures - libxslt/pattern.[ch]: started adding code to precompile patterns and do the lookup - libxslt/makefile.am: added the new files Daniel --- ChangeLog | 7 + libxslt/Makefile.am | 2 + libxslt/pattern.c | 408 ++++++++++++++++++++++++++++++++++++++++++++++++ libxslt/pattern.h | 28 ++++ libxslt/xslt.c | 396 +++++++++++++++++++++++++++++++++++++++++++--- libxslt/xslt.h | 2 +- libxslt/xsltInternals.h | 25 +++ 7 files changed, 843 insertions(+), 25 deletions(-) create mode 100644 libxslt/pattern.c create mode 100644 libxslt/pattern.h diff --git a/ChangeLog b/ChangeLog index 08f0e62..6bf7919 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +Wed Jan 10 16:29:41 CET 2001 Daniel Veillard + + * libxslt/xslt*: completeted the structures + * libxslt/pattern.[ch]: started adding code to precompile patterns + and do the lookup + * libxslt/makefile.am: added the new files + Mon Jan 8 19:55:18 CET 2001 Daniel Veillard * libxslt/xslt.c : small cleanup diff --git a/libxslt/Makefile.am b/libxslt/Makefile.am index 173d626..44dc34d 100644 --- a/libxslt/Makefile.am +++ b/libxslt/Makefile.am @@ -6,6 +6,8 @@ lib_LTLIBRARIES = libxslt.la libxslt_la_SOURCES = \ xslt.c \ xslt.h \ + pattern.c \ + pattern.h \ xsltInternals.h diff --git a/libxslt/pattern.c b/libxslt/pattern.c new file mode 100644 index 0000000..df52c48 --- /dev/null +++ b/libxslt/pattern.c @@ -0,0 +1,408 @@ +/* + * pattern.c: Implemetation of the template match compilation and lookup + * + * Reference: + * http://www.w3.org/TR/1999/REC-xslt-19991116 + * + * See Copyright for the status of this software. + * + * Daniel.Veillard@imag.fr + */ + +#include "xsltconfig.h" + +#include + +#include +#include +#include +#include +#include +#include "xslt.h" +#include "xsltInternals.h" + +#define DEBUG_PARSING + +/* + * To cleanup + */ +xmlChar *xmlSplitQName2(const xmlChar *name, xmlChar **prefix); + +/* + * There is no XSLT specific error reporting module yet + */ +#define xsltGenericError xmlGenericError +#define xsltGenericErrorContext xmlGenericErrorContext + +/* + * Types are private: + */ + +typedef enum { + XSLT_OP_END=0, + XSLT_OP_ROOT, + XSLT_OP_ELEM, + XSLT_OP_CHILD, + XSLT_OP_ATTR, + XSLT_OP_PARENT, + XSLT_OP_ANCESTOR, + XSLT_OP_ID, + XSLT_OP_KEY, + XSLT_OP_NS, + XSLT_OP_ALL, + XSLT_OP_PREDICATE +} xsltOp; + +typedef union _xsltStepOp xsltStepOp; +typedef xsltStepOp *xsltStepOpPtr; +union _xsltStepOp { + xsltOp op; + xmlChar *value; +}; + +typedef struct _xsltCompMatch xsltCompMatch; +typedef xsltCompMatch *xsltCompMatchPtr; +struct _xsltCompMatch { + struct _xsltCompMatch *next; /* siblings in the name hash */ + int priority; /* the priority */ + + /* TODO fix the statically allocated size */ + int nbStep; + int maxStep; + xsltStepOp steps[20]; /* ops for computation */ +}; + + +/************************************************************************ + * * + * Type functions * + * * + ************************************************************************/ + +/** + * xsltNewCompMatch: + * + * Create a new XSLT CompMatch + * + * Returns the newly allocated xsltCompMatchPtr or NULL in case of error + */ +xsltCompMatchPtr +xsltNewCompMatch(void) { + xsltCompMatchPtr cur; + + cur = (xsltCompMatchPtr) xmlMalloc(sizeof(xsltCompMatch)); + if (cur == NULL) { + xsltGenericError(xsltGenericErrorContext, + "xsltNewCompMatch : malloc failed\n"); + return(NULL); + } + memset(cur, 0, sizeof(xsltCompMatch)); + cur->maxStep = 20; + return(cur); +} + +/** + * xsltFreeCompMatch: + * @comp: an XSLT comp + * + * Free up the memory allocated by @comp + */ +void +xsltFreeCompMatch(xsltCompMatchPtr comp) { + if (comp == NULL) + return; + memset(comp, -1, sizeof(xsltCompMatch)); + xmlFree(comp); +} + +/** + * xsltFreeCompMatchList: + * @comp: an XSLT comp list + * + * Free up the memory allocated by all the elements of @comp + */ +void +xsltFreeCompMatchList(xsltCompMatchPtr comp) { + xsltCompMatchPtr cur; + + while (comp != NULL) { + cur = comp; + comp = comp->next; + xsltFreeCompMatch(cur); + } +} + +/** + * xsltCompMatchAddOp: + * @comp: the compiled match expression + * @op: an op + * + * Add an step to an XSLT Compiled Match + * + * Returns -1 in case of failure, 0 otherwise. + */ +int +xsltCompMatchAddOp(xsltCompMatchPtr comp, xsltOp op) { + if (comp->nbStep >= 20) { + xsltGenericError(xsltGenericErrorContext, + "xsltCompMatchAddOp: overflow\n"); + return(-1); + } + comp->steps[comp->nbStep++].op = op; + return(0); +} + +/** + * xsltCompMatchAddValue: + * @comp: the compiled match expression + * @val: a name + * + * Add an step to an XSLT Compiled Match + * + * Returns -1 in case of failure, 0 otherwise. + */ +int +xsltCompMatchAddValue(xsltCompMatchPtr comp, xmlChar *val) { + if (comp->nbStep >= 20) { + xsltGenericError(xsltGenericErrorContext, + "xsltCompMatchAddOp: overflow\n"); + return(-1); + } + comp->steps[comp->nbStep++].value = val; + return(0); +} + +/** + * xsltReverseCompMatch: + * @comp: the compiled match expression + * + * reverse all the stack of expressions + */ +void +xsltReverseCompMatch(xsltCompMatchPtr comp) { + int i = 0; + int j = comp->nbStep - 1; + + while (j > i) { + register xmlChar *tmp; + tmp = comp->steps[i].value; + comp->steps[i].value = comp->steps[j].value; + comp->steps[j].value = tmp; + j--; + i++; + } + comp->steps[comp->nbStep].op = XSLT_OP_END; +} + +/************************************************************************ + * * + * Dedicated parser for templates * + * * + ************************************************************************/ + +#define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \ + ((c) == 0x0D)) + +#define SKIP_BLANKS while (IS_BLANK(*cur)) cur++; + +#define CUR (*(cur)) +#define NXT (*(cur + 1)) +#define NEXT cur++ + +#define PUSH(comp, step) \ + if (xsltCompMatchAddOp((comp), (xsltOp) step)) goto error; + +#define PUSHSTR(comp, step) \ + if (xsltCompMatchAddValue((comp), (xmlChar *) step)) goto error; + +/* + * Compile the XSLT LocationPathPattern + * [2] LocationPathPattern ::= '/' RelativePathPattern? + * | IdKeyPattern (('/' | '//') RelativePathPattern)? + * | '//'? RelativePathPattern + * [3] IdKeyPattern ::= 'id' '(' Literal ')' + * | 'key' '(' Literal ',' Literal ')' + * [4] RelativePathPattern ::= StepPattern + * | RelativePathPattern '/' StepPattern + * | RelativePathPattern '//' StepPattern + * [5] StepPattern ::= ChildOrAttributeAxisSpecifier NodeTest Predicate* + * [6] ChildOrAttributeAxisSpecifier ::= AbbreviatedAxisSpecifier + * | ('child' | 'attribute') '::' + */ + +/** + * xsltCompilePattern: + * @pattern an XSLT pattern + * + * Compile the XSLT pattern and generates a precompiled form suitable + * for fast matching. + * + * [1] Pattern ::= LocationPathPattern | Pattern '|' LocationPathPattern + * Returns the generated xsltCompMatchPtr or NULL in case of failure + */ + +xsltCompMatchPtr +xsltCompilePattern(const xmlChar *pattern) { + xsltCompMatchPtr ret; + const xmlChar *cur; + + if (pattern == NULL) { + xsltGenericError(xsltGenericErrorContext, + "xsltCompilePattern : NULL pattern\n"); + return(NULL); + } + +#ifdef DEBUG_PARSING + xsltGenericError(xsltGenericErrorContext, + "xsltCompilePattern : parsing '%s'\n", pattern); +#endif + + cur = pattern; + SKIP_BLANKS; + if (*cur == 0) { + xsltGenericError(xsltGenericErrorContext, + "xsltCompilePattern : NULL pattern\n"); + return(NULL); + } + ret = xsltNewCompMatch(); + if (ret == NULL) + return(NULL); + + if ((CUR == '/') && (NXT == '/')) { + } else if (CUR == '/') { + PUSH(ret, XSLT_OP_ROOT); + } + + /* + * Reverse for faster interpretation. + */ + xsltReverseCompMatch(ret); + + return(ret); + +error: + xsltFreeCompMatch(ret); + return(NULL); + +} + + +/************************************************************************ + * * + * Module interfaces * + * * + ************************************************************************/ + +/** + * xsltAddTemplate: + * @style: an XSLT stylesheet + * @cur: an XSLT template + * + * Register the XSLT pattern associated to @cur + * + * Returns -1 in case of error, 0 otherwise + */ +int +xsltAddTemplate(xsltStylesheetPtr style, xsltTemplatePtr cur) { + xsltCompMatchPtr pat, list; + const xmlChar *name; + + /* + * get a compiled form of the pattern + */ + /* TODO : handle | in patterns as multple pat !!! */ + pat = xsltCompilePattern(cur->match); + if (pat == NULL) + return(-1); + if (cur->priority != XSLT_PAT_NO_PRIORITY) + pat->priority = cur->priority; + + /* + * insert it in the hash table list corresponding to its lookup name + */ + switch (pat->steps[0].op) { + case XSLT_OP_ELEM: + case XSLT_OP_CHILD: + case XSLT_OP_ATTR: + case XSLT_OP_PARENT: + case XSLT_OP_ANCESTOR: + case XSLT_OP_ID: + case XSLT_OP_KEY: + case XSLT_OP_NS: + name = pat->steps[1].value; + break; + case XSLT_OP_ROOT: + name = (const xmlChar *) "/"; + break; + case XSLT_OP_ALL: + name = (const xmlChar *) "*"; + break; + case XSLT_OP_END: + case XSLT_OP_PREDICATE: + xsltGenericError(xsltGenericErrorContext, + "xsltAddTemplate: invalid compiled pattern\n"); + xsltFreeCompMatch(pat); + return(-1); + } + if (style->templatesHash == NULL) { + style->templatesHash = xmlHashCreate(0); + if (style->templatesHash == NULL) { + xsltFreeCompMatch(pat); + return(-1); + } +#ifdef DEBUG_PARSING + xsltGenericError(xsltGenericErrorContext, + "xsltAddTemplate: created template hash\n"); +#endif + xmlHashAddEntry(style->templatesHash, name, pat); +#ifdef DEBUG_PARSING + xsltGenericError(xsltGenericErrorContext, + "xsltAddTemplate: added new hash %s\n", name); +#endif + } else { + list = (xsltCompMatchPtr) xmlHashLookup(style->templatesHash, name); + if (list == NULL) { + xmlHashAddEntry(style->templatesHash, name, pat); +#ifdef DEBUG_PARSING + xsltGenericError(xsltGenericErrorContext, + "xsltAddTemplate: added new hash %s\n", name); +#endif + } else { + /* + * Note '<=' since one must choose among the matching template + * rules that are left, the one that occurs last in the stylesheet + */ + if (list->priority <= pat->priority) { + pat->next = list; + xmlHashAddEntry(style->templatesHash, name, pat); +#ifdef DEBUG_PARSING + xsltGenericError(xsltGenericErrorContext, + "xsltAddTemplate: added head hash for %s\n", name); +#endif + } else { + while (list->next != NULL) { + if (list->next->priority < pat->priority) + break; + } + pat->next = list->next; + list->next = pat; + } + } + } + return(0); +} + +/** + * xsltAddTemplate: + * @style: an XSLT stylesheet + * @node: an XML Node + * + * Finds the template applying to this node + * + * Returns the xsltTemplatePtr or NULL if not found + */ +xsltTemplatePtr +xsltGetTemplate(xsltStylesheetPtr style, xmlNodePtr node) { + return(NULL); +} + diff --git a/libxslt/pattern.h b/libxslt/pattern.h new file mode 100644 index 0000000..5c79c4c --- /dev/null +++ b/libxslt/pattern.h @@ -0,0 +1,28 @@ +/* + * pattern.h: interface for the pattern matching used in template matches. + * + * See Copyright for the status of this software. + * + * Daniel.Veillard@imag.fr + */ + +#ifndef __XML_XSLT_PATTERN_H__ +#define __XML_XSLT_H__ + +#include "xsltInternals.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int xsltAddTemplate (xsltStylesheetPtr style, + xsltTemplatePtr cur); +xsltTemplatePtr xsltGetTemplate (xsltStylesheetPtr style, + xmlNodePtr node); + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_H__ */ + diff --git a/libxslt/xslt.c b/libxslt/xslt.c index f4886be..b7e4e2c 100644 --- a/libxslt/xslt.c +++ b/libxslt/xslt.c @@ -1,5 +1,5 @@ /* - * xslt.h: Implemetation of an XSL Transformation 1.0 engine + * xslt.c: Implemetation of an XSL Transformation 1.0 engine * * Reference: * http://www.w3.org/TR/1999/REC-xslt-19991116 @@ -16,13 +16,21 @@ #include #include #include +#include +#include #include #include "xslt.h" #include "xsltInternals.h" +#include "pattern.h" #define DEBUG_PARSING /* + * To cleanup + */ +xmlChar *xmlSplitQName2(const xmlChar *name, xmlChar **prefix); + +/* * There is no XSLT specific error reporting module yet */ #define xsltGenericError xmlGenericError @@ -33,7 +41,10 @@ */ #define IS_XSLT_ELEM(n) \ - ((n)->ns != NULL) && (xmlStrEqual(cur->ns->href, XSLT_NAMESPACE)) + ((n)->ns != NULL) && (xmlStrEqual((n)->ns->href, XSLT_NAMESPACE)) + +#define IS_XSLT_NAME(n, val) \ + (xmlStrEqual((n)->name, (const xmlChar *) (val))) #define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \ ((c) == 0x0D)) @@ -98,6 +109,7 @@ xsltNewTemplate(void) { return(NULL); } memset(cur, 0, sizeof(xsltTemplate)); + cur->priority = XSLT_PAT_NO_PRIORITY; return(cur); } @@ -150,6 +162,9 @@ xsltNewStylesheet(void) { return(NULL); } memset(cur, 0, sizeof(xsltStylesheet)); + cur->omitXmlDeclaration = -1; + cur->standalone = -1; + cur->indent = -1; return(cur); } @@ -166,6 +181,17 @@ xsltFreeStylesheet(xsltStylesheetPtr sheet) { xsltFreeTemplateList(sheet->templates); if (sheet->doc != NULL) xmlFreeDoc(sheet->doc); + if (sheet->stripSpaces != NULL) + xmlHashFree(sheet->stripSpaces, NULL); + + if (sheet->method != NULL) xmlFree(sheet->method); + if (sheet->methodURI != NULL) xmlFree(sheet->methodURI); + if (sheet->version != NULL) xmlFree(sheet->version); + if (sheet->encoding != NULL) xmlFree(sheet->encoding); + if (sheet->doctypePublic != NULL) xmlFree(sheet->doctypePublic); + if (sheet->doctypeSystem != NULL) xmlFree(sheet->doctypeSystem); + if (sheet->mediaType != NULL) xmlFree(sheet->mediaType); + memset(sheet, -1, sizeof(xsltStylesheet)); xmlFree(sheet); } @@ -177,32 +203,339 @@ xsltFreeStylesheet(xsltStylesheetPtr sheet) { ************************************************************************/ /** + * xsltParseStylesheetOutput: + * @style: the XSLT stylesheet + * @template: the "output" element + * + * parse an XSLT stylesheet output element and record + * information related to the stylesheet output + */ + +void +xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur) { + xmlChar *elements, *prop; + xmlChar *element, *end; + + if ((cur == NULL) || (style == NULL)) + return; + + prop = xmlGetNsProp(cur, (const xmlChar *)"version", XSLT_NAMESPACE); + if (prop != NULL) { + if (style->version != NULL) xmlFree(style->version); + style->version = prop; + } + + prop = xmlGetNsProp(cur, (const xmlChar *)"encoding", XSLT_NAMESPACE); + if (prop != NULL) { + if (style->encoding != NULL) xmlFree(style->encoding); + style->encoding = prop; + } + + prop = xmlGetNsProp(cur, (const xmlChar *)"method", XSLT_NAMESPACE); + if (prop != NULL) { + xmlChar *ncname; + xmlChar *prefix = NULL; + + if (style->method != NULL) xmlFree(style->method); + style->method = NULL; + if (style->methodURI != NULL) xmlFree(style->methodURI); + style->methodURI = 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); + style->method = prop; + } else { + style->methodURI = xmlStrdup(ns->href); + style->method = ncname; + xmlFree(prefix); + xmlFree(prop); + } + } else { + style->method = ncname; + xmlFree(prop); + } + } else { + if ((xmlStrEqual(prop, (const xmlChar *)"xml")) || + (xmlStrEqual(prop, (const xmlChar *)"html")) || + (xmlStrEqual(prop, (const xmlChar *)"text"))) { + style->method = prop; + } else { + xsltGenericError(xsltGenericErrorContext, + "invalid value for method: %s\n", prop); + } + } + } + + prop = xmlGetNsProp(cur, (const xmlChar *)"doctype-system", XSLT_NAMESPACE); + if (prop != NULL) { + if (style->doctypeSystem != NULL) xmlFree(style->doctypeSystem); + style->doctypeSystem = prop; + } + + prop = xmlGetNsProp(cur, (const xmlChar *)"doctype-public", XSLT_NAMESPACE); + if (prop != NULL) { + if (style->doctypePublic != NULL) xmlFree(style->doctypePublic); + style->doctypePublic = prop; + } + + prop = xmlGetNsProp(cur, (const xmlChar *)"standalone", + XSLT_NAMESPACE); + if (prop != NULL) { + if (xmlStrEqual(prop, (const xmlChar *)"yes")) { + style->standalone = 1; + } else if (xmlStrEqual(prop, (const xmlChar *)"no")) { + style->standalone = 0; + } else { + xsltGenericError(xsltGenericErrorContext, + "invalid value for standalone: %s\n", prop); + } + xmlFree(prop); + } + + prop = xmlGetNsProp(cur, (const xmlChar *)"indent", + XSLT_NAMESPACE); + if (prop != NULL) { + if (xmlStrEqual(prop, (const xmlChar *)"yes")) { + style->indent = 1; + } else if (xmlStrEqual(prop, (const xmlChar *)"no")) { + style->indent = 0; + } else { + xsltGenericError(xsltGenericErrorContext, + "invalid value for indent: %s\n", prop); + } + xmlFree(prop); + } + + prop = xmlGetNsProp(cur, (const xmlChar *)"omit-xml-declaration", + XSLT_NAMESPACE); + if (prop != NULL) { + if (xmlStrEqual(prop, (const xmlChar *)"yes")) { + style->omitXmlDeclaration = 1; + } else if (xmlStrEqual(prop, (const xmlChar *)"no")) { + style->omitXmlDeclaration = 0; + } else { + xsltGenericError(xsltGenericErrorContext, + "invalid value for omit-xml-declaration: %s\n", prop); + } + xmlFree(prop); + } + + elements = xmlGetNsProp(cur, (const xmlChar *)"cdata-section-elements", + XSLT_NAMESPACE); + if (elements != NULL) { + if (style->stripSpaces == NULL) + style->stripSpaces = xmlHashCreate(10); + if (style->stripSpaces == NULL) + return; + + element = elements; + while (*element != 0) { + while (IS_BLANK(*element)) element++; + if (*element == 0) + break; + end = element; + while ((*end != 0) && (!IS_BLANK(*end))) end++; + element = xmlStrndup(element, end - element); + if (element) { +#ifdef DEBUG_PARSING + xsltGenericError(xsltGenericErrorContext, + "add cdata section output element %s\n", element); +#endif + xmlHashAddEntry(style->stripSpaces, element, "cdata"); + xmlFree(element); + } + element = end; + } + xmlFree(elements); + } +} + +/** + * xsltParseStylesheetPreserveSpace: + * @style: the XSLT stylesheet + * @template: the "preserve-space" element + * + * parse an XSLT stylesheet preserve-space element and record + * elements needing preserving + */ + +void +xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style, xmlNodePtr cur) { + xmlChar *elements; + xmlChar *element, *end; + + if ((cur == NULL) || (style == NULL)) + return; + + elements = xmlGetNsProp(cur, (const xmlChar *)"elements", XSLT_NAMESPACE); + if (elements == NULL) { + xsltGenericError(xsltGenericErrorContext, + "xsltParseStylesheetPreserveSpace: missing elements attribute\n"); + return; + } + + if (style->stripSpaces == NULL) + style->stripSpaces = xmlHashCreate(10); + if (style->stripSpaces == NULL) + return; + + element = elements; + while (*element != 0) { + while (IS_BLANK(*element)) element++; + if (*element == 0) + break; + end = element; + while ((*end != 0) && (!IS_BLANK(*end))) end++; + element = xmlStrndup(element, end - element); + if (element) { +#ifdef DEBUG_PARSING + xsltGenericError(xsltGenericErrorContext, + "add preserved space element %s\n", element); +#endif + xmlHashAddEntry(style->stripSpaces, element, "preserve"); + xmlFree(element); + } + element = end; + } + xmlFree(elements); +} + +/** + * xsltParseStylesheetStripSpace: + * @style: the XSLT stylesheet + * @template: the "strip-space" element + * + * parse an XSLT stylesheet strip-space element and record + * elements needing stripping + */ + +void +xsltParseStylesheetStripSpace(xsltStylesheetPtr style, xmlNodePtr cur) { + xmlChar *elements; + xmlChar *element, *end; + + if ((cur == NULL) || (style == NULL)) + return; + + elements = xmlGetNsProp(cur, (const xmlChar *)"elements", XSLT_NAMESPACE); + if (elements == NULL) { + xsltGenericError(xsltGenericErrorContext, + "xsltParseStylesheetStripSpace: missing elements attribute\n"); + return; + } + + if (style->stripSpaces == NULL) + style->stripSpaces = xmlHashCreate(10); + if (style->stripSpaces == NULL) + return; + + element = elements; + while (*element != 0) { + while (IS_BLANK(*element)) element++; + if (*element == 0) + break; + end = element; + while ((*end != 0) && (!IS_BLANK(*end))) end++; + element = xmlStrndup(element, end - element); + if (element) { +#ifdef DEBUG_PARSING + xsltGenericError(xsltGenericErrorContext, + "add stripped space element %s\n", element); +#endif + xmlHashAddEntry(style->stripSpaces, element, "strip"); + xmlFree(element); + } + element = end; + } + xmlFree(elements); +} + +/** * xsltParseStylesheetTemplate: * @style: the XSLT stylesheet * @template: the "template" element * - * parse an XSLT stylesheet building the associated structures + * parse an XSLT stylesheet template building the associated structures */ void xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) { xsltTemplatePtr ret; xmlNodePtr cur; + xmlChar *prop; if (template == NULL) return; + + /* + * Create and link the structure + */ ret = xsltNewTemplate(); if (ret == NULL) return; ret->next = style->templates; style->templates = ret; - cur = template->children; + /* + * 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; + } + } /* * Find and handle the params */ + cur = template->children; while (cur != NULL) { /* * Remove Blank nodes found at this level. @@ -215,7 +548,7 @@ xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) { xmlFreeNode(blank); continue; } - if ((IS_XSLT_ELEM(cur)) && (xmlStrEqual(cur->name, "param"))) { + if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) { TODO /* Handle param */ } else break; @@ -237,7 +570,7 @@ xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) { xmlFreeNode(blank); continue; } - if ((IS_XSLT_ELEM(cur)) && (xmlStrEqual(cur->name, "param"))) { + if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) { xmlNodePtr param = cur; cur = cur->next; @@ -252,6 +585,11 @@ xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) { } ret->content = template->children; + + /* + * Register pattern + */ + xsltAddTemplate(style, ret); } /** @@ -265,6 +603,9 @@ xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) { void xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) { xmlNodePtr cur; +#ifdef DEBUG_PARSING + int templates = 0; +#endif if (top == NULL) return; @@ -284,7 +625,7 @@ xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) { cur = cur->next; continue; } - if (xmlStrEqual(cur->name, "import")) { + if (IS_XSLT_NAME(cur, "import")) { TODO /* Handle import */ } else break; @@ -304,30 +645,33 @@ xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) { cur = cur->next; continue; } - if (xmlStrEqual(cur->name, "import")) { + if (IS_XSLT_NAME(cur, "import")) { xsltGenericError(xsltGenericErrorContext, "xsltParseStylesheetTop: ignoring misplaced import element\n"); - } else if (xmlStrEqual(cur->name, "include")) { + } else if (IS_XSLT_NAME(cur, "include")) { TODO /* Handle include */ - } else if (xmlStrEqual(cur->name, "strip-space")) { - TODO /* Handle strip-space */ - } else if (xmlStrEqual(cur->name, "preserve-space")) { - TODO /* Handle preserve-space */ - } else if (xmlStrEqual(cur->name, "output")) { - TODO /* Handle output */ - } else if (xmlStrEqual(cur->name, "key")) { + } else if (IS_XSLT_NAME(cur, "strip-space")) { + xsltParseStylesheetStripSpace(style, cur); + } else if (IS_XSLT_NAME(cur, "preserve-space")) { + xsltParseStylesheetPreserveSpace(style, cur); + } else if (IS_XSLT_NAME(cur, "output")) { + xsltParseStylesheetOutput(style, cur); + } else if (IS_XSLT_NAME(cur, "key")) { TODO /* Handle key */ - } else if (xmlStrEqual(cur->name, "decimal-format")) { + } else if (IS_XSLT_NAME(cur, "decimal-format")) { TODO /* Handle decimal-format */ - } else if (xmlStrEqual(cur->name, "attribute-set")) { + } else if (IS_XSLT_NAME(cur, "attribute-set")) { TODO /* Handle attribute-set */ - } else if (xmlStrEqual(cur->name, "variable")) { + } else if (IS_XSLT_NAME(cur, "variable")) { TODO /* Handle variable */ - } else if (xmlStrEqual(cur->name, "param")) { + } else if (IS_XSLT_NAME(cur, "param")) { TODO /* Handle param */ - } else if (xmlStrEqual(cur->name, "template")) { + } else if (IS_XSLT_NAME(cur, "template")) { +#ifdef DEBUG_PARSING + templates++; +#endif xsltParseStylesheetTemplate(style, cur); - } else if (xmlStrEqual(cur->name, "namespace-alias")) { + } else if (IS_XSLT_NAME(cur, "namespace-alias")) { TODO /* Handle namespace-alias */ } else { xsltGenericError(xsltGenericErrorContext, @@ -336,6 +680,10 @@ xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) { } cur = cur->next; } +#ifdef DEBUG_PARSING + xsltGenericError(xsltGenericErrorContext, + "parsed %d templates\n", templates); +#endif } /** @@ -371,7 +719,7 @@ xsltParseStylesheetDoc(xmlDocPtr doc) { return(NULL); } - if ((IS_XSLT_ELEM(cur)) && (xmlStrEqual(cur->name, "stylesheet"))) { + if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "stylesheet"))) { #ifdef DEBUG_PARSING xsltGenericError(xsltGenericErrorContext, "xsltParseStylesheetDoc : found stylesheet\n"); @@ -414,7 +762,7 @@ xsltParseStylesheetFile(const xmlChar* filename) { "xsltParseStylesheetFile : parse %s\n", filename); #endif - doc = xmlParseFile(filename); + doc = xmlParseFile((const char *) filename); if (doc == NULL) { xsltGenericError(xsltGenericErrorContext, "xsltParseStylesheetFile : cannot parse %s\n", filename); diff --git a/libxslt/xslt.h b/libxslt/xslt.h index 1371dc6..02d3524 100644 --- a/libxslt/xslt.h +++ b/libxslt/xslt.h @@ -19,7 +19,7 @@ extern "C" { * Constants. */ #define XSLT_DEFAULT_VERSION "1.0" -#define XSLT_NAMESPACE "http://www.w3.org/1999/XSL/Transform" +#define XSLT_NAMESPACE ((xmlChar *) "http://www.w3.org/1999/XSL/Transform") #ifdef __cplusplus } diff --git a/libxslt/xsltInternals.h b/libxslt/xsltInternals.h index 8d28b48..d698499 100644 --- a/libxslt/xsltInternals.h +++ b/libxslt/xsltInternals.h @@ -23,6 +23,9 @@ extern "C" { * NOTE: most of the content is simply linked from the doc tree * structure, no specific allocation is made. */ + +#define XSLT_PAT_NO_PRIORITY -12345789 + typedef struct _xsltTemplate xsltTemplate; typedef xsltTemplate *xsltTemplatePtr; struct _xsltTemplate { @@ -43,7 +46,29 @@ typedef struct _xsltStylesheet xsltStylesheet; typedef xsltStylesheet *xsltStylesheetPtr; struct _xsltStylesheet { xmlDocPtr doc; /* the parsed XML stylesheet */ + xmlHashTablePtr stripSpaces;/* the hash table of the strip-space + preserve space and cdata-section elements */ + + /* + * Template descriptions + */ xsltTemplatePtr templates; /* the ordered list of templates */ + void *templatesHash; /* hash table or wherever compiled templates + informations are stored */ + + /* + * Output related stuff. + */ + xmlChar *method; /* the output method */ + xmlChar *methodURI; /* associated namespace if any */ + xmlChar *version; /* version string */ + xmlChar *encoding; /* encoding string */ + int omitXmlDeclaration; /* omit-xml-declaration = "yes" | "no" */ + int standalone; /* standalone = "yes" | "no" */ + xmlChar *doctypePublic; /* doctype-public string */ + xmlChar *doctypeSystem; /* doctype-system string */ + int indent; /* should output being indented */ + xmlChar *mediaType; /* media-type string */ }; -- 2.7.4