Skip to content

Commit 3535127

Browse files
committed
Add XPath selector cache feature.
1 parent 3b69d31 commit 3535127

File tree

5 files changed

+62
-6
lines changed

5 files changed

+62
-6
lines changed

.travis.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ go:
99
install:
1010
- go get github.com/antchfx/xpath
1111
- go get github.com/mattn/goveralls
12-
12+
- go get github.com/golang/groupcache
13+
1314
script:
1415
- $HOME/gopath/bin/goveralls -service=travis-ci

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@ jsonquery
88
Overview
99
===
1010

11-
jsonquery is an XPath query package for JSON document, lets you extract data from JSON documents through an XPath expression.
11+
jsonquery is an XPath query package for JSON document, lets you extract data from JSON documents through an XPath expression. Built-in XPath expression cache avoid re-compile XPath expression each query.
1212

1313
Getting Started
1414
===
1515

1616
### Install Package
17-
18-
> $ go get github.com/antchfx/jsonquery
17+
```
18+
go get github.com/antchfx/jsonquery
19+
```
1920

2021
#### Load JSON document from URL.
2122

cache.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package jsonquery
2+
3+
import (
4+
"sync"
5+
6+
"github.com/golang/groupcache/lru"
7+
8+
"github.com/antchfx/xpath"
9+
)
10+
11+
// DisableSelectorCache will disable caching for the query selector if value is true.
12+
var DisableSelectorCache = false
13+
14+
// SelectorCacheMaxEntries allows how many selector object can be caching. Default is 50.
15+
// Will disable caching if SelectorCacheMaxEntries <= 0.
16+
var SelectorCacheMaxEntries = 50
17+
18+
var (
19+
cacheOnce sync.Once
20+
cache *lru.Cache
21+
)
22+
23+
func getQuery(expr string) (*xpath.Expr, error) {
24+
if DisableSelectorCache || SelectorCacheMaxEntries <= 0 {
25+
return xpath.Compile(expr)
26+
}
27+
cacheOnce.Do(func() {
28+
cache = lru.New(50)
29+
})
30+
if v, ok := cache.Get(expr); ok {
31+
return v.(*xpath.Expr), nil
32+
}
33+
v, err := xpath.Compile(expr)
34+
if err != nil {
35+
return nil, err
36+
}
37+
cache.Add(expr, v)
38+
return v, nil
39+
40+
}

query.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func FindOne(top *Node, expr string) *Node {
3434
// QueryAll searches the Node that matches by the specified XPath expr.
3535
// Return an error if the expression `expr` cannot be parsed.
3636
func QueryAll(top *Node, expr string) ([]*Node, error) {
37-
exp, err := xpath.Compile(expr)
37+
exp, err := getQuery(expr)
3838
if err != nil {
3939
return nil, err
4040
}
@@ -44,7 +44,7 @@ func QueryAll(top *Node, expr string) ([]*Node, error) {
4444
// Query searches the Node that matches by the specified XPath expr,
4545
// and returns first element of matched.
4646
func Query(top *Node, expr string) (*Node, error) {
47-
exp, err := xpath.Compile(expr)
47+
exp, err := getQuery(expr)
4848
if err != nil {
4949
return nil, err
5050
}

query_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,20 @@ import (
77
"github.com/antchfx/xpath"
88
)
99

10+
func BenchmarkSelectorCache(b *testing.B) {
11+
DisableSelectorCache = false
12+
for i := 0; i < b.N; i++ {
13+
getQuery("/AAA/BBB/DDD/CCC/EEE/ancestor::*")
14+
}
15+
}
16+
17+
func BenchmarkDisableSelectorCache(b *testing.B) {
18+
DisableSelectorCache = true
19+
for i := 0; i < b.N; i++ {
20+
getQuery("/AAA/BBB/DDD/CCC/EEE/ancestor::*")
21+
}
22+
}
23+
1024
func TestNavigator(t *testing.T) {
1125
s := `{
1226
"name":"John",

0 commit comments

Comments
 (0)