+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 != '@') {
+ yaz_log(YLOG_WARN,
+ " Only attributes (@) are supported in xelm xpath predicates");
+ yaz_log(YLOG_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) {
+ yaz_log(YLOG_DEBUG," - attribute %s <-> %s", attname, attr->name );
+
+ if (!strcmp(attr->name, attname)) {
+ if (p->u.relation.op[0]) {
+ if (*p->u.relation.op != '=') {
+ yaz_log(YLOG_WARN,
+ "Only '=' relation is supported (%s)",p->u.relation.op);
+ yaz_log(YLOG_WARN, "predicate %s ignored", p->u.relation.name);
+ res = 1; break;
+ } else {
+ yaz_log(YLOG_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;
+ }
+ }
+ }
+ yaz_log(YLOG_DEBUG, "return %d", res);
+ 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 {
+ yaz_log(YLOG_WARN, "Unknown boolean relation %s, ignored",p->u.boolean.op);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+
+static int dfa_match_first(struct DFA_state **dfaar, const char *text)
+{
+ struct DFA_state *s = dfaar[0]; /* start state */
+ struct DFA_tran *t;
+ int i;
+ const char *p = text;
+ unsigned char c;
+
+ for (c = *p++, t = s->trans, i = s->tran_no; --i >= 0; t++)
+ {
+ if (c >= t->ch[0] && c <= t->ch[1])
+ {
+ while (i >= 0)
+ {
+ /* move to next state and return if we get a match */
+ s = dfaar[t->to];
+ if (s->rule_no)
+ return 1;
+ /* next char */
+ if (!c)
+ return 0;
+ c = *p++;
+ for (t = s->trans, i = s->tran_no; --i >= 0; t++)
+ if (c >= t->ch[0] && c <= t->ch[1])
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+/* *ostrich*
+
+New function, looking for xpath "element" definitions in abs, by
+tagpath, using a kind of ugly regxp search.The DFA was built while
+parsing abs, so here we just go trough them and try to match
+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 = xmalloc(strlen(tagpath)+5);
+ int ok = 0;
+
+ sprintf (pexpr, "/%s\n", tagpath);
+ for (; xpe; xpe = xpe->next)
+ {
+ int i;
+ ok = dfa_match_first(xpe->dfa->states, pexpr);
+
+ 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 */
+ for (nn = n; 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--)
+ {
+ yaz_log(YLOG_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))
+ {
+ yaz_log(YLOG_DEBUG, " Predicates didn't match");
+ ok = 0;
+ break;
+ }
+
+ if (nn->which == DATA1N_tag)
+ nn = nn->parent;
+ }
+#endif
+ if (ok)
+ break;
+ }
+ }
+
+ xfree(pexpr);
+
+ if (ok) {
+ yaz_log(YLOG_DEBUG, "Got it");
+ return xpe->termlists;
+ } else {
+ return NULL;
+ }
+}
+
+/* use
+ 1 start element (tag)
+ 2 end element
+ 3 start attr (and attr-exact)
+ 4 end attr
+
+ 1016 cdata
+ 1015 attr data
+
+ *ostrich*
+
+ Now, if there is a matching xelm described in abs, for the
+ indexed element or the attribute, then the data is handled according
+ to those definitions...
+
+ modified by pop, 2002-12-13
+*/
+
+/* add xpath index for an attribute */
+static void index_xpath_attr (char *tag_path, char *name, char *value,
+ char *structure, struct recExtractCtrl *p,
+ RecWord *wrd)
+{
+#if NATTR
+ wrd->index_name = ZEBRA_XPATH_ELM_BEGIN;
+#else
+ wrd->attrSet = VAL_IDXPATH;
+ wrd->attrUse = 1;