1package execxp 2 3import ( 4 "encoding/xml" 5 "fmt" 6 "strconv" 7 "strings" 8 9 "github.com/ChrisTrenkamp/goxpath/internal/execxp/findutil" 10 "github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns" 11 "github.com/ChrisTrenkamp/goxpath/internal/xsort" 12 "github.com/ChrisTrenkamp/goxpath/lexer" 13 "github.com/ChrisTrenkamp/goxpath/parser" 14 "github.com/ChrisTrenkamp/goxpath/parser/pathexpr" 15 "github.com/ChrisTrenkamp/goxpath/tree" 16 "github.com/ChrisTrenkamp/goxpath/xconst" 17) 18 19type xpFilt struct { 20 t tree.Node 21 ctx tree.Result 22 expr pathexpr.PathExpr 23 ns map[string]string 24 ctxPos int 25 ctxSize int 26 proxPos map[int]int 27 fns map[xml.Name]tree.Wrap 28 variables map[string]tree.Result 29} 30 31type xpExecFn func(*xpFilt, string) 32 33var xpFns = map[lexer.XItemType]xpExecFn{ 34 lexer.XItemAbsLocPath: xfAbsLocPath, 35 lexer.XItemAbbrAbsLocPath: xfAbbrAbsLocPath, 36 lexer.XItemRelLocPath: xfRelLocPath, 37 lexer.XItemAbbrRelLocPath: xfAbbrRelLocPath, 38 lexer.XItemAxis: xfAxis, 39 lexer.XItemAbbrAxis: xfAbbrAxis, 40 lexer.XItemNCName: xfNCName, 41 lexer.XItemQName: xfQName, 42 lexer.XItemNodeType: xfNodeType, 43 lexer.XItemProcLit: xfProcInstLit, 44 lexer.XItemStrLit: xfStrLit, 45 lexer.XItemNumLit: xfNumLit, 46} 47 48func xfExec(f *xpFilt, n *parser.Node) (err error) { 49 for n != nil { 50 if fn, ok := xpFns[n.Val.Typ]; ok { 51 fn(f, n.Val.Val) 52 n = n.Left 53 } else if n.Val.Typ == lexer.XItemPredicate { 54 if err = xfPredicate(f, n.Left); err != nil { 55 return 56 } 57 58 n = n.Right 59 } else if n.Val.Typ == lexer.XItemFunction { 60 if err = xfFunction(f, n); err != nil { 61 return 62 } 63 64 n = n.Right 65 } else if n.Val.Typ == lexer.XItemOperator { 66 lf := xpFilt{ 67 t: f.t, 68 ns: f.ns, 69 ctx: f.ctx, 70 ctxPos: f.ctxPos, 71 ctxSize: f.ctxSize, 72 proxPos: f.proxPos, 73 fns: f.fns, 74 variables: f.variables, 75 } 76 left, err := exec(&lf, n.Left) 77 if err != nil { 78 return err 79 } 80 81 rf := xpFilt{ 82 t: f.t, 83 ns: f.ns, 84 ctx: f.ctx, 85 fns: f.fns, 86 variables: f.variables, 87 } 88 right, err := exec(&rf, n.Right) 89 if err != nil { 90 return err 91 } 92 93 return xfOperator(left, right, f, n.Val.Val) 94 } else if n.Val.Typ == lexer.XItemVariable { 95 if res, ok := f.variables[n.Val.Val]; ok { 96 f.ctx = res 97 return nil 98 } 99 return fmt.Errorf("Invalid variable '%s'", n.Val.Val) 100 } else if string(n.Val.Typ) == "" { 101 n = n.Left 102 //} else { 103 // return fmt.Errorf("Cannot process " + string(n.Val.Typ)) 104 } 105 } 106 107 return 108} 109 110func xfPredicate(f *xpFilt, n *parser.Node) (err error) { 111 res := f.ctx.(tree.NodeSet) 112 newRes := make(tree.NodeSet, 0, len(res)) 113 114 for i := range res { 115 pf := xpFilt{ 116 t: f.t, 117 ns: f.ns, 118 ctxPos: i, 119 ctxSize: f.ctxSize, 120 ctx: tree.NodeSet{res[i]}, 121 fns: f.fns, 122 variables: f.variables, 123 } 124 125 predRes, err := exec(&pf, n) 126 if err != nil { 127 return err 128 } 129 130 ok, err := checkPredRes(predRes, f, res[i]) 131 if err != nil { 132 return err 133 } 134 135 if ok { 136 newRes = append(newRes, res[i]) 137 } 138 } 139 140 f.proxPos = make(map[int]int) 141 for pos, j := range newRes { 142 f.proxPos[j.Pos()] = pos + 1 143 } 144 145 f.ctx = newRes 146 f.ctxSize = len(newRes) 147 148 return 149} 150 151func checkPredRes(ret tree.Result, f *xpFilt, node tree.Node) (bool, error) { 152 if num, ok := ret.(tree.Num); ok { 153 if float64(f.proxPos[node.Pos()]) == float64(num) { 154 return true, nil 155 } 156 return false, nil 157 } 158 159 if b, ok := ret.(tree.IsBool); ok { 160 return bool(b.Bool()), nil 161 } 162 163 return false, fmt.Errorf("Cannot convert argument to boolean") 164} 165 166func xfFunction(f *xpFilt, n *parser.Node) error { 167 spl := strings.Split(n.Val.Val, ":") 168 var name xml.Name 169 if len(spl) == 1 { 170 name.Local = spl[0] 171 } else { 172 name.Space = f.ns[spl[0]] 173 name.Local = spl[1] 174 } 175 fn, ok := intfns.BuiltIn[name] 176 if !ok { 177 fn, ok = f.fns[name] 178 } 179 180 if ok { 181 args := []tree.Result{} 182 param := n.Left 183 184 for param != nil { 185 pf := xpFilt{ 186 t: f.t, 187 ctx: f.ctx, 188 ns: f.ns, 189 ctxPos: f.ctxPos, 190 ctxSize: f.ctxSize, 191 fns: f.fns, 192 variables: f.variables, 193 } 194 res, err := exec(&pf, param.Left) 195 if err != nil { 196 return err 197 } 198 199 args = append(args, res) 200 param = param.Right 201 } 202 203 filt, err := fn.Call(tree.Ctx{NodeSet: f.ctx.(tree.NodeSet), Size: f.ctxSize, Pos: f.ctxPos + 1}, args...) 204 f.ctx = filt 205 return err 206 } 207 208 return fmt.Errorf("Unknown function: %s", n.Val.Val) 209} 210 211var eqOps = map[string]bool{ 212 "=": true, 213 "!=": true, 214} 215 216var booleanOps = map[string]bool{ 217 "=": true, 218 "!=": true, 219 "<": true, 220 "<=": true, 221 ">": true, 222 ">=": true, 223} 224 225var numOps = map[string]bool{ 226 "*": true, 227 "div": true, 228 "mod": true, 229 "+": true, 230 "-": true, 231 "=": true, 232 "!=": true, 233 "<": true, 234 "<=": true, 235 ">": true, 236 ">=": true, 237} 238 239var andOrOps = map[string]bool{ 240 "and": true, 241 "or": true, 242} 243 244func xfOperator(left, right tree.Result, f *xpFilt, op string) error { 245 if booleanOps[op] { 246 lNode, lOK := left.(tree.NodeSet) 247 rNode, rOK := right.(tree.NodeSet) 248 if lOK && rOK { 249 return bothNodeOperator(lNode, rNode, f, op) 250 } 251 252 if lOK { 253 return leftNodeOperator(lNode, right, f, op) 254 } 255 256 if rOK { 257 return rightNodeOperator(left, rNode, f, op) 258 } 259 260 if eqOps[op] { 261 return equalsOperator(left, right, f, op) 262 } 263 } 264 265 if numOps[op] { 266 return numberOperator(left, right, f, op) 267 } 268 269 if andOrOps[op] { 270 return andOrOperator(left, right, f, op) 271 } 272 273 //if op == "|" { 274 return unionOperator(left, right, f, op) 275 //} 276 277 //return fmt.Errorf("Unknown operator " + op) 278} 279 280func xfAbsLocPath(f *xpFilt, val string) { 281 i := f.t 282 for i.GetNodeType() != tree.NtRoot { 283 i = i.GetParent() 284 } 285 f.ctx = tree.NodeSet{i} 286} 287 288func xfAbbrAbsLocPath(f *xpFilt, val string) { 289 i := f.t 290 for i.GetNodeType() != tree.NtRoot { 291 i = i.GetParent() 292 } 293 f.ctx = tree.NodeSet{i} 294 f.expr = abbrPathExpr() 295 find(f) 296} 297 298func xfRelLocPath(f *xpFilt, val string) { 299} 300 301func xfAbbrRelLocPath(f *xpFilt, val string) { 302 f.expr = abbrPathExpr() 303 find(f) 304} 305 306func xfAxis(f *xpFilt, val string) { 307 f.expr.Axis = val 308} 309 310func xfAbbrAxis(f *xpFilt, val string) { 311 f.expr.Axis = xconst.AxisAttribute 312} 313 314func xfNCName(f *xpFilt, val string) { 315 f.expr.Name.Space = val 316} 317 318func xfQName(f *xpFilt, val string) { 319 f.expr.Name.Local = val 320 find(f) 321} 322 323func xfNodeType(f *xpFilt, val string) { 324 f.expr.NodeType = val 325 find(f) 326} 327 328func xfProcInstLit(f *xpFilt, val string) { 329 filt := tree.NodeSet{} 330 for _, i := range f.ctx.(tree.NodeSet) { 331 if i.GetToken().(xml.ProcInst).Target == val { 332 filt = append(filt, i) 333 } 334 } 335 f.ctx = filt 336} 337 338func xfStrLit(f *xpFilt, val string) { 339 f.ctx = tree.String(val) 340} 341 342func xfNumLit(f *xpFilt, val string) { 343 num, _ := strconv.ParseFloat(val, 64) 344 f.ctx = tree.Num(num) 345} 346 347func abbrPathExpr() pathexpr.PathExpr { 348 return pathexpr.PathExpr{ 349 Name: xml.Name{}, 350 Axis: xconst.AxisDescendentOrSelf, 351 NodeType: xconst.NodeTypeNode, 352 } 353} 354 355func find(f *xpFilt) { 356 dupFilt := make(map[int]tree.Node) 357 f.proxPos = make(map[int]int) 358 359 if f.expr.Axis == "" && f.expr.NodeType == "" && f.expr.Name.Space == "" { 360 if f.expr.Name.Local == "." { 361 f.expr = pathexpr.PathExpr{ 362 Name: xml.Name{}, 363 Axis: xconst.AxisSelf, 364 NodeType: xconst.NodeTypeNode, 365 } 366 } 367 368 if f.expr.Name.Local == ".." { 369 f.expr = pathexpr.PathExpr{ 370 Name: xml.Name{}, 371 Axis: xconst.AxisParent, 372 NodeType: xconst.NodeTypeNode, 373 } 374 } 375 } 376 377 f.expr.NS = f.ns 378 379 for _, i := range f.ctx.(tree.NodeSet) { 380 for pos, j := range findutil.Find(i, f.expr) { 381 dupFilt[j.Pos()] = j 382 f.proxPos[j.Pos()] = pos + 1 383 } 384 } 385 386 res := make(tree.NodeSet, 0, len(dupFilt)) 387 for _, i := range dupFilt { 388 res = append(res, i) 389 } 390 391 xsort.SortNodes(res) 392 393 f.expr = pathexpr.PathExpr{} 394 f.ctxSize = len(res) 395 f.ctx = res 396} 397