1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 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);
}
|