aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrett Vickers <brett@arena.net>2017-05-11 13:24:51 -0700
committerBrett Vickers <brett@arena.net>2017-05-11 13:28:47 -0700
commit09746331a38f3da8c023a85a65c8c152070de725 (patch)
treecc0bc9c854c851da7369322dead173982ac7ec09
parentcda1c0026246bd095961ef9a3c430e50d0e80fba (diff)
downloadgo-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.go31
-rw-r--r--path_test.go2
2 files changed, 31 insertions, 2 deletions
diff --git a/path.go b/path.go
index 126eb15..f200332 100644
--- a/path.go
+++ b/path.go
@@ -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"}},