| OLD | NEW |
| (Empty) |
| 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 xmlXPathSetError(ctxt, XPATH_EXPR_ERROR); | |
| 105 return; | |
| 106 } | |
| 107 xmlHashAddEntry(hash, arg, (void *) ret); | |
| 108 } | |
| 109 | |
| 110 xmlFree(arg); | |
| 111 | |
| 112 xmlXPathReturnExternal(ctxt, ret); | |
| 113 } | |
| 114 | |
| 115 /** | |
| 116 * exsltSaxonEvalFunction: | |
| 117 * @ctxt: an XPath parser context | |
| 118 * @nargs: number of arguments | |
| 119 * | |
| 120 * Implements de SAXON eval() function: | |
| 121 * object saxon:eval (saxon:stored-expression) | |
| 122 * Returns the result of evaluating the supplied stored expression. | |
| 123 * A stored expression may be obtained as the result of calling | |
| 124 * the saxon:expression() function. | |
| 125 * The stored expression is evaluated in the current context, that | |
| 126 * is, the context node is the current node, and the context position | |
| 127 * and context size are the same as the result of calling position() | |
| 128 * or last() respectively. | |
| 129 */ | |
| 130 static void | |
| 131 exsltSaxonEvalFunction (xmlXPathParserContextPtr ctxt, int nargs) { | |
| 132 xmlXPathCompExprPtr expr; | |
| 133 xmlXPathObjectPtr ret; | |
| 134 | |
| 135 if (nargs != 1) { | |
| 136 xmlXPathSetArityError(ctxt); | |
| 137 return; | |
| 138 } | |
| 139 | |
| 140 if (!xmlXPathStackIsExternal(ctxt)) { | |
| 141 xmlXPathSetTypeError(ctxt); | |
| 142 return; | |
| 143 } | |
| 144 | |
| 145 expr = (xmlXPathCompExprPtr) xmlXPathPopExternal(ctxt); | |
| 146 | |
| 147 ret = xmlXPathCompiledEval(expr, ctxt->context); | |
| 148 if (ret == NULL) { | |
| 149 xmlXPathSetError(ctxt, XPATH_EXPR_ERROR); | |
| 150 return; | |
| 151 } | |
| 152 | |
| 153 valuePush(ctxt, ret); | |
| 154 } | |
| 155 | |
| 156 /** | |
| 157 * exsltSaxonEvaluateFunction: | |
| 158 * @ctxt: an XPath parser context | |
| 159 * @nargs: number of arguments | |
| 160 * | |
| 161 * Implements the SAXON evaluate() function | |
| 162 * object saxon:evaluate (string) | |
| 163 * The supplied string must contain an XPath expression. The result of | |
| 164 * the function is the result of evaluating the XPath expression. This | |
| 165 * is useful where an expression needs to be constructed at run-time or | |
| 166 * passed to the stylesheet as a parameter, for example where the sort | |
| 167 * key is determined dynamically. The context for the expression (e.g. | |
| 168 * which variables and namespaces are available) is exactly the same as | |
| 169 * if the expression were written explicitly at this point in the | |
| 170 * stylesheet. The function saxon:evaluate(string) is shorthand for | |
| 171 * saxon:eval(saxon:expression(string)). | |
| 172 */ | |
| 173 static void | |
| 174 exsltSaxonEvaluateFunction (xmlXPathParserContextPtr ctxt, int nargs) { | |
| 175 if (nargs != 1) { | |
| 176 xmlXPathSetArityError(ctxt); | |
| 177 return; | |
| 178 } | |
| 179 | |
| 180 exsltSaxonExpressionFunction(ctxt, 1); | |
| 181 exsltSaxonEvalFunction(ctxt, 1); | |
| 182 } | |
| 183 | |
| 184 /** | |
| 185 * exsltSaxonSystemIdFunction: | |
| 186 * @ctxt: an XPath parser context | |
| 187 * @nargs: number of arguments | |
| 188 * | |
| 189 * Implements the SAXON systemId() function | |
| 190 * string saxon:systemId () | |
| 191 * This function returns the system ID of the document being styled. | |
| 192 */ | |
| 193 static void | |
| 194 exsltSaxonSystemIdFunction(xmlXPathParserContextPtr ctxt, int nargs) | |
| 195 { | |
| 196 if (ctxt == NULL) | |
| 197 return; | |
| 198 if (nargs != 0) { | |
| 199 xmlXPathSetArityError(ctxt); | |
| 200 return; | |
| 201 } | |
| 202 | |
| 203 if ((ctxt->context) && (ctxt->context->doc) && | |
| 204 (ctxt->context->doc->URL)) | |
| 205 valuePush(ctxt, xmlXPathNewString(ctxt->context->doc->URL)); | |
| 206 else | |
| 207 valuePush(ctxt, xmlXPathNewString(BAD_CAST "")); | |
| 208 } | |
| 209 | |
| 210 /** | |
| 211 * exsltSaxonLineNumberFunction: | |
| 212 * @ctxt: an XPath parser context | |
| 213 * @nargs: number of arguments | |
| 214 * | |
| 215 * Implements the SAXON line-number() function | |
| 216 * integer saxon:line-number() | |
| 217 * | |
| 218 * This returns the line number of the context node in the source document | |
| 219 * within the entity that contains it. There are no arguments. If line numbers | |
| 220 * are not maintained for the current document, the function returns -1. (To | |
| 221 * ensure that line numbers are maintained, use the -l option on the command | |
| 222 * line) | |
| 223 * | |
| 224 * The extension has been extended to have the following form: | |
| 225 * integer saxon:line-number([node-set-1]) | |
| 226 * If a node-set is given, this extension will return the line number of the | |
| 227 * node in the argument node-set that is first in document order. | |
| 228 */ | |
| 229 static void | |
| 230 exsltSaxonLineNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { | |
| 231 xmlNodePtr cur = NULL; | |
| 232 xmlXPathObjectPtr obj = NULL; | |
| 233 long lineNo = -1; | |
| 234 | |
| 235 if (nargs == 0) { | |
| 236 cur = ctxt->context->node; | |
| 237 } else if (nargs == 1) { | |
| 238 xmlNodeSetPtr nodelist; | |
| 239 int i; | |
| 240 | |
| 241 if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) { | |
| 242 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, | |
| 243 "saxon:line-number() : invalid arg expecting a node-set\n"); | |
| 244 ctxt->error = XPATH_INVALID_TYPE; | |
| 245 return; | |
| 246 } | |
| 247 | |
| 248 obj = valuePop(ctxt); | |
| 249 nodelist = obj->nodesetval; | |
| 250 if ((nodelist != NULL) && (nodelist->nodeNr > 0)) { | |
| 251 cur = nodelist->nodeTab[0]; | |
| 252 for (i = 1;i < nodelist->nodeNr;i++) { | |
| 253 int ret = xmlXPathCmpNodes(cur, nodelist->nodeTab[i]); | |
| 254 if (ret == -1) | |
| 255 cur = nodelist->nodeTab[i]; | |
| 256 } | |
| 257 } | |
| 258 } else { | |
| 259 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, | |
| 260 "saxon:line-number() : invalid number of args %d\n", | |
| 261 nargs); | |
| 262 ctxt->error = XPATH_INVALID_ARITY; | |
| 263 return; | |
| 264 } | |
| 265 | |
| 266 if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL)) { | |
| 267 /* | |
| 268 * The XPath module sets the owner element of a ns-node on | |
| 269 * the ns->next field. | |
| 270 */ | |
| 271 cur = (xmlNodePtr) ((xmlNsPtr) cur)->next; | |
| 272 if (cur == NULL || cur->type != XML_ELEMENT_NODE) { | |
| 273 xsltGenericError(xsltGenericErrorContext, | |
| 274 "Internal error in exsltSaxonLineNumberFunction: " | |
| 275 "Cannot retrieve the doc of a namespace node.\n"); | |
| 276 cur = NULL; | |
| 277 } | |
| 278 } | |
| 279 | |
| 280 if (cur != NULL) | |
| 281 lineNo = xmlGetLineNo(cur); | |
| 282 | |
| 283 valuePush(ctxt, xmlXPathNewFloat(lineNo)); | |
| 284 | |
| 285 xmlXPathFreeObject(obj); | |
| 286 } | |
| 287 | |
| 288 /** | |
| 289 * exsltSaxonRegister: | |
| 290 * | |
| 291 * Registers the SAXON extension module | |
| 292 */ | |
| 293 void | |
| 294 exsltSaxonRegister (void) { | |
| 295 xsltRegisterExtModule (SAXON_NAMESPACE, | |
| 296 (xsltExtInitFunction) exsltSaxonInit, | |
| 297 (xsltExtShutdownFunction) exsltSaxonShutdown); | |
| 298 xsltRegisterExtModuleFunction((const xmlChar *) "expression", | |
| 299 SAXON_NAMESPACE, | |
| 300 exsltSaxonExpressionFunction); | |
| 301 xsltRegisterExtModuleFunction((const xmlChar *) "eval", | |
| 302 SAXON_NAMESPACE, | |
| 303 exsltSaxonEvalFunction); | |
| 304 xsltRegisterExtModuleFunction((const xmlChar *) "evaluate", | |
| 305 SAXON_NAMESPACE, | |
| 306 exsltSaxonEvaluateFunction); | |
| 307 xsltRegisterExtModuleFunction ((const xmlChar *) "line-number", | |
| 308 SAXON_NAMESPACE, | |
| 309 exsltSaxonLineNumberFunction); | |
| 310 xsltRegisterExtModuleFunction ((const xmlChar *) "systemId", | |
| 311 SAXON_NAMESPACE, | |
| 312 exsltSaxonSystemIdFunction); | |
| 313 } | |
| OLD | NEW |