package query import ( "reflect" "goutil/xmlUtil/gxpath/xpath" ) // An XPath query interface. type Query interface { // Select traversing Iterator returns a query matched node xpath.NodeNavigator. Select(Iterator) xpath.NodeNavigator // Evaluate evaluates query and returns values of the current query. Evaluate(Iterator) interface{} // Test checks a specified xpath.NodeNavigator can passed by the current query. //Test(xpath.NodeNavigator) bool } // ContextQuery is returns current node on the Iterator object query. type ContextQuery struct { count int Root bool // Moving to root-level node in the current context Iterator. } func (c *ContextQuery) Select(t Iterator) (n xpath.NodeNavigator) { if c.count == 0 { c.count++ n = t.Current().Copy() if c.Root { n.MoveToRoot() } } return n } func (c *ContextQuery) Evaluate(Iterator) interface{} { c.count = 0 return c } // AncestorQuery is an XPath ancestor node query.(ancestor::*|ancestor-self::*) type AncestorQuery struct { iterator func() xpath.NodeNavigator Self bool Input Query Predicate func(xpath.NodeNavigator) bool } func (a *AncestorQuery) Select(t Iterator) xpath.NodeNavigator { for { if a.iterator == nil { node := a.Input.Select(t) if node == nil { return nil } first := true a.iterator = func() xpath.NodeNavigator { if first && a.Self { first = false if a.Predicate(node) { return node } } for node.MoveToParent() { if !a.Predicate(node) { break } return node } return nil } } if node := a.iterator(); node != nil { return node } a.iterator = nil } } func (a *AncestorQuery) Evaluate(t Iterator) interface{} { a.Input.Evaluate(t) return a } func (a *AncestorQuery) Test(n xpath.NodeNavigator) bool { return a.Predicate(n) } // AttributeQuery is an XPath attribute node query.(@*) type AttributeQuery struct { iterator func() xpath.NodeNavigator Input Query Predicate func(xpath.NodeNavigator) bool } func (a *AttributeQuery) Select(t Iterator) xpath.NodeNavigator { for { if a.iterator == nil { node := a.Input.Select(t) if node == nil { return nil } node = node.Copy() a.iterator = func() xpath.NodeNavigator { for { onAttr := node.MoveToNextAttribute() if !onAttr { return nil } if a.Predicate(node) { return node } } } } if node := a.iterator(); node != nil { return node } a.iterator = nil } } func (a *AttributeQuery) Evaluate(t Iterator) interface{} { a.Input.Evaluate(t) a.iterator = nil return a } func (a *AttributeQuery) Test(n xpath.NodeNavigator) bool { return a.Predicate(n) } // ChildQuery is an XPath child node query.(child::*) type ChildQuery struct { posit int iterator func() xpath.NodeNavigator Input Query Predicate func(xpath.NodeNavigator) bool } func (c *ChildQuery) Select(t Iterator) xpath.NodeNavigator { for { if c.iterator == nil { c.posit = 0 node := c.Input.Select(t) if node == nil { return nil } node = node.Copy() first := true c.iterator = func() xpath.NodeNavigator { for { if (first && !node.MoveToChild()) || (!first && !node.MoveToNext()) { return nil } first = false if c.Predicate(node) { return node } } } } if node := c.iterator(); node != nil { c.posit++ return node } c.iterator = nil } } func (c *ChildQuery) Evaluate(t Iterator) interface{} { c.Input.Evaluate(t) c.iterator = nil return c } func (c *ChildQuery) Test(n xpath.NodeNavigator) bool { return c.Predicate(n) } // position returns a position of current xpath.NodeNavigator. func (c *ChildQuery) position() int { return c.posit } // DescendantQuery is an XPath descendant node query.(descendant::* | descendant-or-self::*) type DescendantQuery struct { iterator func() xpath.NodeNavigator Self bool Input Query Predicate func(xpath.NodeNavigator) bool } func (d *DescendantQuery) Select(t Iterator) xpath.NodeNavigator { for { if d.iterator == nil { node := d.Input.Select(t) if node == nil { return nil } node = node.Copy() level := 0 first := true d.iterator = func() xpath.NodeNavigator { if first && d.Self { first = false if d.Predicate(node) { return node } } for { if node.MoveToChild() { level++ } else { for { if level == 0 { return nil } if node.MoveToNext() { break } node.MoveToParent() level-- } } if d.Predicate(node) { return node } } } } if node := d.iterator(); node != nil { return node } d.iterator = nil } } func (d *DescendantQuery) Evaluate(t Iterator) interface{} { d.Input.Evaluate(t) d.iterator = nil return d } func (d *DescendantQuery) Test(n xpath.NodeNavigator) bool { return d.Predicate(n) } // FollowingQuery is an XPath following node query.(following::*|following-sibling::*) type FollowingQuery struct { iterator func() xpath.NodeNavigator Input Query Sibling bool // The matching sibling node of current node. Predicate func(xpath.NodeNavigator) bool } func (f *FollowingQuery) Select(t Iterator) xpath.NodeNavigator { for { if f.iterator == nil { node := f.Input.Select(t) if node == nil { return nil } node = node.Copy() if f.Sibling { f.iterator = func() xpath.NodeNavigator { for { if !node.MoveToNext() { return nil } if f.Predicate(node) { return node } } } } else { var q Query // descendant query f.iterator = func() xpath.NodeNavigator { for { if q == nil { for !node.MoveToNext() { if !node.MoveToParent() { return nil } } q = &DescendantQuery{ Self: true, Input: &ContextQuery{}, Predicate: f.Predicate, } t.Current().MoveTo(node) } if node := q.Select(t); node != nil { return node } q = nil } } } } if node := f.iterator(); node != nil { return node } f.iterator = nil } } func (f *FollowingQuery) Evaluate(t Iterator) interface{} { f.Input.Evaluate(t) return f } func (f *FollowingQuery) Test(n xpath.NodeNavigator) bool { return f.Predicate(n) } // PrecedingQuery is an XPath preceding node query.(preceding::*) type PrecedingQuery struct { iterator func() xpath.NodeNavigator Input Query Sibling bool // The matching sibling node of current node. Predicate func(xpath.NodeNavigator) bool } func (p *PrecedingQuery) Select(t Iterator) xpath.NodeNavigator { for { if p.iterator == nil { node := p.Input.Select(t) if node == nil { return nil } node = node.Copy() if p.Sibling { p.iterator = func() xpath.NodeNavigator { for { for !node.MoveToPrevious() { return nil } if p.Predicate(node) { return node } } } } else { var q Query p.iterator = func() xpath.NodeNavigator { for { if q == nil { for !node.MoveToPrevious() { if !node.MoveToParent() { return nil } } q = &DescendantQuery{ Self: true, Input: &ContextQuery{}, Predicate: p.Predicate, } t.Current().MoveTo(node) } if node := q.Select(t); node != nil { return node } q = nil } } } } if node := p.iterator(); node != nil { return node } p.iterator = nil } } func (p *PrecedingQuery) Evaluate(t Iterator) interface{} { p.Input.Evaluate(t) return p } func (p *PrecedingQuery) Test(n xpath.NodeNavigator) bool { return p.Predicate(n) } // ParentQuery is an XPath parent node query.(parent::*) type ParentQuery struct { Input Query Predicate func(xpath.NodeNavigator) bool } func (p *ParentQuery) Select(t Iterator) xpath.NodeNavigator { for { node := p.Input.Select(t) if node == nil { return nil } node = node.Copy() if node.MoveToParent() && p.Predicate(node) { return node } } } func (p *ParentQuery) Evaluate(t Iterator) interface{} { p.Input.Evaluate(t) return p } func (p *ParentQuery) Test(n xpath.NodeNavigator) bool { return p.Predicate(n) } // SelfQuery is an Self node query.(self::*) type SelfQuery struct { Input Query Predicate func(xpath.NodeNavigator) bool } func (s *SelfQuery) Select(t Iterator) xpath.NodeNavigator { for { node := s.Input.Select(t) if node == nil { return nil } if s.Predicate(node) { return node } } } func (s *SelfQuery) Evaluate(t Iterator) interface{} { s.Input.Evaluate(t) return s } func (s *SelfQuery) Test(n xpath.NodeNavigator) bool { return s.Predicate(n) } // FilterQuery is an XPath query for predicate filter. type FilterQuery struct { Input Query Predicate Query } func (f *FilterQuery) do(t Iterator) bool { val := reflect.ValueOf(f.Predicate.Evaluate(t)) switch val.Kind() { case reflect.Bool: return val.Bool() case reflect.String: return len(val.String()) > 0 case reflect.Float64: pt := float64(getNodePosition(f.Input)) return int(val.Float()) == int(pt) default: if q, ok := f.Predicate.(Query); ok { return q.Select(t) != nil } } return false } func (f *FilterQuery) Select(t Iterator) xpath.NodeNavigator { for { node := f.Input.Select(t) if node == nil { return node } node = node.Copy() //fmt.Println(node.LocalName()) t.Current().MoveTo(node) if f.do(t) { return node } } } func (f *FilterQuery) Evaluate(t Iterator) interface{} { f.Input.Evaluate(t) return f } // FunctionQuery is an XPath function that call a function to returns // value of current xpath.NodeNavigator node. type XPathFunction struct { Input Query // Node Set Func func(Query, Iterator) interface{} // The xpath function. } func (f *XPathFunction) Select(t Iterator) xpath.NodeNavigator { return nil } // Evaluate call a specified function that will returns the // following value type: number,string,boolean. func (f *XPathFunction) Evaluate(t Iterator) interface{} { return f.Func(f.Input, t) } // XPathConstant is an XPath constant operand. type XPathConstant struct { Val interface{} } func (c *XPathConstant) Select(t Iterator) xpath.NodeNavigator { return nil } func (c *XPathConstant) Evaluate(t Iterator) interface{} { return c.Val } // LogicalExpr is an XPath logical expression. type LogicalExpr struct { Left, Right Query Do func(Iterator, interface{}, interface{}) interface{} } func (l *LogicalExpr) Select(t Iterator) xpath.NodeNavigator { // When a XPath expr is logical expression. node := t.Current().Copy() val := l.Evaluate(t) switch val.(type) { case bool: if val.(bool) == true { return node } } return nil } func (l *LogicalExpr) Evaluate(t Iterator) interface{} { m := l.Left.Evaluate(t) n := l.Right.Evaluate(t) return l.Do(t, m, n) } // NumericExpr is an XPath numeric operator expression. type NumericExpr struct { Left, Right Query Do func(interface{}, interface{}) interface{} } func (n *NumericExpr) Select(t Iterator) xpath.NodeNavigator { return nil } func (n *NumericExpr) Evaluate(t Iterator) interface{} { m := n.Left.Evaluate(t) k := n.Right.Evaluate(t) return n.Do(m, k) } type BooleanExpr struct { IsOr bool Left, Right Query iterator func() xpath.NodeNavigator } func (b *BooleanExpr) Select(t Iterator) xpath.NodeNavigator { if b.iterator == nil { var list []xpath.NodeNavigator i := 0 root := t.Current().Copy() if b.IsOr { for { node := b.Left.Select(t) if node == nil { break } node = node.Copy() list = append(list, node) } t.Current().MoveTo(root) for { node := b.Right.Select(t) if node == nil { break } node = node.Copy() list = append(list, node) } } else { var m []xpath.NodeNavigator var n []xpath.NodeNavigator for { node := b.Left.Select(t) if node == nil { break } node = node.Copy() list = append(m, node) } t.Current().MoveTo(root) for { node := b.Right.Select(t) if node == nil { break } node = node.Copy() list = append(n, node) } for _, k := range m { for _, j := range n { if k == j { list = append(list, k) } } } } b.iterator = func() xpath.NodeNavigator { if i >= len(list) { return nil } node := list[i] i++ return node } } return b.iterator() } func (b *BooleanExpr) Evaluate(t Iterator) interface{} { m := b.Left.Evaluate(t) if m.(bool) == b.IsOr { return m } return b.Right.Evaluate(t) } func getNodePosition(q Query) int { type Position interface { position() int } if count, ok := q.(Position); ok { return count.position() } return 1 }