root/third_party/libxslt/libexslt/saxon.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. exsltSaxonInit
  2. exsltSaxonShutdown
  3. exsltSaxonExpressionFunction
  4. exsltSaxonEvalFunction
  5. exsltSaxonEvaluateFunction
  6. exsltSaxonLineNumberFunction
  7. exsltSaxonRegister

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

/* [<][>][^][v][top][bottom][index][help] */