1 #define IN_LIBEXSLT 2 #include "libexslt/libexslt.h" 3 4 #if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__) 5 #include <win32config.h> 6 #else 7 #include "config.h" 8 #endif 9 10 #include <libxml/tree.h> 11 #include <libxml/xpath.h> 12 #include <libxml/xpathInternals.h> 13 #include <libxml/parser.h> 14 #include <libxml/hash.h> 15 16 #include <libxslt/xsltconfig.h> 17 #include <libxslt/xsltutils.h> 18 #include <libxslt/xsltInternals.h> 19 #include <libxslt/extensions.h> 20 21 #include "exslt.h" 22 23 /** 24 * exsltSaxonInit: 25 * @ctxt: an XSLT transformation context 26 * @URI: the namespace URI for the extension 27 * 28 * Initializes the SAXON module. 29 * 30 * Returns the data for this transformation 31 */ 32 static xmlHashTablePtr 33 exsltSaxonInit (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, 34 const xmlChar *URI ATTRIBUTE_UNUSED) { 35 return xmlHashCreate(1); 36 } 37 38 /** 39 * exsltSaxonShutdown: 40 * @ctxt: an XSLT transformation context 41 * @URI: the namespace URI for the extension 42 * @data: the module data to free up 43 * 44 * Shutdown the SAXON extension module 45 */ 46 static void 47 exsltSaxonShutdown (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, 48 const xmlChar *URI ATTRIBUTE_UNUSED, 49 xmlHashTablePtr data) { 50 xmlHashFree(data, (xmlHashDeallocator) xmlXPathFreeCompExpr); 51 } 52 53 54 /** 55 * exsltSaxonExpressionFunction: 56 * @ctxt: an XPath parser context 57 * @nargs: the number of arguments 58 * 59 * The supplied string must contain an XPath expression. The result of 60 * the function is a stored expression, which may be supplied as an 61 * argument to other extension functions such as saxon:eval(), 62 * saxon:sum() and saxon:distinct(). The result of the expression will 63 * usually depend on the current node. The expression may contain 64 * references to variables that are in scope at the point where 65 * saxon:expression() is called: these variables will be replaced in 66 * the stored expression with the values they take at the time 67 * saxon:expression() is called, not the values of the variables at 68 * the time the stored expression is evaluated. Similarly, if the 69 * expression contains namespace prefixes, these are interpreted in 70 * terms of the namespace declarations in scope at the point where the 71 * saxon:expression() function is called, not those in scope where the 72 * stored expression is evaluated. 73 * 74 * TODO: current implementation doesn't conform to SAXON behaviour 75 * regarding context and namespaces. 76 */ 77 static void 78 exsltSaxonExpressionFunction (xmlXPathParserContextPtr ctxt, int nargs) { 79 xmlChar *arg; 80 xmlXPathCompExprPtr ret; 81 xmlHashTablePtr hash; 82 xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt); 83 84 if (nargs != 1) { 85 xmlXPathSetArityError(ctxt); 86 return; 87 } 88 89 arg = xmlXPathPopString(ctxt); 90 if (xmlXPathCheckError(ctxt) || (arg == NULL)) { 91 xmlXPathSetTypeError(ctxt); 92 return; 93 } 94 95 hash = (xmlHashTablePtr) xsltGetExtData(tctxt, 96 ctxt->context->functionURI); 97 98 ret = xmlHashLookup(hash, arg); 99 100 if (ret == NULL) { 101 ret = xmlXPathCompile(arg); 102 if (ret == NULL) { 103 xmlFree(arg); 104 xsltGenericError(xsltGenericErrorContext, 105 "{%s}:%s: argument is not an XPath expression\n", 106 ctxt->context->functionURI, ctxt->context->function); 107 return; 108 } 109 xmlHashAddEntry(hash, arg, (void *) ret); 110 } 111 112 xmlFree(arg); 113 114 xmlXPathReturnExternal(ctxt, ret); 115 } 116 117 /** 118 * exsltSaxonEvalFunction: 119 * @ctxt: an XPath parser context 120 * @nargs: number of arguments 121 * 122 * Implements de SAXON eval() function: 123 * object saxon:eval (saxon:stored-expression) 124 * Returns the result of evaluating the supplied stored expression. 125 * A stored expression may be obtained as the result of calling 126 * the saxon:expression() function. 127 * The stored expression is evaluated in the current context, that 128 * is, the context node is the current node, and the context position 129 * and context size are the same as the result of calling position() 130 * or last() respectively. 131 */ 132 static void 133 exsltSaxonEvalFunction (xmlXPathParserContextPtr ctxt, int nargs) { 134 xmlXPathCompExprPtr expr; 135 xmlXPathObjectPtr ret; 136 137 if (nargs != 1) { 138 xmlXPathSetArityError(ctxt); 139 return; 140 } 141 142 if (!xmlXPathStackIsExternal(ctxt)) { 143 xmlXPathSetTypeError(ctxt); 144 return; 145 } 146 147 expr = (xmlXPathCompExprPtr) xmlXPathPopExternal(ctxt); 148 149 ret = xmlXPathCompiledEval(expr, ctxt->context); 150 151 valuePush(ctxt, ret); 152 } 153 154 /** 155 * exsltSaxonEvaluateFunction: 156 * @ctxt: an XPath parser context 157 * @nargs: number of arguments 158 * 159 * Implements the SAXON evaluate() function 160 * object saxon:evaluate (string) 161 * The supplied string must contain an XPath expression. The result of 162 * the function is the result of evaluating the XPath expression. This 163 * is useful where an expression needs to be constructed at run-time or 164 * passed to the stylesheet as a parameter, for example where the sort 165 * key is determined dynamically. The context for the expression (e.g. 166 * which variables and namespaces are available) is exactly the same as 167 * if the expression were written explicitly at this point in the 168 * stylesheet. The function saxon:evaluate(string) is shorthand for 169 * saxon:eval(saxon:expression(string)). 170 */ 171 static void 172 exsltSaxonEvaluateFunction (xmlXPathParserContextPtr ctxt, int nargs) { 173 if (nargs != 1) { 174 xmlXPathSetArityError(ctxt); 175 return; 176 } 177 178 exsltSaxonExpressionFunction(ctxt, 1); 179 exsltSaxonEvalFunction(ctxt, 1); 180 } 181 182 /** 183 * exsltSaxonLineNumberFunction: 184 * @ctxt: an XPath parser context 185 * @nargs: number of arguments 186 * 187 * Implements the SAXON line-number() function 188 * integer saxon:line-number() 189 * 190 * This returns the line number of the context node in the source document 191 * within the entity that contains it. There are no arguments. If line numbers 192 * are not maintained for the current document, the function returns -1. (To 193 * ensure that line numbers are maintained, use the -l option on the command 194 * line) 195 * 196 * The extension has been extended to have the following form: 197 * integer saxon:line-number([node-set-1]) 198 * If a node-set is given, this extension will return the line number of the 199 * node in the argument node-set that is first in document order. 200 */ 201 static void 202 exsltSaxonLineNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { 203 xmlNodePtr cur = NULL; 204 205 if (nargs == 0) { 206 cur = ctxt->context->node; 207 } else if (nargs == 1) { 208 xmlXPathObjectPtr obj; 209 xmlNodeSetPtr nodelist; 210 int i; 211 212 if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) { 213 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, 214 "saxon:line-number() : invalid arg expecting a node-set\n"); 215 ctxt->error = XPATH_INVALID_TYPE; 216 return; 217 } 218 219 obj = valuePop(ctxt); 220 nodelist = obj->nodesetval; 221 if ((nodelist == NULL) || (nodelist->nodeNr <= 0)) { 222 xmlXPathFreeObject(obj); 223 valuePush(ctxt, xmlXPathNewFloat(-1)); 224 return; 225 } 226 cur = nodelist->nodeTab[0]; 227 for (i = 1;i < nodelist->nodeNr;i++) { 228 int ret = xmlXPathCmpNodes(cur, nodelist->nodeTab[i]); 229 if (ret == -1) 230 cur = nodelist->nodeTab[i]; 231 } 232 xmlXPathFreeObject(obj); 233 } else { 234 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, 235 "saxon:line-number() : invalid number of args %d\n", 236 nargs); 237 ctxt->error = XPATH_INVALID_ARITY; 238 return; 239 } 240 241 valuePush(ctxt, xmlXPathNewFloat(xmlGetLineNo(cur))); 242 return; 243 } 244 245 /** 246 * exsltSaxonRegister: 247 * 248 * Registers the SAXON extension module 249 */ 250 void 251 exsltSaxonRegister (void) { 252 xsltRegisterExtModule (SAXON_NAMESPACE, 253 (xsltExtInitFunction) exsltSaxonInit, 254 (xsltExtShutdownFunction) exsltSaxonShutdown); 255 xsltRegisterExtModuleFunction((const xmlChar *) "expression", 256 SAXON_NAMESPACE, 257 exsltSaxonExpressionFunction); 258 xsltRegisterExtModuleFunction((const xmlChar *) "eval", 259 SAXON_NAMESPACE, 260 exsltSaxonEvalFunction); 261 xsltRegisterExtModuleFunction((const xmlChar *) "evaluate", 262 SAXON_NAMESPACE, 263 exsltSaxonEvaluateFunction); 264 xsltRegisterExtModuleFunction ((const xmlChar *) "line-number", 265 SAXON_NAMESPACE, 266 exsltSaxonLineNumberFunction); 267 } 268