ref: ce4a8027322c53b2832f221e2956c90dcd65fd1a
dir: /libxpath/xmllookpath.c/
#include <u.h> #include <libc.h> #include <xml.h> #include <xpath.h> #include "dat.h" static XpResult recurse(Elem*, Node*); static int bufsize(int m) { int b = 32; return (m/b + 1) * b; } static void dbgprintnode(Elem *e) { Attr *a; fprint(2, "<%s", e->name); for (a = e->attrs; a; a = a->next) fprint(2, " %s='%s'", a->name, a->value); fprint(2, " />"); } static char* resulttypestring(int type) { switch (type) { case Xelem: return "elem"; case Xstring: return "string"; case Xnum: return "num"; } return "invalid"; } static void appendresult(XpResult *a, XpResult b) { int n; if (b.num < 1) return; if (!a->type) { *a = b; goto Out; } if (a->type != b.type) sysfatal("error: incompatible type"); n = a->num + b.num; switch (a->type) { case Xelem: if (n >= a->size) { a->elems = realloc(a->elems, bufsize(n) * sizeof(Elem*)); } memcpy(&a->elems[a->num], b.elems, b.num * sizeof(Elem*)); a->num = n; free(b.elems); break; case Xstring: if (n >= a->size) { a->strings = realloc(a->strings, bufsize(n) * sizeof(char*)); } memcpy(&a->strings[a->num], b.strings, b.num * sizeof(char*)); a->num = n; free(b.strings); break; case Xnum: if (n >= a->size) { a->numbers = realloc(a->numbers, bufsize(n) * sizeof(int)); } memcpy(&a->numbers[a->num], b.numbers, b.num * sizeof(int)); a->num = n; free(b.numbers); break; } Out: if (xmldebug) { fprint(2, "appendresult:\n"); fprint(2, " type: %s\n", resulttypestring(a->type)); switch (a->type) { case Xelem: for (n = 0; n < a->num; n++) { fprint(2, " e: "); dbgprintnode(a->elems[n]); fprint(2, "\n"); } break; case Xstring: for (n = 0; n < a->num; n++) { fprint(2, " s: %s\n", a->strings[n]); } break; case Xnum: for (n = 0; n < a->num; n++) { fprint(2, " n: %d\n", a->numbers[n]); } break; } } } static XpResult getattrvalue(Elem *ep, char *attr) { XpResult r; Attr *a; r.type = 0; for (a = ep->attrs; a; a = a->next) if (strcmp(a->name, attr) == 0) { buildsinglestring(&r, a->value); return r; } return r; } static int equals(Elem *e, Cond *c) { XpResult ra, rb; int n; if (c->anode && c->bnode) { ra = recurse(e, c->anode); rb = recurse(e, c->bnode); if (ra.num != 1) { return 0; } if (rb.num != 1) { return 0; } if (ra.type != rb.type) { werrstr("equals: A.type != B.type (%s != %s)\n", resulttypestring(ra.type), resulttypestring(rb.type)); return 0; } if (ra.type == Xstring) return strcmp(ra.strings[0], rb.strings[0]) == 0; if (ra.type == Xelem) return ra.elems[0] == rb.elems[0]; if (ra.type == Xnum) return ra.numbers[0] == rb.numbers[0]; sysfatal("code error"); } return 0; } static int evalcond(Elem *e, Cond *c) { Attr *a; if (!c) return 1; switch (c->type) { case CTand: return evalcond(e, c->a) && evalcond(e, c->b); case CTor: return evalcond(e, c->a) || evalcond(e, c->b); case CTindex: return position(e) == c->index; break; case CTattr: for (a = e->attrs; a; a = a->next) if (strcmp(a->name, c->attr->name) == 0 && strcmp(a->value, c->value->name) == 0) return 1; return 0; case CThasattr: for (a = e->attrs; a; a = a->next) if (strcmp(a->name, c->attr->name) == 0) return 1; return 0; case CTeq: return equals(e, c); } werrstr("unhandled predicate condition: %d\n", c->type); return 1; } static XpResult recurse(Elem *ep, Node *n) { XpResult r; char *s; memset(&r, 0, sizeof(XpResult)); if (!n) { buildsingleelem(&r, ep); return r; } if (n->type == Nroot) { while (ep->parent) ep = ep->parent; r = recurse(ep, n->chain); return r; } if (n->type == Nattribute) { return getattrvalue(ep, n->name->name); } if (n->type == Nfunction) { if (!(n->func && n->func->f)) sysfatal("error: no valid func"); n->func->f(&r, ep); return r; } if (n->type == Ndescself) { /* descendant or self */ for (Elem *e = ep->child; e; e = e->next) { if (strcmp(e->name, n->name->name) == 0 && evalcond(e, n->cond)) { /* if found, proceed with next rule */ appendresult(&r, recurse(e, n->chain)); } /* search for more occuring children */ appendresult(&r, recurse(e, n)); } return r; } if (n->type == Nchild) { for (Elem *e = ep->child; e; e = e->next) if (strcmp(e->name, n->name->name) == 0 && evalcond(e, n->cond)) { appendresult(&r, recurse(e, n->chain)); } return r; } if (n->type == Nstring) { buildsinglestring(&r, n->name->name); return r; } if (n->type == Nnumber) { buildsinglenum(&r, n->number); return r; } return r; } /* * search for element using XPath, starting at ep. */ XpResult xmllookpath(Elem *ep, char *path) { Node *nodes; Elem *p, root; XpResult r; char err[2]; memset(&r, 0, sizeof(XpResult)); nodes = parsexpath(path); if (!nodes) { r.error = 1; return r; } if (xmldebug) debugprintnodes(nil); p = ep; while (p->parent) p = p->parent; memset(&root, 0, sizeof(Elem)); root.child = p; p->parent = &root; r = recurse(ep, nodes); rerrstr(err, sizeof(err)); if (*err) r.error = 1; root.child = nil; p->parent = nil; return r; }