| #define IN_LIBEXSLT |
| #include "libexslt/libexslt.h" |
| |
| #if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__) |
| #include <win32config.h> |
| #else |
| #include "config.h" |
| #endif |
| |
| #include <libxml/tree.h> |
| #include <libxml/xpath.h> |
| #include <libxml/xpathInternals.h> |
| #include <libxml/parser.h> |
| #include <libxml/hash.h> |
| |
| #include <libxslt/xsltconfig.h> |
| #include <libxslt/xsltutils.h> |
| #include <libxslt/xsltInternals.h> |
| #include <libxslt/extensions.h> |
| |
| #include "exslt.h" |
| |
| /** |
| * exsltSaxonInit: |
| * @ctxt: an XSLT transformation context |
| * @URI: the namespace URI for the extension |
| * |
| * Initializes the SAXON module. |
| * |
| * Returns the data for this transformation |
| */ |
| static xmlHashTablePtr |
| exsltSaxonInit (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, |
| const xmlChar *URI ATTRIBUTE_UNUSED) { |
| return xmlHashCreate(1); |
| } |
| |
| /** |
| * exsltSaxonShutdown: |
| * @ctxt: an XSLT transformation context |
| * @URI: the namespace URI for the extension |
| * @data: the module data to free up |
| * |
| * Shutdown the SAXON extension module |
| */ |
| static void |
| exsltSaxonShutdown (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, |
| const xmlChar *URI ATTRIBUTE_UNUSED, |
| xmlHashTablePtr data) { |
| xmlHashFree(data, (xmlHashDeallocator) xmlXPathFreeCompExpr); |
| } |
| |
| |
| /** |
| * exsltSaxonExpressionFunction: |
| * @ctxt: an XPath parser context |
| * @nargs: the number of arguments |
| * |
| * The supplied string must contain an XPath expression. The result of |
| * the function is a stored expression, which may be supplied as an |
| * argument to other extension functions such as saxon:eval(), |
| * saxon:sum() and saxon:distinct(). The result of the expression will |
| * usually depend on the current node. The expression may contain |
| * references to variables that are in scope at the point where |
| * saxon:expression() is called: these variables will be replaced in |
| * the stored expression with the values they take at the time |
| * saxon:expression() is called, not the values of the variables at |
| * the time the stored expression is evaluated. Similarly, if the |
| * expression contains namespace prefixes, these are interpreted in |
| * terms of the namespace declarations in scope at the point where the |
| * saxon:expression() function is called, not those in scope where the |
| * stored expression is evaluated. |
| * |
| * TODO: current implementation doesn't conform to SAXON behaviour |
| * regarding context and namespaces. |
| */ |
| static void |
| exsltSaxonExpressionFunction (xmlXPathParserContextPtr ctxt, int nargs) { |
| xmlChar *arg; |
| xmlXPathCompExprPtr ret; |
| xmlHashTablePtr hash; |
| xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt); |
| |
| if (nargs != 1) { |
| xmlXPathSetArityError(ctxt); |
| return; |
| } |
| |
| arg = xmlXPathPopString(ctxt); |
| if (xmlXPathCheckError(ctxt) || (arg == NULL)) { |
| xmlXPathSetTypeError(ctxt); |
| return; |
| } |
| |
| hash = (xmlHashTablePtr) xsltGetExtData(tctxt, |
| ctxt->context->functionURI); |
| |
| ret = xmlHashLookup(hash, arg); |
| |
| if (ret == NULL) { |
| ret = xmlXPathCompile(arg); |
| if (ret == NULL) { |
| xmlFree(arg); |
| xsltGenericError(xsltGenericErrorContext, |
| "{%s}:%s: argument is not an XPath expression\n", |
| ctxt->context->functionURI, ctxt->context->function); |
| return; |
| } |
| xmlHashAddEntry(hash, arg, (void *) ret); |
| } |
| |
| xmlFree(arg); |
| |
| xmlXPathReturnExternal(ctxt, ret); |
| } |
| |
| /** |
| * exsltSaxonEvalFunction: |
| * @ctxt: an XPath parser context |
| * @nargs: number of arguments |
| * |
| * Implements de SAXON eval() function: |
| * object saxon:eval (saxon:stored-expression) |
| * Returns the result of evaluating the supplied stored expression. |
| * A stored expression may be obtained as the result of calling |
| * the saxon:expression() function. |
| * The stored expression is evaluated in the current context, that |
| * is, the context node is the current node, and the context position |
| * and context size are the same as the result of calling position() |
| * or last() respectively. |
| */ |
| static void |
| exsltSaxonEvalFunction (xmlXPathParserContextPtr ctxt, int nargs) { |
| xmlXPathCompExprPtr expr; |
| xmlXPathObjectPtr ret; |
| |
| if (nargs != 1) { |
| xmlXPathSetArityError(ctxt); |
| return; |
| } |
| |
| if (!xmlXPathStackIsExternal(ctxt)) { |
| xmlXPathSetTypeError(ctxt); |
| return; |
| } |
| |
| expr = (xmlXPathCompExprPtr) xmlXPathPopExternal(ctxt); |
| |
| ret = xmlXPathCompiledEval(expr, ctxt->context); |
| |
| valuePush(ctxt, ret); |
| } |
| |
| /** |
| * exsltSaxonEvaluateFunction: |
| * @ctxt: an XPath parser context |
| * @nargs: number of arguments |
| * |
| * Implements the SAXON evaluate() function |
| * object saxon:evaluate (string) |
| * The supplied string must contain an XPath expression. The result of |
| * the function is the result of evaluating the XPath expression. This |
| * is useful where an expression needs to be constructed at run-time or |
| * passed to the stylesheet as a parameter, for example where the sort |
| * key is determined dynamically. The context for the expression (e.g. |
| * which variables and namespaces are available) is exactly the same as |
| * if the expression were written explicitly at this point in the |
| * stylesheet. The function saxon:evaluate(string) is shorthand for |
| * saxon:eval(saxon:expression(string)). |
| */ |
| static void |
| exsltSaxonEvaluateFunction (xmlXPathParserContextPtr ctxt, int nargs) { |
| if (nargs != 1) { |
| xmlXPathSetArityError(ctxt); |
| return; |
| } |
| |
| exsltSaxonExpressionFunction(ctxt, 1); |
| exsltSaxonEvalFunction(ctxt, 1); |
| } |
| |
| /** |
| * exsltSaxonLineNumberFunction: |
| * @ctxt: an XPath parser context |
| * @nargs: number of arguments |
| * |
| * Implements the SAXON line-number() function |
| * integer saxon:line-number() |
| * |
| * This returns the line number of the context node in the source document |
| * within the entity that contains it. There are no arguments. If line numbers |
| * are not maintained for the current document, the function returns -1. (To |
| * ensure that line numbers are maintained, use the -l option on the command |
| * line) |
| * |
| * The extension has been extended to have the following form: |
| * integer saxon:line-number([node-set-1]) |
| * If a node-set is given, this extension will return the line number of the |
| * node in the argument node-set that is first in document order. |
| */ |
| static void |
| exsltSaxonLineNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { |
| xmlNodePtr cur = NULL; |
| |
| if (nargs == 0) { |
| cur = ctxt->context->node; |
| } else if (nargs == 1) { |
| xmlXPathObjectPtr obj; |
| xmlNodeSetPtr nodelist; |
| int i; |
| |
| if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) { |
| xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, |
| "saxon:line-number() : invalid arg expecting a node-set\n"); |
| ctxt->error = XPATH_INVALID_TYPE; |
| return; |
| } |
| |
| obj = valuePop(ctxt); |
| nodelist = obj->nodesetval; |
| if ((nodelist == NULL) || (nodelist->nodeNr <= 0)) { |
| xmlXPathFreeObject(obj); |
| valuePush(ctxt, xmlXPathNewFloat(-1)); |
| return; |
| } |
| cur = nodelist->nodeTab[0]; |
| for (i = 1;i < nodelist->nodeNr;i++) { |
| int ret = xmlXPathCmpNodes(cur, nodelist->nodeTab[i]); |
| if (ret == -1) |
| cur = nodelist->nodeTab[i]; |
| } |
| xmlXPathFreeObject(obj); |
| } else { |
| xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, |
| "saxon:line-number() : invalid number of args %d\n", |
| nargs); |
| ctxt->error = XPATH_INVALID_ARITY; |
| return; |
| } |
| |
| valuePush(ctxt, xmlXPathNewFloat(xmlGetLineNo(cur))); |
| return; |
| } |
| |
| /** |
| * exsltSaxonRegister: |
| * |
| * Registers the SAXON extension module |
| */ |
| void |
| exsltSaxonRegister (void) { |
| xsltRegisterExtModule (SAXON_NAMESPACE, |
| (xsltExtInitFunction) exsltSaxonInit, |
| (xsltExtShutdownFunction) exsltSaxonShutdown); |
| xsltRegisterExtModuleFunction((const xmlChar *) "expression", |
| SAXON_NAMESPACE, |
| exsltSaxonExpressionFunction); |
| xsltRegisterExtModuleFunction((const xmlChar *) "eval", |
| SAXON_NAMESPACE, |
| exsltSaxonEvalFunction); |
| xsltRegisterExtModuleFunction((const xmlChar *) "evaluate", |
| SAXON_NAMESPACE, |
| exsltSaxonEvaluateFunction); |
| xsltRegisterExtModuleFunction ((const xmlChar *) "line-number", |
| SAXON_NAMESPACE, |
| exsltSaxonLineNumberFunction); |
| } |