diff options
Diffstat (limited to 'libxslt/libexslt/saxon.c')
-rw-r--r-- | libxslt/libexslt/saxon.c | 313 |
1 files changed, 313 insertions, 0 deletions
diff --git a/libxslt/libexslt/saxon.c b/libxslt/libexslt/saxon.c new file mode 100644 index 0000000..7a2f63b --- /dev/null +++ b/libxslt/libexslt/saxon.c @@ -0,0 +1,313 @@ +#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); + xmlXPathSetError(ctxt, XPATH_EXPR_ERROR); + 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); + if (ret == NULL) { + xmlXPathSetError(ctxt, XPATH_EXPR_ERROR); + return; + } + + 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); +} + +/** + * exsltSaxonSystemIdFunction: + * @ctxt: an XPath parser context + * @nargs: number of arguments + * + * Implements the SAXON systemId() function + * string saxon:systemId () + * This function returns the system ID of the document being styled. + */ +static void +exsltSaxonSystemIdFunction(xmlXPathParserContextPtr ctxt, int nargs) +{ + if (ctxt == NULL) + return; + if (nargs != 0) { + xmlXPathSetArityError(ctxt); + return; + } + + if ((ctxt->context) && (ctxt->context->doc) && + (ctxt->context->doc->URL)) + valuePush(ctxt, xmlXPathNewString(ctxt->context->doc->URL)); + else + valuePush(ctxt, xmlXPathNewString(BAD_CAST "")); +} + +/** + * 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; + xmlXPathObjectPtr obj = NULL; + long lineNo = -1; + + if (nargs == 0) { + cur = ctxt->context->node; + } else if (nargs == 1) { + 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)) { + 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]; + } + } + } else { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "saxon:line-number() : invalid number of args %d\n", + nargs); + ctxt->error = XPATH_INVALID_ARITY; + return; + } + + if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL)) { + /* + * The XPath module sets the owner element of a ns-node on + * the ns->next field. + */ + cur = (xmlNodePtr) ((xmlNsPtr) cur)->next; + if (cur == NULL || cur->type != XML_ELEMENT_NODE) { + xsltGenericError(xsltGenericErrorContext, + "Internal error in exsltSaxonLineNumberFunction: " + "Cannot retrieve the doc of a namespace node.\n"); + cur = NULL; + } + } + + if (cur != NULL) + lineNo = xmlGetLineNo(cur); + + valuePush(ctxt, xmlXPathNewFloat(lineNo)); + + xmlXPathFreeObject(obj); +} + +/** + * 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); + xsltRegisterExtModuleFunction ((const xmlChar *) "systemId", + SAXON_NAMESPACE, + exsltSaxonSystemIdFunction); +} |