diff options
author | Brett Vickers <brett@arena.net> | 2017-05-11 13:24:51 -0700 |
---|---|---|
committer | Brett Vickers <brett@arena.net> | 2017-05-11 13:28:47 -0700 |
commit | 09746331a38f3da8c023a85a65c8c152070de725 (patch) | |
tree | cc0bc9c854c851da7369322dead173982ac7ec09 | |
parent | cda1c0026246bd095961ef9a3c430e50d0e80fba (diff) | |
download | go-etree-09746331a38f3da8c023a85a65c8c152070de725.tar.gz |
path: add text filters
It is now possible to use a path filter like [text()='val'] to
select elements whose text matches a string.
-rw-r--r-- | path.go | 31 | ||||
-rw-r--r-- | path_test.go | 2 |
2 files changed, 31 insertions, 2 deletions
@@ -25,7 +25,8 @@ only the following limited syntax is supported: [@attrib='val'] Selects all elements with the given attribute set to val [tag] Selects all elements with a child element named tag [tag='val'] Selects all elements with a child element named tag - and text equal to val + and text matching val + [text()='val'] Selects all elements whose text matches val Examples: @@ -41,9 +42,14 @@ Starting from the current element, select all children of book elements with an attribute 'language' set to 'english': ./book/*[@language='english'] +Starting from the current element, select all children of book elements +containing the text 'special': + ./book/*[text()='special'] + Select all descendant book elements whose title element has an attribute 'language' set to 'french': //book/title[@language='french']/.. + */ type Path struct { segments []segment @@ -254,7 +260,7 @@ func (c *compiler) parseFilter(path string) filter { return nil } - // Filter contains [@attr='val'] or [tag='val']? + // Filter contains [@attr='val'], [text()='val'], or [tag='val']? eqindex := strings.Index(path, "='") if eqindex >= 0 { rindex := nextIndex(path, "'", eqindex+2) @@ -265,6 +271,8 @@ func (c *compiler) parseFilter(path string) filter { switch { case path[0] == '@': return newFilterAttrVal(path[1:eqindex], path[eqindex+2:rindex]) + case strings.HasPrefix(path, "text()"): + return newFilterTextVal(path[eqindex+2 : rindex]) default: return newFilterChildText(path[:eqindex], path[eqindex+2:rindex]) } @@ -420,6 +428,25 @@ func (f *filterAttrVal) apply(p *pather) { p.candidates, p.scratch = p.scratch, p.candidates[0:0] } +// filterTextVal filters the candidate list for elements having +// text equal to the specified value. +type filterTextVal struct { + val string +} + +func newFilterTextVal(value string) *filterTextVal { + return &filterTextVal{value} +} + +func (f *filterTextVal) apply(p *pather) { + for _, c := range p.candidates { + if c.Text() == f.val { + p.scratch = append(p.scratch, c) + } + } + p.candidates, p.scratch = p.scratch, p.candidates[0:0] +} + // filterChild filters the candidate list for elements having // a child element with the specified tag. type filterChild struct { diff --git a/path_test.go b/path_test.go index 60abf57..12a4e21 100644 --- a/path_test.go +++ b/path_test.go @@ -93,6 +93,8 @@ var tests = []test{ {"./bookstore/book[author='Vaidyanathan Nagarajan']/title", "XQuery Kick Start"}, {"//book[p:price='29.99']/title", "Harry Potter"}, {"//book[price='29.99']/title", "Harry Potter"}, + {"//book/price[text()='29.99']", "29.99"}, + {"//book/author[text()='Kurt Cagle']", "Kurt Cagle"}, // attribute queries {"./bookstore/book[@category='WEB']/title", []string{"XQuery Kick Start", "Learning XML"}}, |