diff --git a/src/lua_xpath.c b/src/lua_xpath.c index ecce558..5055099 100644 --- a/src/lua_xpath.c +++ b/src/lua_xpath.c @@ -5,6 +5,7 @@ #define LUA_XPATH_NAME "xpath" #define LUA_XPATH_MT_NAME "xpath_mt" +#define MAX_XPATH_PREFIX_NUM 20 typedef struct xpath_selector_s { struct xpath_selector_s *root; @@ -204,11 +205,13 @@ __parse_file(xpath_selector_t *sel, char const *fname) static void ** -__eval_xpath(lua_State *L, xpath_selector_t *sel, char const *xpath) +__eval_xpath(lua_State *L, xpath_selector_t *sel, char const *xpath, const xmlChar * nsList[]) { int i; xmlXPathObject *result = NULL; xmlXPathContext *ctxt = NULL; + const xmlChar* prefix = NULL; + const xmlChar* href = NULL; void **nodes = NULL; @@ -223,6 +226,14 @@ __eval_xpath(lua_State *L, xpath_selector_t *sel, char const *xpath) break; } + for (i = 0 ; prefix = nsList[i++];) { + if ((href = nsList[i]) + && (xmlXPathRegisterNs(ctxt, prefix, href) != 0)) { + __set_error(sel, NULL, "add namespace to xpath context error"); + break; + } + } + /* the current node */ ctxt->node = sel->node; @@ -460,6 +471,7 @@ xpath_eval_xpath(lua_State *L) size_t length; void **nodes; const char *xpath; + const xmlChar* nsList[MAX_XPATH_PREFIX_NUM]; xpath_selector_t *sel, *node; @@ -477,8 +489,29 @@ xpath_eval_xpath(lua_State *L) lua_pushstring(L, "xpath pattern needed"); return 2; } + { + int n, top = lua_gettop(L); + i = 1; + if (top > 2) { //optionally prefix/href array for xpath + if (lua_type(L, 3) != LUA_TTABLE) { + lua_pushnil(L); + lua_pushstring(L, "prefix/href array is expected"); + return 2; + } + if ((n = luaL_getn(L, 3)) > MAX_XPATH_PREFIX_NUM) { + lua_pushnil(L); + lua_pushstring(L, "too much prefixes"); + return 2; + } + for (; i <= n; i++) { + lua_rawgeti(L, 3, i); + nsList[i - 1] = luaL_optlstring(L, -1, NULL, &length); + } + } + nsList[i - 1] = 0; + } - nodes = (void **) __eval_xpath(L, sel, xpath); + nodes = (void **) __eval_xpath(L, sel, xpath, nsList); if (nodes == NULL) { lua_pushnil(L); lua_pushstring(L, __get_error(sel, "eval xpath error")); diff --git a/src/lua_xpath.h b/src/lua_xpath.h index 49c62bd..f01dd9a 100644 --- a/src/lua_xpath.h +++ b/src/lua_xpath.h @@ -7,6 +7,8 @@ #include #include #include +#include + #include diff --git a/tests/api.lua b/tests/api.lua index 7de6aba..5f51d32 100644 --- a/tests/api.lua +++ b/tests/api.lua @@ -1,4 +1,4 @@ -package.cpath = "/home/duhoobo/prj/amateur/lua-xpath/src/?.so;" .. package.cpath +package.cpath = "/home/akh/local/lua-xpath/src/?.so;" .. package.cpath local xpath = require("xpath") @@ -12,6 +12,17 @@ xml = [[ male ]] +xmlns = [[ + + + + + 4 + + + +]] + function test_xpath() @@ -40,6 +51,33 @@ function test_xpath() print "\n--- leave test_xpath ---" end +function test_xpath_with_ns() + print "--- enter test_xpath_with_ns ---\n" + + local sel, err = xpath.loads(xmlns) + + if not sel then + print(sel, err) + return + end + + print(sel) + + local ls, err = sel:xpath("/soap:Envelope/soap:Body//message:SomeField[text()=4]", + {"soap", "http://schemas.xmlsoap.org/soap/envelope/", "message", "http://org.mycomp"}) + + if not ls then + print(ls, err) + return + end + + for k, v in pairs(ls) do + print(k, v, v:extract()) + end + + print "\n--- leave test_xpath_with_ns ---" +end + function test_relative_xpath() print "--- enter test_relative_xpath ---\n" @@ -214,6 +252,7 @@ end test_xpath() +test_xpath_with_ns() test_relative_xpath() test_re() test_css()