From 26a5a4b96b90361859cf856d6c41852b03ca2f84 Mon Sep 17 00:00:00 2001 From: pop Date: Tue, 4 Feb 2003 12:06:46 +0000 Subject: [PATCH] xelm support enhanced, now supports simpler predicates --- configure.in | 4 +- data1/d1_absyn.c | 97 ++++++++++++++++++++-- include/Makefile.am | 3 +- include/data1.h | 9 ++- include/zebra_xpath.h | 35 ++++++++ index/Makefile.am | 5 +- index/zrpn.c | 106 +++++------------------- isamb/isamb.c | 4 +- recctrl/recgrs.c | 119 +++++++++++++++++++++++++-- util/Makefile.am | 4 +- util/xpath.c | 214 +++++++++++++++++++++++++++++++++++++++++++++++++ 11 files changed, 491 insertions(+), 109 deletions(-) create mode 100644 include/zebra_xpath.h create mode 100644 util/xpath.c diff --git a/configure.in b/configure.in index 317ef3f..3da6705 100644 --- a/configure.in +++ b/configure.in @@ -1,5 +1,5 @@ dnl Zebra, Index Data Aps, 1995-2002 -dnl $Id: configure.in,v 1.61 2002-12-30 10:25:24 adam Exp $ +dnl $Id: configure.in,v 1.62 2003-02-04 12:06:46 pop Exp $ dnl AC_INIT(include/zebraver.h) AM_INIT_AUTOMAKE(idzebra,1.3.4) @@ -333,7 +333,7 @@ AC_OUTPUT([ doc/zebraphp.dsl doc/tkl.xsl test/Makefile test/gils/Makefile test/usmarc/Makefile test/api/Makefile - perl/Makefile.PL + perl/Makefile.PL test/xelm/Makefile test/dmoz/Makefile test/xpath/Makefile test/sort/Makefile examples/Makefile examples/gils/Makefile examples/zthes/Makefile ]) diff --git a/data1/d1_absyn.c b/data1/d1_absyn.c index e2434c4..c7f8ba7 100644 --- a/data1/d1_absyn.c +++ b/data1/d1_absyn.c @@ -1,4 +1,4 @@ -/* $Id: d1_absyn.c,v 1.5 2002-12-16 22:59:34 adam Exp $ +/* $Id: d1_absyn.c,v 1.6 2003-02-04 12:06:46 pop Exp $ Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002 Index Data Aps @@ -28,6 +28,7 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include #include #include +#include #define D1_MAX_NESTING 128 @@ -282,14 +283,23 @@ void fix_element_ref (data1_handle dh, data1_absyn *absyn, data1_element *e) / -> none pop, 2002-12-13 + + Now [] predicates are supported + + pop, 2003-01-17 + */ const char * mk_xpath_regexp (data1_handle dh, char *expr) { char *p = expr; + char *pp; + char *s; int abs = 1; int i; + int j; int e=0; + int is_predicate = 0; static char *stack[32]; static char res[1024]; @@ -301,10 +311,28 @@ const char * mk_xpath_regexp (data1_handle dh, char *expr) while (*p) { i=0; - while (*p && !strchr("/",*p)) { i++; p++; } + while (*p && !strchr("/",*p)) { + i++; p++; + } stack[e] = (char *) nmem_malloc (data1_nmem_get (dh), i+1); - memcpy (stack[e], p - i, i); - stack[e][i] = 0; + s = stack[e]; + for (j=0; j< i; j++) { + pp = p-i+j; + if (*pp == '[') { + is_predicate=1; + } + else if (*pp == ']') { + is_predicate=0; + } + else { + if (!is_predicate) { + if (*pp == '*') + *s++ = '.'; + *s++ = *pp; + } + } + } + *s = 0; e++; if (*p) {p++;} } @@ -319,6 +347,7 @@ const char * mk_xpath_regexp (data1_handle dh, char *expr) if (!abs) { sprintf (p, ".*"); p+=2; } sprintf (p, "$"); p++; r = nmem_strdup (data1_nmem_get (dh), res); + yaz_log(LOG_DEBUG,"Got regexp: %s",r); return (r); } @@ -399,6 +428,48 @@ const char *data1_systag_lookup(data1_absyn *absyn, const char *tag, return default_value; } +#define l_isspace(c) ((c) == '\t' || (c) == ' ' || (c) == '\n' || (c) == '\r') + +int read_absyn_line(FILE *f, int *lineno, char *line, int len, + char *argv[], int num) +{ + char *p; + int argc; + int quoted = 0; + + while ((p = fgets(line, len, f))) + { + (*lineno)++; + while (*p && l_isspace(*p)) + p++; + if (*p && *p != '#') + break; + } + if (!p) + return 0; + + for (argc = 0; *p ; argc++) + { + if (*p == '#') /* trailing comment */ + break; + argv[argc] = p; + while (*p && !(l_isspace(*p) && !quoted)) { + if (*p =='"') quoted = 1 - quoted; + if (*p =='[') quoted = 1; + if (*p ==']') quoted = 0; + p++; + } + if (*p) + { + *(p++) = '\0'; + while (*p && l_isspace(*p)) + p++; + } + } + return argc; +} + + data1_absyn *data1_read_absyn (data1_handle dh, const char *file, int file_must_exist) { @@ -451,7 +522,7 @@ data1_absyn *data1_read_absyn (data1_handle dh, const char *file, res->main_elements = NULL; res->xp_elements = NULL; - while (f && (argc = readconf_line(f, &lineno, line, 512, argv, 50))) + while (f && (argc = read_absyn_line(f, &lineno, line, 512, argv, 50))) { char *cmd = *argv; if (!strcmp(cmd, "elm") || !strcmp(cmd, "element")) @@ -582,6 +653,11 @@ data1_absyn *data1_read_absyn (data1_handle dh, const char *file, maybe we should use a simple sscanf instead of dfa? pop, 2002-12-13 + + Now [] predicates are supported. regexps and xpath structure is + a bit redundant, however it's comfortable later... + + pop, 2003-01-17 */ else if (!strcmp(cmd, "xelm")) { @@ -624,7 +700,16 @@ data1_absyn *data1_read_absyn (data1_handle dh, const char *file, dfa_mkstate (dfa); cur_xpelement->dfa = dfa; - + +#ifdef ENHANCED_XELM + cur_xpelement->xpath_len = parse_xpath_str(xpath_expr, + cur_xpelement->xpath, + data1_nmem_get(dh)); + + /* + dump_xp_steps(cur_xpelement->xpath,cur_xpelement->xpath_len); + */ +#endif cur_xpelement->termlists = 0; tp = &cur_xpelement->termlists; diff --git a/include/Makefile.am b/include/Makefile.am index 2d36402..f1d5408 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -3,4 +3,5 @@ noinst_HEADERS = bfile.h bset.h charmap.h d1_attset.h d1_map.h \ data1.h dfa.h dict.h direntz.h isamb.h isamc.h isamd.h isamg.h isam.h \ isams.h mfile.h passwddb.h recctrl.h res.h rsbetween.h rsbool.h rset.h \ rsisamb.h rsisamc.h rsisamd.h rsisam.h rsisams.h rsm_or.h rsnull.h \ -rstemp.h set.h sortidx.h str.h zebra-lock.h zebramap.h zebrautl.h zebraver.h +rstemp.h set.h sortidx.h str.h zebra-lock.h zebramap.h zebrautl.h \ +zebra_xpath.h zebraver.h diff --git a/include/data1.h b/include/data1.h index 8b48a06..34dd37d 100644 --- a/include/data1.h +++ b/include/data1.h @@ -1,4 +1,4 @@ -/* $Id: data1.h,v 1.4 2002-12-16 20:27:18 adam Exp $ +/* $Id: data1.h,v 1.5 2003-02-04 12:06:47 pop Exp $ Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002 Index Data Aps @@ -23,6 +23,8 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA #ifndef DATA1_H #define DATA1_H +#define ENHANCED_XELM 1 + #include #include @@ -34,6 +36,7 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include #include #include /* pop */ +#include /* pop */ #define d1_isspace(c) strchr(" \r\n\t\f", c) #define d1_isdigit(c) ((c) <= '9' && (c) >= '0') @@ -192,6 +195,10 @@ typedef struct data1_sub_elements { typedef struct data1_xpelement { char *xpath_expr; +#ifdef ENHANCED_XELM + struct xpath_location_step xpath[XPATH_STEP_COUNT]; + int xpath_len; +#endif struct DFA *dfa; data1_termlist *termlists; struct data1_xpelement *next; diff --git a/include/zebra_xpath.h b/include/zebra_xpath.h new file mode 100644 index 0000000..d09bf16 --- /dev/null +++ b/include/zebra_xpath.h @@ -0,0 +1,35 @@ +/* Moved from zrpn.c -pop */ + +#ifndef ZEBRA_XPATH_H +#define ZEBRA_XPATH_H + +#define XPATH_STEP_COUNT 10 +struct xpath_predicate { + int which; + union { +#define XPATH_PREDICATE_RELATION 1 + struct { + char *name; + char *op; + char *value; + } relation; +#define XPATH_PREDICATE_BOOLEAN 2 + struct { + const char *op; + struct xpath_predicate *left; + struct xpath_predicate *right; + } boolean; + } u; +}; + +struct xpath_location_step { + char *part; + struct xpath_predicate *predicate; +}; + +int parse_xpath_str(const char *xpath_string, + struct xpath_location_step *xpath, NMEM mem); + +void dump_xp_steps (struct xpath_location_step *xpath, int no); + +#endif diff --git a/index/Makefile.am b/index/Makefile.am index 062b0b4..1f3f2b8 100644 --- a/index/Makefile.am +++ b/index/Makefile.am @@ -1,4 +1,4 @@ -## $Id: Makefile.am,v 1.17 2002-11-26 22:18:17 adam Exp $ +## $Id: Makefile.am,v 1.18 2003-02-04 12:06:47 pop Exp $ noinst_PROGRAMS = apitest kdump @@ -7,7 +7,8 @@ noinst_LIBRARIES = libzebra.a libzebra_a_SOURCES = dir.c dirs.c trav.c kinput.c kcompare.c \ attribute.c symtab.c recindex.c recstat.c lockutil.c \ zebraapi.c zinfo.c invstat.c sortidx.c compact.c zsets.c zrpn.c \ - rank1.c trunc.c retrieve.c extract.c index.h recindex.h recindxp.h \ + rank1.c trunc.c retrieve.c extract.c \ + index.h recindex.h recindxp.h \ zebraapi.h zinfo.h zserver.h libzebra_a_LIBADD = \ diff --git a/index/zrpn.c b/index/zrpn.c index 0a2c29c..2f35cfa 100644 --- a/index/zrpn.c +++ b/index/zrpn.c @@ -1,4 +1,4 @@ -/* $Id: zrpn.c,v 1.126 2002-12-16 22:59:34 adam Exp $ +/* $Id: zrpn.c,v 1.127 2003-02-04 12:06:47 pop Exp $ Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002 Index Data Aps @@ -31,6 +31,7 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include #include "index.h" +#include #include #include @@ -43,6 +44,14 @@ struct rpn_char_map_info { int reg_type; }; +typedef struct { + int type; + int major; + int minor; + Z_AttributesPlusTerm *zapt; +} AttrType; + + static const char **rpn_char_map_handler (void *vp, const char **from, int len) { struct rpn_char_map_info *p = (struct rpn_char_map_info *) vp; @@ -70,13 +79,6 @@ static void rpn_char_map_prepare (struct zebra_register *reg, int reg_type, dict_grep_cmap (reg->dict, map_info, rpn_char_map_handler); } -typedef struct { - int type; - int major; - int minor; - Z_AttributesPlusTerm *zapt; -} AttrType; - static int attr_find_ex (AttrType *src, oid_value *attributeSetP, const char **string_value) { @@ -2034,6 +2036,9 @@ static RSET rpn_sort_spec (ZebraHandle zh, Z_AttributesPlusTerm *zapt, return rset_create (rset_kind_null, &parms); } +/* pop - moved to xpath.c */ +#if 0 + struct xpath_predicate { int which; union { @@ -2057,6 +2062,8 @@ struct xpath_location_step { struct xpath_predicate *predicate; }; +#endif + static int parse_xpath(ZebraHandle zh, Z_AttributesPlusTerm *zapt, oid_value attributeSet, struct xpath_location_step *xpath, NMEM mem) @@ -2064,7 +2071,6 @@ static int parse_xpath(ZebraHandle zh, Z_AttributesPlusTerm *zapt, oid_value curAttributeSet = attributeSet; AttrType use; const char *use_string = 0; - const char *cp; int no = 0; attr_init (&use, zapt, 1); @@ -2072,87 +2078,11 @@ static int parse_xpath(ZebraHandle zh, Z_AttributesPlusTerm *zapt, if (!use_string || *use_string != '/') return -1; - cp = use_string; - while (*cp) - { - int i = 0; - while (*cp && !strchr("/[",*cp)) - { - i++; - cp++; - } - xpath[no].predicate = 0; - xpath[no].part = nmem_malloc (mem, i+1); - memcpy (xpath[no].part, cp - i, i); - xpath[no].part[i] = 0; - if (*cp == '[') - { - struct xpath_predicate *p = xpath[no].predicate = - nmem_malloc (mem, sizeof(struct xpath_predicate)); - - p->which = XPATH_PREDICATE_RELATION; - cp++; - while (*cp == ' ') - cp++; - - for (i = 0; *cp && !strchr("><=] ", *cp); i++) - cp++; - p->u.relation.name = nmem_malloc (mem, i+1); - memcpy (p->u.relation.name, cp - i, i); - p->u.relation.name[i] = 0; - while (*cp == ' ') - cp++; - if (*cp != ']') - { - for (i = 0; *cp && strchr(">=u.relation.op = nmem_malloc (mem, i+1); - if (i) - memcpy (p->u.relation.op, cp - i, i); - p->u.relation.op[i] = 0; - - while (*cp == ' ') - cp++; - - if (strchr("\"'", *cp)) - { - cp++; - for (i = 0; *cp && !strchr("\"'", *cp); i++) - cp++; - - p->u.relation.value = nmem_malloc (mem, i+1); - if (i) - memcpy (p->u.relation.value, cp - i, i); - p->u.relation.value[i] = 0; - yaz_log (LOG_LOG, "value=%s", p->u.relation.value); - - cp++; - } - else - { - for (i = 0; *cp && !strchr(" ]", *cp); i++) - cp++; - p->u.relation.value = nmem_malloc (mem, i+1); - if (i) - memcpy (p->u.relation.value, cp - i, i); - p->u.relation.value[i] = 0; - } - while (*cp == ' ') - cp++; - } - if (*cp == ']') - cp++; - } /* end of ] predicate */ - no++; - if (*cp != '/') - break; - cp++; - } - return no; + return (parse_xpath_str(use_string, xpath, mem)); } - + + static RSET xpath_trunc(ZebraHandle zh, NMEM stream, int reg_type, const char *term, int use, diff --git a/isamb/isamb.c b/isamb/isamb.c index ca6ba68..4fa613a 100644 --- a/isamb/isamb.c +++ b/isamb/isamb.c @@ -1,4 +1,4 @@ -/* $Id: isamb.c,v 1.21 2002-09-03 19:05:02 adam Exp $ +/* $Id: isamb.c,v 1.22 2003-02-04 12:06:47 pop Exp $ Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002 Index Data Aps @@ -20,7 +20,7 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - +#include #include #include #include diff --git a/recctrl/recgrs.c b/recctrl/recgrs.c index 4f3ab50..ae5a782 100644 --- a/recctrl/recgrs.c +++ b/recctrl/recgrs.c @@ -1,4 +1,4 @@ -/* $Id: recgrs.c,v 1.71 2002-12-16 20:27:18 adam Exp $ +/* $Id: recgrs.c,v 1.72 2003-02-04 12:06:47 pop Exp $ Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002 Index Data Aps @@ -123,6 +123,71 @@ static void grs_destroy(void *clientData) xfree (h); } +int d1_check_xpath_predicate(data1_node *n, struct xpath_predicate *p) { + int res = 1; + char *attname; + data1_xattr *attr; + + if (!p) { + return (1); + } else { + if (p->which == XPATH_PREDICATE_RELATION) { + if (p->u.relation.name[0]) { + if (*p->u.relation.name != '@') { + logf(LOG_WARN, + " Only attributes (@) are supported in xelm xpath predicates"); + logf(LOG_WARN, "predicate %s ignored", p->u.relation.name); + return (1); + } + attname = p->u.relation.name + 1; + res = 0; + /* looking for the attribute with a specified name */ + for (attr = n->u.tag.attributes; attr; attr = attr->next) { + logf(LOG_DEBUG," - attribute %s <-> %s", attname, attr->name ); + + if (!strcmp(attr->name, attname)) { + if (p->u.relation.op[0]) { + if (*p->u.relation.op != '=') { + logf(LOG_WARN, + "Only '=' relation is supported (%s)",p->u.relation.op); + logf(LOG_WARN, "predicate %s ignored", p->u.relation.name); + res = 1; break; + } else { + logf(LOG_DEBUG," - value %s <-> %s", + p->u.relation.value, attr->value ); + if (!strcmp(attr->value, p->u.relation.value)) { + res = 1; break; + } + } + } else { + /* attribute exists, no value specified */ + res = 1; break; + } + } + } + return (res); + } else { + return (1); + } + } + else if (p->which == XPATH_PREDICATE_BOOLEAN) { + if (!strcmp(p->u.boolean.op,"and")) { + return (d1_check_xpath_predicate(n, p->u.boolean.left) + && d1_check_xpath_predicate(n, p->u.boolean.right)); + } + else if (!strcmp(p->u.boolean.op,"or")) { + return (d1_check_xpath_predicate(n, p->u.boolean.left) + || d1_check_xpath_predicate(n, p->u.boolean.right)); + } else { + logf(LOG_WARN, "Unknown boolean relation %s, ignored",p->u.boolean.op); + return (1); + } + } + } + return 0; +} + + /* *ostrich* New function, looking for xpath "element" definitions in abs, by @@ -131,12 +196,24 @@ static void grs_destroy(void *clientData) against the given tagpath. The first matching entry is returned. pop, 2002-12-13 + + Added support for enhanced xelm. Now [] predicates are considered + as well, when selecting indexing rules... (why the hell it's called + termlist???) + + pop, 2003-01-17 + */ data1_termlist *xpath_termlist_by_tagpath(char *tagpath, data1_node *n) { data1_absyn *abs = n->root->u.root.absyn; data1_xpelement *xpe = abs->xp_elements; + data1_node *nn; +#ifdef ENHANCED_XELM + struct xpath_location_step *xp; + +#endif char *pexpr = malloc(strlen(tagpath)+2); int ok = 0; @@ -168,11 +245,43 @@ data1_termlist *xpath_termlist_by_tagpath(char *tagpath, data1_node *n) } while (i >= 0); } pexpr--; - if (ok) break; + if (ok) { +#ifdef ENHANCED_XELM + /* we have to check the perdicates up to the root node */ + xp = xpe->xpath; + + /* find the first tag up in the node structure */ + nn = n; while (nn && nn->which != DATA1N_tag) { + nn = nn->parent; + } + + /* go from inside out in the node structure, while going + backwards trough xpath location steps ... */ + for (i=xpe->xpath_len - 1; i>0; i--) { + + logf(LOG_DEBUG,"Checking step %d: %s on tag %s", + i,xp[i].part,nn->u.tag.tag); + + if (!d1_check_xpath_predicate(nn, xp[i].predicate)) { + logf(LOG_DEBUG," Predicates didn't match"); + ok = 0; + break; + } + + if (nn->which == DATA1N_tag) { + nn = nn->parent; + } + } +#endif + if (ok) { + break; + } + } xpe = xpe->next; } if (ok) { + logf(LOG_DEBUG,"Got it"); return xpe->termlists; } else { return NULL; @@ -237,7 +346,7 @@ static void index_xpath (data1_node *n, struct recExtractCtrl *p, tag_path_full[flen] = 0; /* If we have a matching termlist... */ - if (tl = xpath_termlist_by_tagpath(tag_path_full, n)) { + if ((tl = xpath_termlist_by_tagpath(tag_path_full, n))) { for (; tl; tl = tl->next) { wrd->reg_type = *tl->structure; /* this is the ! case, so structure is for the xpath index */ @@ -354,8 +463,8 @@ static void index_xpath (data1_node *n, struct recExtractCtrl *p, wrd->length = strlen(xp->value); wrd->reg_type = 'w'; - if (tl = xpath_termlist_by_tagpath(attr_tag_path_full, - n)) { + if ((tl = xpath_termlist_by_tagpath(attr_tag_path_full, + n))) { for (; tl; tl = tl->next) { wrd->reg_type = *tl->structure; if (!tl->att) { diff --git a/util/Makefile.am b/util/Makefile.am index 5c859a2..fac1cb9 100644 --- a/util/Makefile.am +++ b/util/Makefile.am @@ -1,4 +1,4 @@ -## $Id: Makefile.am,v 1.6 2002-10-30 14:35:09 adam Exp $ +## $Id: Makefile.am,v 1.7 2003-02-04 12:06:48 pop Exp $ noinst_LIBRARIES = libutil.a @@ -9,6 +9,6 @@ EXTRA_DIST = zebrasrv.rh AM_CPPFLAGS = -I$(srcdir)/../include @YAZINC@ -DDEFAULT_PROFILE_PATH=\"$(pkgdatadir)/tab\" LDADD = libutil.a $(YAZLIB) $(TCL_LIB) -libutil_a_SOURCES = res.c charmap.c zebramap.c passwddb.c zebra-lock.c dirent.c +libutil_a_SOURCES = res.c charmap.c zebramap.c passwddb.c zebra-lock.c dirent.c xpath.c passtest_SOURCES = passtest.c diff --git a/util/xpath.c b/util/xpath.c new file mode 100644 index 0000000..1155cb1 --- /dev/null +++ b/util/xpath.c @@ -0,0 +1,214 @@ +/* $Id: xpath.c,v 1.1 2003-02-04 12:06:48 pop Exp $ + Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002 + Index Data Aps + +This file is part of the Zebra server. + +Zebra is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +Zebra is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Zebra; see the file LICENSE.zebra. If not, write to the +Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. +*/ + + +#include +#include +#include +#include +#include +#include + +char *get_xp_part (char **strs, NMEM mem) { + char *str = *strs; + char *res = '\0'; + char *cp = str; + char *co; + int quoted = 0; + + /* ugly */ + char *sep = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\" "; + + while (*cp == ' ') {cp++; str++;} + if (!strchr("><=] ", *cp)) sep = "><=] "; + + while (*cp && !(strchr(sep,*cp) && !quoted) && (*cp != ']')) { + if (*cp =='"') quoted = 1 - quoted; + cp++; + } + /* removing leading and trailing " */ + co = cp; + if (*str == '"') str++; + if (*(cp-1) == '"') cp--; + if (str < co) { + res = nmem_malloc(mem, cp - str + 1); + memcpy (res, str, (cp-str)); + *(res + (cp-str)) = '\0'; + *strs = co; + } + + return (res); +} + + +struct xpath_predicate *get_xpath_predicate(char *predicates, NMEM mem) { + char *p1; + char *p2; + char *p3; + char *p4; + + struct xpath_predicate *r1; + struct xpath_predicate *r2; + struct xpath_predicate *res = 0; + + char *pr = predicates; + + if ((p1 = get_xp_part(&pr, mem))) { + if ((p2 = get_xp_part(&pr, mem))) { + if (!strcmp (p2, "and") || !strcmp (p2, "or") || !strcmp (p2, "not")) { + r1=nmem_malloc(mem, sizeof(struct xpath_predicate)); + r1->which = XPATH_PREDICATE_RELATION; + r1->u.relation.name = p1; + r1->u.relation.op = ""; + r1->u.relation.value = ""; + + r2 = get_xpath_predicate (pr, mem); + + res = nmem_malloc(mem, sizeof(struct xpath_predicate)); + res->which = XPATH_PREDICATE_BOOLEAN; + res->u.boolean.op = p2; + res->u.boolean.left = r1; + res->u.boolean.right = r2; + + return (res); + } + + if (strchr("><=] ", *p2)) { + r1 = nmem_malloc(mem, sizeof(struct xpath_predicate)); + + r1->which = XPATH_PREDICATE_RELATION; + r1->u.relation.name = p1; + r1->u.relation.op = p2; + + if ((p3 = get_xp_part(&pr, mem))) { + r1->u.relation.value = p3; + } else { + /* error */ + } + } + + if ((p4 = get_xp_part(&pr, mem))) { + if (!strcmp (p4, "and") || !strcmp (p4, "or") || !strcmp (p4, "not")) { + + r2 = get_xpath_predicate (pr, mem); + + res = nmem_malloc(mem, sizeof(struct xpath_predicate)); + res->which = XPATH_PREDICATE_BOOLEAN; + res->u.boolean.op = p4; + res->u.boolean.left = r1; + res->u.boolean.right = r2; + return (res); + } else { + /* error */ + } + } else { + return (r1); + } + + } else { + r1 = nmem_malloc(mem, sizeof(struct xpath_predicate)); + + r1->which = XPATH_PREDICATE_RELATION; + r1->u.relation.name = p1; + r1->u.relation.op = ""; + r1->u.relation.value = ""; + + return (r1); + } + } + return 0; +} + +int parse_xpath_str(const char *xpath_string, + struct xpath_location_step *xpath, NMEM mem) +{ + const char *cp; + char *a; + + int no = 0; + + if (!xpath_string || *xpath_string != '/') + return -1; + cp = xpath_string; + + while (*cp) + { + int i = 0; + while (*cp && !strchr("/[",*cp)) + { + i++; + cp++; + } + xpath[no].predicate = 0; + xpath[no].part = nmem_malloc (mem, i+1); + memcpy (xpath[no].part, cp - i, i); + xpath[no].part[i] = 0; + + if (*cp == '[') + { + cp++; + while (*cp == ' ') + cp++; + + a = (char *)cp; + xpath[no].predicate = get_xpath_predicate(a, mem); + while(*cp && *cp != ']') { + cp++; + } + if (*cp == ']') + cp++; + } /* end of ] predicate */ + no++; + if (*cp != '/') + break; + cp++; + } + return no; +} + +void dump_xp_predicate (struct xpath_predicate *p) { + if (p) { + if (p->which == XPATH_PREDICATE_RELATION && + p->u.relation.name[0]) { + fprintf (stderr, "%s,%s,%s", + p->u.relation.name, + p->u.relation.op, + p->u.relation.value); + } else { + fprintf (stderr, "("); + dump_xp_predicate(p->u.boolean.left); + fprintf (stderr, ") %s (", p->u.boolean.op); + dump_xp_predicate(p->u.boolean.right); + fprintf (stderr, ")"); + } + } +} + +void dump_xp_steps (struct xpath_location_step *xpath, int no) { + int i; + for (i=0; i