/* * 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. * * [email protected] */ /* * TODO: handle pathological cases like *[*[@a="b"]] * TODO: detect [number] at compilation, optimize accordingly */ #define IN_LIBXSLT #include "libxslt.h" #include <string.h> #include <libxml/xmlmemory.h> #include <libxml/tree.h> #include <libxml/valid.h> #include <libxml/hash.h> #include <libxml/xmlerror.h> #include <libxml/parserInternals.h> #include <libxml/xpath.h> #include "xslt.h" #include "xsltInternals.h" #include "xsltutils.h" #include "imports.h" #include "templates.h" #include "keys.h" #include "pattern.h" #include "documents.h" #ifdef WITH_XSLT_DEBUG #define WITH_XSLT_DEBUG_PATTERN #endif /* * Types are private: */ xsltOp; xsltAxis; xsltStepState; xsltStepStatePtr; struct _xsltStepState { … }; xsltStepStates; xsltStepStatesPtr; struct _xsltStepStates { … }; xsltStepOp; xsltStepOpPtr; struct _xsltStepOp { … }; struct _xsltCompMatch { … }; xsltParserContext; xsltParserContextPtr; struct _xsltParserContext { … }; /************************************************************************ * * * Type functions * * * ************************************************************************/ /** * xsltNewCompMatch: * * Create a new XSLT CompMatch * * Returns the newly allocated xsltCompMatchPtr or NULL in case of error */ static xsltCompMatchPtr xsltNewCompMatch(void) { … } /** * xsltFreeCompMatch: * @comp: an XSLT comp * * Free up the memory allocated by @comp */ static void xsltFreeCompMatch(xsltCompMatchPtr comp) { … } /** * xsltFreeCompMatchList: * @comp: an XSLT comp list * * Free up the memory allocated by all the elements of @comp */ void xsltFreeCompMatchList(xsltCompMatchPtr comp) { … } static void xsltFreeCompMatchListEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { … } /** * xsltNormalizeCompSteps: * @payload: pointer to template hash table entry * @data: pointer to the stylesheet * @name: template match name * * This is a hashtable scanner function to normalize the compiled * steps of an imported stylesheet. */ void xsltNormalizeCompSteps(void *payload, void *data, const xmlChar *name ATTRIBUTE_UNUSED) { … } /** * xsltNewParserContext: * @style: the stylesheet * @ctxt: the transformation context, if done at run-time * * Create a new XSLT ParserContext * * Returns the newly allocated xsltParserContextPtr or NULL in case of error */ static xsltParserContextPtr xsltNewParserContext(xsltStylesheetPtr style, xsltTransformContextPtr ctxt) { … } /** * xsltFreeParserContext: * @ctxt: an XSLT parser context * * Free up the memory allocated by @ctxt */ static void xsltFreeParserContext(xsltParserContextPtr ctxt) { … } /** * xsltCompMatchAdd: * @comp: the compiled match expression * @op: an op * @value: the first value * @value2: the second value * @novar: flag to set XML_XPATH_NOVAR * * Add an step to an XSLT Compiled Match * * Returns -1 in case of failure, 0 otherwise. */ static int xsltCompMatchAdd(xsltParserContextPtr ctxt, xsltCompMatchPtr comp, xsltOp op, xmlChar * value, xmlChar * value2, int novar) { … } /** * xsltSwapTopCompMatch: * @comp: the compiled match expression * * reverse the two top steps. */ static void xsltSwapTopCompMatch(xsltCompMatchPtr comp) { … } /** * xsltReverseCompMatch: * @ctxt: the parser context * @comp: the compiled match expression * * reverse all the stack of expressions */ static void xsltReverseCompMatch(xsltParserContextPtr ctxt, xsltCompMatchPtr comp) { … } /************************************************************************ * * * The interpreter for the precompiled patterns * * * ************************************************************************/ static int xsltPatPushState(xsltTransformContextPtr ctxt, xsltStepStates *states, int step, xmlNodePtr node) { … } static void xmlXPathFreeObjectWrapper(void *obj) { … } /** * xsltTestCompMatchDirect: * @ctxt: a XSLT process context * @comp: the precompiled pattern * @node: a node * @nsList: the namespaces in scope * @nsNr: the number of namespaces in scope * * Test whether the node matches the pattern, do a direct evalutation * and not a step by step evaluation. * * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure */ static int xsltTestCompMatchDirect(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp, xmlNodePtr node, xmlNsPtr *nsList, int nsNr) { … } /** * xsltTestStepMatch: * @ctxt: a XSLT process context * @node: a node * @step: the step * * Test whether the node matches the step. * * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure */ static int xsltTestStepMatch(xsltTransformContextPtr ctxt, xmlNodePtr node, xsltStepOpPtr step) { … } /** * xsltTestPredicateMatch: * @ctxt: a XSLT process context * @comp: the precompiled pattern * @node: a node * @step: the predicate step * @sel: the previous step * * Test whether the node matches the predicate * * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure */ static int xsltTestPredicateMatch(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp, xmlNodePtr node, xsltStepOpPtr step, xsltStepOpPtr sel) { … } /** * xsltTestCompMatch: * @ctxt: a XSLT process context * @comp: the precompiled pattern * @node: a node * @mode: the mode name or NULL * @modeURI: the mode URI or NULL * * Test whether the node matches the pattern * * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure */ static int xsltTestCompMatch(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp, xmlNodePtr matchNode, const xmlChar *mode, const xmlChar *modeURI) { … } /** * xsltTestCompMatchList: * @ctxt: a XSLT process context * @node: a node * @comp: the precompiled pattern list * * Test whether the node matches one of the patterns in the list * * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure */ int xsltTestCompMatchList(xsltTransformContextPtr ctxt, xmlNodePtr node, xsltCompMatchPtr comp) { … } /** * xsltCompMatchClearCache: * @ctxt: a XSLT process context * @comp: the precompiled pattern list * * Clear pattern match cache. */ void xsltCompMatchClearCache(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp) { … } /************************************************************************ * * * Dedicated parser for templates * * * ************************************************************************/ #define CUR … #define SKIP(val) … #define NXT(val) … #define CUR_PTR … #define SKIP_BLANKS … #define CURRENT … #define NEXT … #define PUSH(op, val, val2, novar) … #define SWAP() … #define XSLT_ERROR(X) … #define XSLT_ERROR0(X) … /** * xsltScanLiteral: * @ctxt: the XPath Parser context * * Parse an XPath Litteral: * * [29] Literal ::= '"' [^"]* '"' * | "'" [^']* "'" * * Returns the Literal parsed or NULL */ static xmlChar * xsltScanLiteral(xsltParserContextPtr ctxt) { … } /** * xsltScanNCName: * @ctxt: the XPath Parser context * * Parses a non qualified name * * Returns the Name parsed or NULL */ static xmlChar * xsltScanNCName(xsltParserContextPtr ctxt) { … } /* * xsltCompileIdKeyPattern: * @ctxt: the compilation context * @name: a preparsed name * @aid: whether id/key are allowed there * @novar: flag to prohibit xslt var * * Compile the XSLT LocationIdKeyPattern * [3] IdKeyPattern ::= 'id' '(' Literal ')' * | 'key' '(' Literal ',' Literal ')' * * also handle NodeType and PI from: * * [7] NodeTest ::= NameTest * | NodeType '(' ')' * | 'processing-instruction' '(' Literal ')' */ static void xsltCompileIdKeyPattern(xsltParserContextPtr ctxt, xmlChar *name, int aid, int novar, xsltAxis axis) { … } /** * xsltCompileStepPattern: * @ctxt: the compilation context * @token: a posible precompiled name * @novar: flag to prohibit xslt variables from pattern * * Compile the XSLT StepPattern and generates a precompiled * form suitable for fast matching. * * [5] StepPattern ::= ChildOrAttributeAxisSpecifier NodeTest Predicate* * [6] ChildOrAttributeAxisSpecifier ::= AbbreviatedAxisSpecifier * | ('child' | 'attribute') '::' * from XPath * [7] NodeTest ::= NameTest * | NodeType '(' ')' * | 'processing-instruction' '(' Literal ')' * [8] Predicate ::= '[' PredicateExpr ']' * [9] PredicateExpr ::= Expr * [13] AbbreviatedAxisSpecifier ::= '@'? * [37] NameTest ::= '*' | NCName ':' '*' | QName */ static void xsltCompileStepPattern(xsltParserContextPtr ctxt, xmlChar *token, int novar) { … } /** * xsltCompileRelativePathPattern: * @comp: the compilation context * @token: a posible precompiled name * @novar: flag to prohibit xslt variables * * Compile the XSLT RelativePathPattern and generates a precompiled * form suitable for fast matching. * * [4] RelativePathPattern ::= StepPattern * | RelativePathPattern '/' StepPattern * | RelativePathPattern '//' StepPattern */ static void xsltCompileRelativePathPattern(xsltParserContextPtr ctxt, xmlChar *token, int novar) { … } /** * xsltCompileLocationPathPattern: * @ctxt: the compilation context * @novar: flag to prohibit xslt variables * * Compile the XSLT LocationPathPattern and generates a precompiled * form suitable for fast matching. * * [2] LocationPathPattern ::= '/' RelativePathPattern? * | IdKeyPattern (('/' | '//') RelativePathPattern)? * | '//'? RelativePathPattern */ static void xsltCompileLocationPathPattern(xsltParserContextPtr ctxt, int novar) { … } /** * xsltCompilePatternInternal: * @pattern: an XSLT pattern * @doc: the containing document * @node: the containing element * @style: the stylesheet * @runtime: the transformation context, if done at run-time * @novar: flag to prohibit xslt variables * * Compile the XSLT pattern and generates a list of precompiled form suitable * for fast matching. * * [1] Pattern ::= LocationPathPattern | Pattern '|' LocationPathPattern * * Returns the generated pattern list or NULL in case of failure */ static xsltCompMatchPtr xsltCompilePatternInternal(const xmlChar *pattern, xmlDocPtr doc, xmlNodePtr node, xsltStylesheetPtr style, xsltTransformContextPtr runtime, int novar) { … } /** * xsltCompilePattern: * @pattern: an XSLT pattern * @doc: the containing document * @node: the containing element * @style: the stylesheet * @runtime: the transformation context, if done at run-time * * Compile the XSLT pattern and generates a list of precompiled form suitable * for fast matching. * * [1] Pattern ::= LocationPathPattern | Pattern '|' LocationPathPattern * * Returns the generated pattern list or NULL in case of failure */ xsltCompMatchPtr xsltCompilePattern(const xmlChar *pattern, xmlDocPtr doc, xmlNodePtr node, xsltStylesheetPtr style, xsltTransformContextPtr runtime) { … } /************************************************************************ * * * Module interfaces * * * ************************************************************************/ /** * xsltAddTemplate: * @style: an XSLT stylesheet * @cur: an XSLT template * @mode: the mode name or NULL * @modeURI: the mode URI or NULL * * Register the XSLT pattern associated to @cur * * Returns -1 in case of error, 0 otherwise */ int xsltAddTemplate(xsltStylesheetPtr style, xsltTemplatePtr cur, const xmlChar *mode, const xmlChar *modeURI) { … } static int xsltComputeAllKeys(xsltTransformContextPtr ctxt, xmlNodePtr contextNode) { … } /** * xsltGetTemplate: * @ctxt: a XSLT process context * @node: the node being processed * @style: the current style * * Finds the template applying to this node, if @style is non-NULL * it means one needs to look for the next imported template in scope. * * Returns the xsltTemplatePtr or NULL if not found */ xsltTemplatePtr xsltGetTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node, xsltStylesheetPtr style) { … } /** * xsltCleanupTemplates: * @style: an XSLT stylesheet * * Cleanup the state of the templates used by the stylesheet and * the ones it imports. */ void xsltCleanupTemplates(xsltStylesheetPtr style ATTRIBUTE_UNUSED) { … } /** * xsltFreeTemplateHashes: * @style: an XSLT stylesheet * * Free up the memory used by xsltAddTemplate/xsltGetTemplate mechanism */ void xsltFreeTemplateHashes(xsltStylesheetPtr style) { … }