This commit is contained in:
parent
810583964c
commit
6758df2b1d
10
go.mod
10
go.mod
@ -1,13 +1,13 @@
|
|||||||
module git.paulbsd.com/paulbsd/fuelprices
|
module git.paulbsd.com/paulbsd/fuelprices
|
||||||
|
|
||||||
go 1.21
|
go 1.23
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/antchfx/xmlquery v1.3.18
|
github.com/antchfx/xmlquery v1.4.1
|
||||||
github.com/antchfx/xpath v1.2.5 // indirect
|
github.com/antchfx/xpath v1.3.1 // indirect
|
||||||
github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c
|
github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c
|
||||||
golang.org/x/net v0.20.0 // indirect
|
golang.org/x/net v0.28.0 // indirect
|
||||||
golang.org/x/text v0.14.0 // indirect
|
golang.org/x/text v0.17.0 // indirect
|
||||||
gopkg.in/ini.v1 v1.67.0
|
gopkg.in/ini.v1 v1.67.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
8
go.sum
8
go.sum
@ -4,6 +4,8 @@ github.com/antchfx/xmlquery v1.3.15 h1:aJConNMi1sMha5G8YJoAIF5P+H+qG1L73bSItWHo8
|
|||||||
github.com/antchfx/xmlquery v1.3.15/go.mod h1:zMDv5tIGjOxY/JCNNinnle7V/EwthZ5IT8eeCGJKRWA=
|
github.com/antchfx/xmlquery v1.3.15/go.mod h1:zMDv5tIGjOxY/JCNNinnle7V/EwthZ5IT8eeCGJKRWA=
|
||||||
github.com/antchfx/xmlquery v1.3.18 h1:FSQ3wMuphnPPGJOFhvc+cRQ2CT/rUj4cyQXkJcjOwz0=
|
github.com/antchfx/xmlquery v1.3.18 h1:FSQ3wMuphnPPGJOFhvc+cRQ2CT/rUj4cyQXkJcjOwz0=
|
||||||
github.com/antchfx/xmlquery v1.3.18/go.mod h1:Afkq4JIeXut75taLSuI31ISJ/zeq+3jG7TunF7noreA=
|
github.com/antchfx/xmlquery v1.3.18/go.mod h1:Afkq4JIeXut75taLSuI31ISJ/zeq+3jG7TunF7noreA=
|
||||||
|
github.com/antchfx/xmlquery v1.4.1 h1:YgpSwbeWvLp557YFTi8E3z6t6/hYjmFEtiEKbDfEbl0=
|
||||||
|
github.com/antchfx/xmlquery v1.4.1/go.mod h1:lKezcT8ELGt8kW5L+ckFMTbgdR61/odpPgDv8Gvi1fI=
|
||||||
github.com/antchfx/xpath v1.2.1 h1:qhp4EW6aCOVr5XIkT+l6LJ9ck/JsUH/yyauNgTQkBF8=
|
github.com/antchfx/xpath v1.2.1 h1:qhp4EW6aCOVr5XIkT+l6LJ9ck/JsUH/yyauNgTQkBF8=
|
||||||
github.com/antchfx/xpath v1.2.1/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
|
github.com/antchfx/xpath v1.2.1/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
|
||||||
github.com/antchfx/xpath v1.2.3/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
|
github.com/antchfx/xpath v1.2.3/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
|
||||||
@ -11,6 +13,8 @@ github.com/antchfx/xpath v1.2.4 h1:dW1HB/JxKvGtJ9WyVGJ0sIoEcqftV3SqIstujI+B9XY=
|
|||||||
github.com/antchfx/xpath v1.2.4/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
|
github.com/antchfx/xpath v1.2.4/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
|
||||||
github.com/antchfx/xpath v1.2.5 h1:hqZ+wtQ+KIOV/S3bGZcIhpgYC26um2bZYP2KVGcR7VY=
|
github.com/antchfx/xpath v1.2.5 h1:hqZ+wtQ+KIOV/S3bGZcIhpgYC26um2bZYP2KVGcR7VY=
|
||||||
github.com/antchfx/xpath v1.2.5/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
|
github.com/antchfx/xpath v1.2.5/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
|
||||||
|
github.com/antchfx/xpath v1.3.1 h1:PNbFuUqHwWl0xRjvUPjJ95Agbmdj2uzzIwmQKgu4oCk=
|
||||||
|
github.com/antchfx/xpath v1.3.1/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@ -44,6 +48,8 @@ golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
|
|||||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||||
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
|
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
|
||||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||||
|
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
||||||
|
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@ -73,6 +79,8 @@ golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
|||||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
|
||||||
|
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
|
17
vendor/github.com/antchfx/xmlquery/.travis.yml
generated
vendored
17
vendor/github.com/antchfx/xmlquery/.travis.yml
generated
vendored
@ -1,17 +0,0 @@
|
|||||||
language: go
|
|
||||||
|
|
||||||
go:
|
|
||||||
- 1.9.x
|
|
||||||
- 1.12.x
|
|
||||||
- 1.13.x
|
|
||||||
- 1.14.x
|
|
||||||
- 1.15.x
|
|
||||||
|
|
||||||
install:
|
|
||||||
- go get golang.org/x/net/html/charset
|
|
||||||
- go get github.com/antchfx/xpath
|
|
||||||
- go get github.com/mattn/goveralls
|
|
||||||
- go get github.com/golang/groupcache
|
|
||||||
|
|
||||||
script:
|
|
||||||
- $HOME/gopath/bin/goveralls -service=travis-ci
|
|
55
vendor/github.com/antchfx/xmlquery/README.md
generated
vendored
55
vendor/github.com/antchfx/xmlquery/README.md
generated
vendored
@ -1,12 +1,10 @@
|
|||||||
xmlquery
|
# xmlquery
|
||||||
====
|
|
||||||
[![Build Status](https://travis-ci.org/antchfx/xmlquery.svg?branch=master)](https://travis-ci.org/antchfx/xmlquery)
|
[![Build Status](https://github.com/antchfx/xmlquery/actions/workflows/testing.yml/badge.svg)](https://github.com/antchfx/xmlquery/actions/workflows/testing.yml)
|
||||||
[![Coverage Status](https://coveralls.io/repos/github/antchfx/xmlquery/badge.svg?branch=master)](https://coveralls.io/github/antchfx/xmlquery?branch=master)
|
|
||||||
[![GoDoc](https://godoc.org/github.com/antchfx/xmlquery?status.svg)](https://godoc.org/github.com/antchfx/xmlquery)
|
[![GoDoc](https://godoc.org/github.com/antchfx/xmlquery?status.svg)](https://godoc.org/github.com/antchfx/xmlquery)
|
||||||
[![Go Report Card](https://goreportcard.com/badge/github.com/antchfx/xmlquery)](https://goreportcard.com/report/github.com/antchfx/xmlquery)
|
[![Go Report Card](https://goreportcard.com/badge/github.com/antchfx/xmlquery)](https://goreportcard.com/report/github.com/antchfx/xmlquery)
|
||||||
|
|
||||||
Overview
|
# Overview
|
||||||
===
|
|
||||||
|
|
||||||
`xmlquery` is an XPath query package for XML documents, allowing you to extract
|
`xmlquery` is an XPath query package for XML documents, allowing you to extract
|
||||||
data or evaluate from XML documents with an XPath expression.
|
data or evaluate from XML documents with an XPath expression.
|
||||||
@ -17,21 +15,19 @@ each query.
|
|||||||
|
|
||||||
You can visit this page to learn about the supported XPath(1.0/2.0) syntax. https://github.com/antchfx/xpath
|
You can visit this page to learn about the supported XPath(1.0/2.0) syntax. https://github.com/antchfx/xpath
|
||||||
|
|
||||||
[htmlquery](https://github.com/antchfx/htmlquery) - Package for the HTML document query.
|
[htmlquery](https://github.com/antchfx/htmlquery) - Package for the HTML document query.
|
||||||
|
|
||||||
[xmlquery](https://github.com/antchfx/xmlquery) - Package for the XML document query.
|
[xmlquery](https://github.com/antchfx/xmlquery) - Package for the XML document query.
|
||||||
|
|
||||||
[jsonquery](https://github.com/antchfx/jsonquery) - Package for the JSON document query.
|
[jsonquery](https://github.com/antchfx/jsonquery) - Package for the JSON document query.
|
||||||
|
|
||||||
|
# Installation
|
||||||
|
|
||||||
Installation
|
|
||||||
====
|
|
||||||
```
|
```
|
||||||
$ go get github.com/antchfx/xmlquery
|
$ go get github.com/antchfx/xmlquery
|
||||||
```
|
```
|
||||||
|
|
||||||
|
# Quick Starts
|
||||||
Quick Starts
|
|
||||||
===
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
@ -75,8 +71,7 @@ func main(){
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Getting Started
|
# Getting Started
|
||||||
===
|
|
||||||
|
|
||||||
### Find specified XPath query.
|
### Find specified XPath query.
|
||||||
|
|
||||||
@ -157,10 +152,17 @@ list := xmlquery.Find(doc, "//author")
|
|||||||
book := xmlquery.FindOne(doc, "//book[2]")
|
book := xmlquery.FindOne(doc, "//book[2]")
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Find all book elements and only get `id` attribute. (New Feature)
|
#### Find the last book.
|
||||||
|
|
||||||
|
```go
|
||||||
|
book := xmlquery.FindOne(doc, "//book[last()]")
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Find all book elements and only get `id` attribute.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
list := xmlquery.Find(doc,"//book/@id")
|
list := xmlquery.Find(doc,"//book/@id")
|
||||||
|
fmt.Println(list[0].InnerText) // outout @id value
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Find all books with id `bk104`.
|
#### Find all books with id `bk104`.
|
||||||
@ -183,15 +185,21 @@ price := expr.Evaluate(xmlquery.CreateXPathNavigator(doc)).(float64)
|
|||||||
fmt.Printf("total price: %f\n", price)
|
fmt.Printf("total price: %f\n", price)
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Evaluate number of all book elements.
|
#### Count the number of books.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
expr, err := xpath.Compile("count(//book)")
|
expr, err := xpath.Compile("count(//book)")
|
||||||
|
count := expr.Evaluate(xmlquery.CreateXPathNavigator(doc)).(float64)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Calculate the total price of all book prices.
|
||||||
|
|
||||||
|
```go
|
||||||
|
expr, err := xpath.Compile("sum(//book/price)")
|
||||||
price := expr.Evaluate(xmlquery.CreateXPathNavigator(doc)).(float64)
|
price := expr.Evaluate(xmlquery.CreateXPathNavigator(doc)).(float64)
|
||||||
```
|
```
|
||||||
|
|
||||||
Advanced Features
|
# Advanced Features
|
||||||
====
|
|
||||||
|
|
||||||
### Parse `UTF-16` XML file with `ParseWithOptions()`.
|
### Parse `UTF-16` XML file with `ParseWithOptions()`.
|
||||||
|
|
||||||
@ -273,8 +281,7 @@ Output:
|
|||||||
<?xml version="1.0"?><rss><channel><title>W3Schools Home Page</title></channel></rss>
|
<?xml version="1.0"?><rss><channel><title>W3Schools Home Page</title></channel></rss>
|
||||||
```
|
```
|
||||||
|
|
||||||
FAQ
|
# FAQ
|
||||||
====
|
|
||||||
|
|
||||||
#### `Find()` vs `QueryAll()`, which is better?
|
#### `Find()` vs `QueryAll()`, which is better?
|
||||||
|
|
||||||
@ -290,6 +297,6 @@ accept your query expression object.
|
|||||||
Caching a query expression object avoids recompiling the XPath query
|
Caching a query expression object avoids recompiling the XPath query
|
||||||
expression, improving query performance.
|
expression, improving query performance.
|
||||||
|
|
||||||
Questions
|
# Questions
|
||||||
===
|
|
||||||
Please let me know if you have any questions
|
Please let me know if you have any questions
|
||||||
|
121
vendor/github.com/antchfx/xmlquery/books.xml
generated
vendored
121
vendor/github.com/antchfx/xmlquery/books.xml
generated
vendored
@ -1,121 +0,0 @@
|
|||||||
<?xml version="1.0"?>
|
|
||||||
<?xml-stylesheet type="text/xsl" ?>
|
|
||||||
<bookstore specialty="novel">
|
|
||||||
<book id="bk101">
|
|
||||||
<author>Gambardella, Matthew</author>
|
|
||||||
<title>XML Developer's Guide</title>
|
|
||||||
<genre>Computer</genre>
|
|
||||||
<price>44.95</price>
|
|
||||||
<publish_date>2000-10-01</publish_date>
|
|
||||||
<description>An in-depth look at creating applications
|
|
||||||
with XML.</description>
|
|
||||||
</book>
|
|
||||||
<book id="bk102">
|
|
||||||
<author>Ralls, Kim</author>
|
|
||||||
<title>Midnight Rain</title>
|
|
||||||
<genre>Fantasy</genre>
|
|
||||||
<price>5.95</price>
|
|
||||||
<publish_date>2000-12-16</publish_date>
|
|
||||||
<description>A former architect battles corporate zombies,
|
|
||||||
an evil sorceress, and her own childhood to become queen
|
|
||||||
of the world.</description>
|
|
||||||
</book>
|
|
||||||
<book id="bk103">
|
|
||||||
<author>Corets, Eva</author>
|
|
||||||
<title>Maeve Ascendant</title>
|
|
||||||
<genre>Fantasy</genre>
|
|
||||||
<price>5.95</price>
|
|
||||||
<publish_date>2000-11-17</publish_date>
|
|
||||||
<description>After the collapse of a nanotechnology
|
|
||||||
society in England, the young survivors lay the
|
|
||||||
foundation for a new society.</description>
|
|
||||||
</book>
|
|
||||||
<book id="bk104">
|
|
||||||
<author>Corets, Eva</author>
|
|
||||||
<title>Oberon's Legacy</title>
|
|
||||||
<genre>Fantasy</genre>
|
|
||||||
<price>5.95</price>
|
|
||||||
<publish_date>2001-03-10</publish_date>
|
|
||||||
<description>In post-apocalypse England, the mysterious
|
|
||||||
agent known only as Oberon helps to create a new life
|
|
||||||
for the inhabitants of London. Sequel to Maeve
|
|
||||||
Ascendant.</description>
|
|
||||||
</book>
|
|
||||||
<book id="bk105">
|
|
||||||
<author>Corets, Eva</author>
|
|
||||||
<title>The Sundered Grail</title>
|
|
||||||
<genre>Fantasy</genre>
|
|
||||||
<price>5.95</price>
|
|
||||||
<publish_date>2001-09-10</publish_date>
|
|
||||||
<description>The two daughters of Maeve, half-sisters,
|
|
||||||
battle one another for control of England. Sequel to
|
|
||||||
Oberon's Legacy.</description>
|
|
||||||
</book>
|
|
||||||
<book id="bk106">
|
|
||||||
<author>Randall, Cynthia</author>
|
|
||||||
<title>Lover Birds</title>
|
|
||||||
<genre>Romance</genre>
|
|
||||||
<price>4.95</price>
|
|
||||||
<publish_date>2000-09-02</publish_date>
|
|
||||||
<description>When Carla meets Paul at an ornithology
|
|
||||||
conference, tempers fly as feathers get ruffled.</description>
|
|
||||||
</book>
|
|
||||||
<book id="bk107">
|
|
||||||
<author>Thurman, Paula</author>
|
|
||||||
<title>Splish Splash</title>
|
|
||||||
<genre>Romance</genre>
|
|
||||||
<price>4.95</price>
|
|
||||||
<publish_date>2000-11-02</publish_date>
|
|
||||||
<description>A deep sea diver finds true love twenty
|
|
||||||
thousand leagues beneath the sea.</description>
|
|
||||||
</book>
|
|
||||||
<book id="bk108">
|
|
||||||
<author>Knorr, Stefan</author>
|
|
||||||
<title>Creepy Crawlies</title>
|
|
||||||
<genre>Horror</genre>
|
|
||||||
<price>4.95</price>
|
|
||||||
<publish_date>2000-12-06</publish_date>
|
|
||||||
<description>An anthology of horror stories about roaches,
|
|
||||||
centipedes, scorpions and other insects.</description>
|
|
||||||
</book>
|
|
||||||
<book id="bk109">
|
|
||||||
<author>Kress, Peter</author>
|
|
||||||
<title>Paradox Lost</title>
|
|
||||||
<genre>Science Fiction</genre>
|
|
||||||
<price>6.95</price>
|
|
||||||
<publish_date>2000-11-02</publish_date>
|
|
||||||
<description>After an inadvertant trip through a Heisenberg
|
|
||||||
Uncertainty Device, James Salway discovers the problems
|
|
||||||
of being quantum.</description>
|
|
||||||
</book>
|
|
||||||
<book id="bk110">
|
|
||||||
<author>O'Brien, Tim</author>
|
|
||||||
<title>Microsoft .NET: The Programming Bible</title>
|
|
||||||
<genre>Computer</genre>
|
|
||||||
<price>36.95</price>
|
|
||||||
<publish_date>2000-12-09</publish_date>
|
|
||||||
<description>Microsoft's .NET initiative is explored in
|
|
||||||
detail in this deep programmer's reference.</description>
|
|
||||||
</book>
|
|
||||||
<book id="bk111">
|
|
||||||
<author>O'Brien, Tim</author>
|
|
||||||
<title>MSXML3: A Comprehensive Guide</title>
|
|
||||||
<genre>Computer</genre>
|
|
||||||
<price>36.95</price>
|
|
||||||
<publish_date>2000-12-01</publish_date>
|
|
||||||
<description>The Microsoft MSXML3 parser is covered in
|
|
||||||
detail, with attention to XML DOM interfaces, XSLT processing,
|
|
||||||
SAX and more.</description>
|
|
||||||
</book>
|
|
||||||
<book id="bk112">
|
|
||||||
<author>Galos, Mike</author>
|
|
||||||
<title>Visual Studio 7: A Comprehensive Guide</title>
|
|
||||||
<genre>Computer</genre>
|
|
||||||
<price>49.95</price>
|
|
||||||
<publish_date>2001-04-16</publish_date>
|
|
||||||
<description>Microsoft Visual Studio 7 is explored in depth,
|
|
||||||
looking at how Visual Basic, Visual C++, C#, and ASP+ are
|
|
||||||
integrated into a comprehensive development
|
|
||||||
environment.</description>
|
|
||||||
</book>
|
|
||||||
</bookstore>
|
|
9
vendor/github.com/antchfx/xmlquery/node.go
generated
vendored
9
vendor/github.com/antchfx/xmlquery/node.go
generated
vendored
@ -27,6 +27,8 @@ const (
|
|||||||
CommentNode
|
CommentNode
|
||||||
// AttributeNode is an attribute of element.
|
// AttributeNode is an attribute of element.
|
||||||
AttributeNode
|
AttributeNode
|
||||||
|
// NotationNode is a directive represents in document (for example, <!text...>).
|
||||||
|
NotationNode
|
||||||
)
|
)
|
||||||
|
|
||||||
type Attr struct {
|
type Attr struct {
|
||||||
@ -99,6 +101,10 @@ func newXMLName(name string) xml.Name {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *Node) Level() int {
|
||||||
|
return n.level
|
||||||
|
}
|
||||||
|
|
||||||
// InnerText returns the text between the start and end tags of the object.
|
// InnerText returns the text between the start and end tags of the object.
|
||||||
func (n *Node) InnerText() string {
|
func (n *Node) InnerText() string {
|
||||||
var output func(*strings.Builder, *Node)
|
var output func(*strings.Builder, *Node)
|
||||||
@ -153,6 +159,9 @@ func outputXML(b *strings.Builder, n *Node, preserveSpaces bool, config *outputC
|
|||||||
b.WriteString("-->")
|
b.WriteString("-->")
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
case NotationNode:
|
||||||
|
fmt.Fprintf(b, "<!%s>", n.Data)
|
||||||
|
return
|
||||||
case DeclarationNode:
|
case DeclarationNode:
|
||||||
b.WriteString("<?" + n.Data)
|
b.WriteString("<?" + n.Data)
|
||||||
default:
|
default:
|
||||||
|
105
vendor/github.com/antchfx/xmlquery/parse.go
generated
vendored
105
vendor/github.com/antchfx/xmlquery/parse.go
generated
vendored
@ -8,6 +8,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/antchfx/xpath"
|
"github.com/antchfx/xpath"
|
||||||
"golang.org/x/net/html/charset"
|
"golang.org/x/net/html/charset"
|
||||||
@ -59,6 +60,13 @@ type parser struct {
|
|||||||
streamNode *Node // Need to remember the last target node So we can clean it up upon next Read() call.
|
streamNode *Node // Need to remember the last target node So we can clean it up upon next Read() call.
|
||||||
streamNodePrev *Node // Need to remember target node's prev so upon target node removal, we can restore correct prev.
|
streamNodePrev *Node // Need to remember target node's prev so upon target node removal, we can restore correct prev.
|
||||||
reader *cachedReader // Need to maintain a reference to the reader, so we can determine whether a node contains CDATA.
|
reader *cachedReader // Need to maintain a reference to the reader, so we can determine whether a node contains CDATA.
|
||||||
|
once sync.Once
|
||||||
|
space2prefix map[string]*xmlnsPrefix
|
||||||
|
}
|
||||||
|
|
||||||
|
type xmlnsPrefix struct {
|
||||||
|
name string
|
||||||
|
level int
|
||||||
}
|
}
|
||||||
|
|
||||||
func createParser(r io.Reader) *parser {
|
func createParser(r io.Reader) *parser {
|
||||||
@ -77,9 +85,11 @@ func createParser(r io.Reader) *parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *parser) parse() (*Node, error) {
|
func (p *parser) parse() (*Node, error) {
|
||||||
var streamElementNodeCounter int
|
p.once.Do(func() {
|
||||||
space2prefix := map[string]string{"http://www.w3.org/XML/1998/namespace": "xml"}
|
p.space2prefix = map[string]*xmlnsPrefix{"http://www.w3.org/XML/1998/namespace": {name: "xml", level: 0}}
|
||||||
|
})
|
||||||
|
|
||||||
|
var streamElementNodeCounter int
|
||||||
for {
|
for {
|
||||||
p.reader.StartCaching()
|
p.reader.StartCaching()
|
||||||
tok, err := p.decoder.Token()
|
tok, err := p.decoder.Token()
|
||||||
@ -108,16 +118,18 @@ func (p *parser) parse() (*Node, error) {
|
|||||||
|
|
||||||
for _, att := range tok.Attr {
|
for _, att := range tok.Attr {
|
||||||
if att.Name.Local == "xmlns" {
|
if att.Name.Local == "xmlns" {
|
||||||
space2prefix[att.Value] = "" // reset empty if exist the default namespace
|
// https://github.com/antchfx/xmlquery/issues/67
|
||||||
// defaultNamespaceURL = att.Value
|
if prefix, ok := p.space2prefix[att.Value]; !ok || (ok && prefix.level >= p.level) {
|
||||||
|
p.space2prefix[att.Value] = &xmlnsPrefix{name: "", level: p.level} // reset empty if exist the default namespace
|
||||||
|
}
|
||||||
} else if att.Name.Space == "xmlns" {
|
} else if att.Name.Space == "xmlns" {
|
||||||
// maybe there are have duplicate NamespaceURL?
|
// maybe there are have duplicate NamespaceURL?
|
||||||
space2prefix[att.Value] = att.Name.Local
|
p.space2prefix[att.Value] = &xmlnsPrefix{name: att.Name.Local, level: p.level}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if space := tok.Name.Space; space != "" {
|
if space := tok.Name.Space; space != "" {
|
||||||
if _, found := space2prefix[space]; !found && p.decoder.Strict {
|
if _, found := p.space2prefix[space]; !found && p.decoder.Strict {
|
||||||
return nil, fmt.Errorf("xmlquery: invalid XML document, namespace %s is missing", space)
|
return nil, fmt.Errorf("xmlquery: invalid XML document, namespace %s is missing", space)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -125,8 +137,8 @@ func (p *parser) parse() (*Node, error) {
|
|||||||
attributes := make([]Attr, len(tok.Attr))
|
attributes := make([]Attr, len(tok.Attr))
|
||||||
for i, att := range tok.Attr {
|
for i, att := range tok.Attr {
|
||||||
name := att.Name
|
name := att.Name
|
||||||
if prefix, ok := space2prefix[name.Space]; ok {
|
if prefix, ok := p.space2prefix[name.Space]; ok {
|
||||||
name.Space = prefix
|
name.Space = prefix.name
|
||||||
}
|
}
|
||||||
attributes[i] = Attr{
|
attributes[i] = Attr{
|
||||||
Name: name,
|
Name: name,
|
||||||
@ -155,10 +167,10 @@ func (p *parser) parse() (*Node, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if node.NamespaceURI != "" {
|
if node.NamespaceURI != "" {
|
||||||
if v, ok := space2prefix[node.NamespaceURI]; ok {
|
if v, ok := p.space2prefix[node.NamespaceURI]; ok {
|
||||||
cached := string(p.reader.Cache())
|
cached := string(p.reader.Cache())
|
||||||
if strings.HasPrefix(cached, fmt.Sprintf("%s:%s", v, node.Data)) || strings.HasPrefix(cached, fmt.Sprintf("<%s:%s", v, node.Data)) {
|
if strings.HasPrefix(cached, fmt.Sprintf("%s:%s", v.name, node.Data)) || strings.HasPrefix(cached, fmt.Sprintf("<%s:%s", v.name, node.Data)) {
|
||||||
node.Prefix = v
|
node.Prefix = v.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -269,6 +281,17 @@ func (p *parser) parse() (*Node, error) {
|
|||||||
}
|
}
|
||||||
p.prev = node
|
p.prev = node
|
||||||
case xml.Directive:
|
case xml.Directive:
|
||||||
|
node := &Node{Type: NotationNode, Data: string(tok), level: p.level}
|
||||||
|
if p.level == p.prev.level {
|
||||||
|
AddSibling(p.prev, node)
|
||||||
|
} else if p.level > p.prev.level {
|
||||||
|
AddChild(p.prev, node)
|
||||||
|
} else if p.level < p.prev.level {
|
||||||
|
for i := p.prev.level - p.level; i > 1; i-- {
|
||||||
|
p.prev = p.prev.Parent
|
||||||
|
}
|
||||||
|
AddSibling(p.prev.Parent, node)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -285,37 +308,43 @@ type StreamParser struct {
|
|||||||
// scenarios.
|
// scenarios.
|
||||||
//
|
//
|
||||||
// Scenario 1: simple case:
|
// Scenario 1: simple case:
|
||||||
// xml := `<AAA><BBB>b1</BBB><BBB>b2</BBB></AAA>`
|
//
|
||||||
// sp, err := CreateStreamParser(strings.NewReader(xml), "/AAA/BBB")
|
// xml := `<AAA><BBB>b1</BBB><BBB>b2</BBB></AAA>`
|
||||||
// if err != nil {
|
// sp, err := CreateStreamParser(strings.NewReader(xml), "/AAA/BBB")
|
||||||
// panic(err)
|
// if err != nil {
|
||||||
// }
|
// panic(err)
|
||||||
// for {
|
// }
|
||||||
// n, err := sp.Read()
|
// for {
|
||||||
// if err != nil {
|
// n, err := sp.Read()
|
||||||
// break
|
// if err != nil {
|
||||||
// }
|
// break
|
||||||
// fmt.Println(n.OutputXML(true))
|
// }
|
||||||
// }
|
// fmt.Println(n.OutputXML(true))
|
||||||
|
// }
|
||||||
|
//
|
||||||
// Output will be:
|
// Output will be:
|
||||||
// <BBB>b1</BBB>
|
//
|
||||||
// <BBB>b2</BBB>
|
// <BBB>b1</BBB>
|
||||||
|
// <BBB>b2</BBB>
|
||||||
//
|
//
|
||||||
// Scenario 2: advanced case:
|
// Scenario 2: advanced case:
|
||||||
// xml := `<AAA><BBB>b1</BBB><BBB>b2</BBB></AAA>`
|
//
|
||||||
// sp, err := CreateStreamParser(strings.NewReader(xml), "/AAA/BBB", "/AAA/BBB[. != 'b1']")
|
// xml := `<AAA><BBB>b1</BBB><BBB>b2</BBB></AAA>`
|
||||||
// if err != nil {
|
// sp, err := CreateStreamParser(strings.NewReader(xml), "/AAA/BBB", "/AAA/BBB[. != 'b1']")
|
||||||
// panic(err)
|
// if err != nil {
|
||||||
// }
|
// panic(err)
|
||||||
// for {
|
// }
|
||||||
// n, err := sp.Read()
|
// for {
|
||||||
// if err != nil {
|
// n, err := sp.Read()
|
||||||
// break
|
// if err != nil {
|
||||||
// }
|
// break
|
||||||
// fmt.Println(n.OutputXML(true))
|
// }
|
||||||
// }
|
// fmt.Println(n.OutputXML(true))
|
||||||
|
// }
|
||||||
|
//
|
||||||
// Output will be:
|
// Output will be:
|
||||||
// <BBB>b2</BBB>
|
//
|
||||||
|
// <BBB>b2</BBB>
|
||||||
//
|
//
|
||||||
// As the argument names indicate, streamElementXPath should be used for
|
// As the argument names indicate, streamElementXPath should be used for
|
||||||
// providing xpath query pointing to the target element node only, no extra
|
// providing xpath query pointing to the target element node only, no extra
|
||||||
|
2
vendor/github.com/antchfx/xmlquery/query.go
generated
vendored
2
vendor/github.com/antchfx/xmlquery/query.go
generated
vendored
@ -156,7 +156,7 @@ func (x *NodeNavigator) NodeType() xpath.NodeType {
|
|||||||
switch x.curr.Type {
|
switch x.curr.Type {
|
||||||
case CommentNode:
|
case CommentNode:
|
||||||
return xpath.CommentNode
|
return xpath.CommentNode
|
||||||
case TextNode, CharDataNode:
|
case TextNode, CharDataNode, NotationNode:
|
||||||
return xpath.TextNode
|
return xpath.TextNode
|
||||||
case DeclarationNode, DocumentNode:
|
case DeclarationNode, DocumentNode:
|
||||||
return xpath.RootNode
|
return xpath.RootNode
|
||||||
|
12
vendor/github.com/antchfx/xpath/.travis.yml
generated
vendored
12
vendor/github.com/antchfx/xpath/.travis.yml
generated
vendored
@ -1,12 +0,0 @@
|
|||||||
language: go
|
|
||||||
|
|
||||||
go:
|
|
||||||
- 1.6
|
|
||||||
- 1.9
|
|
||||||
- '1.10'
|
|
||||||
|
|
||||||
install:
|
|
||||||
- go get github.com/mattn/goveralls
|
|
||||||
|
|
||||||
script:
|
|
||||||
- $HOME/gopath/bin/goveralls -service=travis-ci
|
|
132
vendor/github.com/antchfx/xpath/README.md
generated
vendored
132
vendor/github.com/antchfx/xpath/README.md
generated
vendored
@ -1,14 +1,13 @@
|
|||||||
XPath
|
# XPath
|
||||||
====
|
|
||||||
[![GoDoc](https://godoc.org/github.com/antchfx/xpath?status.svg)](https://godoc.org/github.com/antchfx/xpath)
|
[![GoDoc](https://godoc.org/github.com/antchfx/xpath?status.svg)](https://godoc.org/github.com/antchfx/xpath)
|
||||||
[![Coverage Status](https://coveralls.io/repos/github/antchfx/xpath/badge.svg?branch=master)](https://coveralls.io/github/antchfx/xpath?branch=master)
|
[![Coverage Status](https://coveralls.io/repos/github/antchfx/xpath/badge.svg?branch=master)](https://coveralls.io/github/antchfx/xpath?branch=master)
|
||||||
[![Build Status](https://travis-ci.org/antchfx/xpath.svg?branch=master)](https://travis-ci.org/antchfx/xpath)
|
[![Build Status](https://github.com/antchfx/xpath/actions/workflows/testing.yml/badge.svg)](https://github.com/antchfx/xpath/actions/workflows/testing.yml)
|
||||||
[![Go Report Card](https://goreportcard.com/badge/github.com/antchfx/xpath)](https://goreportcard.com/report/github.com/antchfx/xpath)
|
[![Go Report Card](https://goreportcard.com/badge/github.com/antchfx/xpath)](https://goreportcard.com/report/github.com/antchfx/xpath)
|
||||||
|
|
||||||
XPath is Go package provides selecting nodes from XML, HTML or other documents using XPath expression.
|
XPath is Go package provides selecting nodes from XML, HTML or other documents using XPath expression.
|
||||||
|
|
||||||
Implementation
|
# Implementation
|
||||||
===
|
|
||||||
|
|
||||||
- [htmlquery](https://github.com/antchfx/htmlquery) - an XPath query package for HTML document
|
- [htmlquery](https://github.com/antchfx/htmlquery) - an XPath query package for HTML document
|
||||||
|
|
||||||
@ -16,8 +15,7 @@ Implementation
|
|||||||
|
|
||||||
- [jsonquery](https://github.com/antchfx/jsonquery) - an XPath query package for JSON document
|
- [jsonquery](https://github.com/antchfx/jsonquery) - an XPath query package for JSON document
|
||||||
|
|
||||||
Supported Features
|
# Supported Features
|
||||||
===
|
|
||||||
|
|
||||||
#### The basic XPath patterns.
|
#### The basic XPath patterns.
|
||||||
|
|
||||||
@ -63,11 +61,14 @@ Supported Features
|
|||||||
|
|
||||||
- `child::*` : The child axis selects children of the current node.
|
- `child::*` : The child axis selects children of the current node.
|
||||||
|
|
||||||
|
- `child::node()`: Selects all the children of the context node.
|
||||||
|
- `child::text()`: Selects all text node children of the context node.
|
||||||
|
|
||||||
- `descendant::*` : The descendant axis selects descendants of the current node. It is equivalent to '//'.
|
- `descendant::*` : The descendant axis selects descendants of the current node. It is equivalent to '//'.
|
||||||
|
|
||||||
- `descendant-or-self::*` : Selects descendants including the current node.
|
- `descendant-or-self::*` : Selects descendants including the current node.
|
||||||
|
|
||||||
- `attribute::*` : Selects attributes of the current element. It is equivalent to @*
|
- `attribute::*` : Selects attributes of the current element. It is equivalent to @\*
|
||||||
|
|
||||||
- `following-sibling::*` : Selects nodes after the current node.
|
- `following-sibling::*` : Selects nodes after the current node.
|
||||||
|
|
||||||
@ -87,27 +88,27 @@ Supported Features
|
|||||||
|
|
||||||
#### Expressions
|
#### Expressions
|
||||||
|
|
||||||
The gxpath supported three types: number, boolean, string.
|
The gxpath supported three types: number, boolean, string.
|
||||||
|
|
||||||
- `path` : Selects nodes based on the path.
|
- `path` : Selects nodes based on the path.
|
||||||
|
|
||||||
- `a = b` : Standard comparisons.
|
- `a = b` : Standard comparisons.
|
||||||
|
|
||||||
* a = b True if a equals b.
|
- `a = b` : True if a equals b.
|
||||||
* a != b True if a is not equal to b.
|
- `a != b` : True if a is not equal to b.
|
||||||
* a < b True if a is less than b.
|
- `a < b` : True if a is less than b.
|
||||||
* a <= b True if a is less than or equal to b.
|
- `a <= b` : True if a is less than or equal to b.
|
||||||
* a > b True if a is greater than b.
|
- `a > b` : True if a is greater than b.
|
||||||
* a >= b True if a is greater than or equal to b.
|
- `a >= b` : True if a is greater than or equal to b.
|
||||||
|
|
||||||
- `a + b` : Arithmetic expressions.
|
- `a + b` : Arithmetic expressions.
|
||||||
|
|
||||||
* `- a` Unary minus
|
- `- a` Unary minus
|
||||||
* a + b Add
|
- `a + b` : Addition
|
||||||
* a - b Substract
|
- `a - b` : Subtraction
|
||||||
* a * b Multiply
|
- `a * b` : Multiplication
|
||||||
* a div b Divide
|
- `a div b` : Division
|
||||||
* a mod b Floating point mod, like Java.
|
- `a mod b` : Modulus (division remainder)
|
||||||
|
|
||||||
- `a or b` : Boolean `or` operation.
|
- `a or b` : Boolean `or` operation.
|
||||||
|
|
||||||
@ -117,49 +118,50 @@ Supported Features
|
|||||||
|
|
||||||
- `fun(arg1, ..., argn)` : Function calls:
|
- `fun(arg1, ..., argn)` : Function calls:
|
||||||
|
|
||||||
| Function | Supported |
|
| Function | Supported |
|
||||||
| --- | --- |
|
| ----------------------- | --------- |
|
||||||
`boolean()`| ✓ |
|
| `boolean()` | ✓ |
|
||||||
`ceiling()`| ✓ |
|
| `ceiling()` | ✓ |
|
||||||
`choose()`| ✗ |
|
| `choose()` | ✗ |
|
||||||
`concat()`| ✓ |
|
| `concat()` | ✓ |
|
||||||
`contains()`| ✓ |
|
| `contains()` | ✓ |
|
||||||
`count()`| ✓ |
|
| `count()` | ✓ |
|
||||||
`current()`| ✗ |
|
| `current()` | ✗ |
|
||||||
`document()`| ✗ |
|
| `document()` | ✗ |
|
||||||
`element-available()`| ✗ |
|
| `element-available()` | ✗ |
|
||||||
`ends-with()`| ✓ |
|
| `ends-with()` | ✓ |
|
||||||
`false()`| ✓ |
|
| `false()` | ✓ |
|
||||||
`floor()`| ✓ |
|
| `floor()` | ✓ |
|
||||||
`format-number()`| ✗ |
|
| `format-number()` | ✗ |
|
||||||
`function-available()`| ✗ |
|
| `function-available()` | ✗ |
|
||||||
`generate-id()`| ✗ |
|
| `generate-id()` | ✗ |
|
||||||
`id()`| ✗ |
|
| `id()` | ✗ |
|
||||||
`key()`| ✗ |
|
| `key()` | ✗ |
|
||||||
`lang()`| ✗ |
|
| `lang()` | ✗ |
|
||||||
`last()`| ✓ |
|
| `last()` | ✓ |
|
||||||
`local-name()`| ✓ |
|
| `local-name()` | ✓ |
|
||||||
`matches()`| ✓ |
|
| `lower-case()`[^1] | ✓ |
|
||||||
`name()`| ✓ |
|
| `matches()` | ✓ |
|
||||||
`namespace-uri()`| ✓ |
|
| `name()` | ✓ |
|
||||||
`normalize-space()`| ✓ |
|
| `namespace-uri()` | ✓ |
|
||||||
`not()`| ✓ |
|
| `normalize-space()` | ✓ |
|
||||||
`number()`| ✓ |
|
| `not()` | ✓ |
|
||||||
`position()`| ✓ |
|
| `number()` | ✓ |
|
||||||
`replace()`| ✓ |
|
| `position()` | ✓ |
|
||||||
`reverse()`| ✓ |
|
| `replace()` | ✓ |
|
||||||
`round()`| ✓ |
|
| `reverse()` | ✓ |
|
||||||
`starts-with()`| ✓ |
|
| `round()` | ✓ |
|
||||||
`string()`| ✓ |
|
| `starts-with()` | ✓ |
|
||||||
`string-join()`[^1]| ✓ |
|
| `string()` | ✓ |
|
||||||
`string-length()`| ✓ |
|
| `string-join()`[^1] | ✓ |
|
||||||
`substring()`| ✓ |
|
| `string-length()` | ✓ |
|
||||||
`substring-after()`| ✓ |
|
| `substring()` | ✓ |
|
||||||
`substring-before()`| ✓ |
|
| `substring-after()` | ✓ |
|
||||||
`sum()`| ✓ |
|
| `substring-before()` | ✓ |
|
||||||
`system-property()`| ✗ |
|
| `sum()` | ✓ |
|
||||||
`translate()`| ✓ |
|
| `system-property()` | ✗ |
|
||||||
`true()`| ✓ |
|
| `translate()` | ✓ |
|
||||||
`unparsed-entity-url()` | ✗ |
|
| `true()` | ✓ |
|
||||||
|
| `unparsed-entity-url()` | ✗ |
|
||||||
|
|
||||||
[^1]: XPath-2.0 expression
|
[^1]: XPath-2.0 expression
|
397
vendor/github.com/antchfx/xpath/build.go
generated
vendored
397
vendor/github.com/antchfx/xpath/build.go
generated
vendored
@ -7,15 +7,39 @@ import (
|
|||||||
|
|
||||||
type flag int
|
type flag int
|
||||||
|
|
||||||
const (
|
var flagsEnum = struct {
|
||||||
noneFlag flag = iota
|
None flag
|
||||||
filterFlag
|
SmartDesc flag
|
||||||
)
|
PosFilter flag
|
||||||
|
Filter flag
|
||||||
|
Condition flag
|
||||||
|
}{
|
||||||
|
None: 0,
|
||||||
|
SmartDesc: 1,
|
||||||
|
PosFilter: 2,
|
||||||
|
Filter: 4,
|
||||||
|
Condition: 8,
|
||||||
|
}
|
||||||
|
|
||||||
|
type builderProp int
|
||||||
|
|
||||||
|
var builderProps = struct {
|
||||||
|
None builderProp
|
||||||
|
PosFilter builderProp
|
||||||
|
HasPosition builderProp
|
||||||
|
HasLast builderProp
|
||||||
|
NonFlat builderProp
|
||||||
|
}{
|
||||||
|
None: 0,
|
||||||
|
PosFilter: 1,
|
||||||
|
HasPosition: 2,
|
||||||
|
HasLast: 4,
|
||||||
|
NonFlat: 8,
|
||||||
|
}
|
||||||
|
|
||||||
// builder provides building an XPath expressions.
|
// builder provides building an XPath expressions.
|
||||||
type builder struct {
|
type builder struct {
|
||||||
depth int
|
parseDepth int
|
||||||
flag flag
|
|
||||||
firstInput query
|
firstInput query
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,23 +87,26 @@ func axisPredicate(root *axisNode) func(NodeNavigator) bool {
|
|||||||
return predicate
|
return predicate
|
||||||
}
|
}
|
||||||
|
|
||||||
// processAxisNode processes a query for the XPath axis node.
|
// processAxis processes a query for the XPath axis node.
|
||||||
func (b *builder) processAxisNode(root *axisNode) (query, error) {
|
func (b *builder) processAxis(root *axisNode, flags flag, props *builderProp) (query, error) {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
qyInput query
|
qyInput query
|
||||||
qyOutput query
|
qyOutput query
|
||||||
predicate = axisPredicate(root)
|
|
||||||
)
|
)
|
||||||
|
b.firstInput = nil
|
||||||
|
predicate := axisPredicate(root)
|
||||||
|
|
||||||
if root.Input == nil {
|
if root.Input == nil {
|
||||||
qyInput = &contextQuery{}
|
qyInput = &contextQuery{}
|
||||||
|
*props = builderProps.None
|
||||||
} else {
|
} else {
|
||||||
|
inputFlags := flagsEnum.None
|
||||||
if root.AxeType == "child" && (root.Input.Type() == nodeAxis) {
|
if root.AxeType == "child" && (root.Input.Type() == nodeAxis) {
|
||||||
if input := root.Input.(*axisNode); input.AxeType == "descendant-or-self" {
|
if input := root.Input.(*axisNode); input.AxeType == "descendant-or-self" {
|
||||||
var qyGrandInput query
|
var qyGrandInput query
|
||||||
if input.Input != nil {
|
if input.Input != nil {
|
||||||
qyGrandInput, _ = b.processNode(input.Input)
|
qyGrandInput, _ = b.processNode(input.Input, flagsEnum.SmartDesc, props)
|
||||||
} else {
|
} else {
|
||||||
qyGrandInput = &contextQuery{}
|
qyGrandInput = &contextQuery{}
|
||||||
}
|
}
|
||||||
@ -94,14 +121,14 @@ func (b *builder) processAxisNode(root *axisNode) (query, error) {
|
|||||||
}
|
}
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
// fix `//*[contains(@id,"food")]//*[contains(@id,"food")]`, see https://github.com/antchfx/htmlquery/issues/52
|
qyOutput = &descendantQuery{name: root.LocalName, Input: qyGrandInput, Predicate: filter, Self: false}
|
||||||
// Skip the current node(Self:false) for the next descendants nodes.
|
*props |= builderProps.NonFlat
|
||||||
_, ok := qyGrandInput.(*contextQuery)
|
|
||||||
qyOutput = &descendantQuery{Input: qyGrandInput, Predicate: filter, Self: ok}
|
|
||||||
return qyOutput, nil
|
return qyOutput, nil
|
||||||
}
|
}
|
||||||
|
} else if ((flags & flagsEnum.Filter) == 0) && (root.AxeType == "descendant" || root.AxeType == "descendant-or-self") {
|
||||||
|
inputFlags |= flagsEnum.SmartDesc
|
||||||
}
|
}
|
||||||
qyInput, err = b.processNode(root.Input)
|
qyInput, err = b.processNode(root.Input, inputFlags, props)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -109,11 +136,13 @@ func (b *builder) processAxisNode(root *axisNode) (query, error) {
|
|||||||
|
|
||||||
switch root.AxeType {
|
switch root.AxeType {
|
||||||
case "ancestor":
|
case "ancestor":
|
||||||
qyOutput = &ancestorQuery{Input: qyInput, Predicate: predicate}
|
qyOutput = &ancestorQuery{name: root.LocalName, Input: qyInput, Predicate: predicate}
|
||||||
|
*props |= builderProps.NonFlat
|
||||||
case "ancestor-or-self":
|
case "ancestor-or-self":
|
||||||
qyOutput = &ancestorQuery{Input: qyInput, Predicate: predicate, Self: true}
|
qyOutput = &ancestorQuery{name: root.LocalName, Input: qyInput, Predicate: predicate, Self: true}
|
||||||
|
*props |= builderProps.NonFlat
|
||||||
case "attribute":
|
case "attribute":
|
||||||
qyOutput = &attributeQuery{Input: qyInput, Predicate: predicate}
|
qyOutput = &attributeQuery{name: root.LocalName, Input: qyInput, Predicate: predicate}
|
||||||
case "child":
|
case "child":
|
||||||
filter := func(n NodeNavigator) bool {
|
filter := func(n NodeNavigator) bool {
|
||||||
v := predicate(n)
|
v := predicate(n)
|
||||||
@ -127,19 +156,35 @@ func (b *builder) processAxisNode(root *axisNode) (query, error) {
|
|||||||
}
|
}
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
qyOutput = &childQuery{Input: qyInput, Predicate: filter}
|
if (*props & builderProps.NonFlat) == 0 {
|
||||||
|
qyOutput = &childQuery{name: root.LocalName, Input: qyInput, Predicate: filter}
|
||||||
|
} else {
|
||||||
|
qyOutput = &cachedChildQuery{name: root.LocalName, Input: qyInput, Predicate: filter}
|
||||||
|
}
|
||||||
case "descendant":
|
case "descendant":
|
||||||
qyOutput = &descendantQuery{Input: qyInput, Predicate: predicate}
|
if (flags & flagsEnum.SmartDesc) != flagsEnum.None {
|
||||||
|
qyOutput = &descendantOverDescendantQuery{name: root.LocalName, Input: qyInput, MatchSelf: false, Predicate: predicate}
|
||||||
|
} else {
|
||||||
|
qyOutput = &descendantQuery{name: root.LocalName, Input: qyInput, Predicate: predicate}
|
||||||
|
}
|
||||||
|
*props |= builderProps.NonFlat
|
||||||
case "descendant-or-self":
|
case "descendant-or-self":
|
||||||
qyOutput = &descendantQuery{Input: qyInput, Predicate: predicate, Self: true}
|
if (flags & flagsEnum.SmartDesc) != flagsEnum.None {
|
||||||
|
qyOutput = &descendantOverDescendantQuery{name: root.LocalName, Input: qyInput, MatchSelf: true, Predicate: predicate}
|
||||||
|
} else {
|
||||||
|
qyOutput = &descendantQuery{name: root.LocalName, Input: qyInput, Predicate: predicate, Self: true}
|
||||||
|
}
|
||||||
|
*props |= builderProps.NonFlat
|
||||||
case "following":
|
case "following":
|
||||||
qyOutput = &followingQuery{Input: qyInput, Predicate: predicate}
|
qyOutput = &followingQuery{Input: qyInput, Predicate: predicate}
|
||||||
|
*props |= builderProps.NonFlat
|
||||||
case "following-sibling":
|
case "following-sibling":
|
||||||
qyOutput = &followingQuery{Input: qyInput, Predicate: predicate, Sibling: true}
|
qyOutput = &followingQuery{Input: qyInput, Predicate: predicate, Sibling: true}
|
||||||
case "parent":
|
case "parent":
|
||||||
qyOutput = &parentQuery{Input: qyInput, Predicate: predicate}
|
qyOutput = &parentQuery{Input: qyInput, Predicate: predicate}
|
||||||
case "preceding":
|
case "preceding":
|
||||||
qyOutput = &precedingQuery{Input: qyInput, Predicate: predicate}
|
qyOutput = &precedingQuery{Input: qyInput, Predicate: predicate}
|
||||||
|
*props |= builderProps.NonFlat
|
||||||
case "preceding-sibling":
|
case "preceding-sibling":
|
||||||
qyOutput = &precedingQuery{Input: qyInput, Predicate: predicate, Sibling: true}
|
qyOutput = &precedingQuery{Input: qyInput, Predicate: predicate, Sibling: true}
|
||||||
case "self":
|
case "self":
|
||||||
@ -153,56 +198,182 @@ func (b *builder) processAxisNode(root *axisNode) (query, error) {
|
|||||||
return qyOutput, nil
|
return qyOutput, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// processFilterNode builds query for the XPath filter predicate.
|
func canBeNumber(q query) bool {
|
||||||
func (b *builder) processFilterNode(root *filterNode) (query, error) {
|
if q.ValueType() != xpathResultType.Any {
|
||||||
b.flag |= filterFlag
|
return q.ValueType() == xpathResultType.Number
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
qyInput, err := b.processNode(root.Input)
|
// processFilterNode builds query for the XPath filter predicate.
|
||||||
|
func (b *builder) processFilter(root *filterNode, flags flag, props *builderProp) (query, error) {
|
||||||
|
first := (flags & flagsEnum.Filter) == 0
|
||||||
|
|
||||||
|
qyInput, err := b.processNode(root.Input, (flags | flagsEnum.Filter), props)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
qyCond, err := b.processNode(root.Condition)
|
firstInput := b.firstInput
|
||||||
|
|
||||||
|
var propsCond builderProp
|
||||||
|
cond, err := b.processNode(root.Condition, flags, &propsCond)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
qyOutput := &filterQuery{Input: qyInput, Predicate: qyCond}
|
|
||||||
return qyOutput, nil
|
// Checking whether is number
|
||||||
|
if canBeNumber(cond) || ((propsCond & (builderProps.HasPosition | builderProps.HasLast)) != 0) {
|
||||||
|
propsCond |= builderProps.HasPosition
|
||||||
|
flags |= flagsEnum.PosFilter
|
||||||
|
}
|
||||||
|
|
||||||
|
if root.Input.Type() != nodeFilter {
|
||||||
|
*props &= ^builderProps.PosFilter
|
||||||
|
}
|
||||||
|
|
||||||
|
if (propsCond & builderProps.HasPosition) != 0 {
|
||||||
|
*props |= builderProps.PosFilter
|
||||||
|
}
|
||||||
|
|
||||||
|
merge := (qyInput.Properties() & queryProps.Merge) != 0
|
||||||
|
if (propsCond & builderProps.HasPosition) != builderProps.None {
|
||||||
|
if (propsCond & builderProps.HasLast) != 0 {
|
||||||
|
// https://github.com/antchfx/xpath/issues/76
|
||||||
|
// https://github.com/antchfx/xpath/issues/78
|
||||||
|
if qyFunc, ok := cond.(*functionQuery); ok {
|
||||||
|
switch qyFunc.Input.(type) {
|
||||||
|
case *filterQuery:
|
||||||
|
cond = &lastQuery{Input: qyFunc.Input}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if first && firstInput != nil {
|
||||||
|
if merge && ((*props & builderProps.PosFilter) != 0) {
|
||||||
|
qyInput = &filterQuery{Input: qyInput, Predicate: cond, NoPosition: false}
|
||||||
|
|
||||||
|
var (
|
||||||
|
rootQuery = &contextQuery{}
|
||||||
|
parent query
|
||||||
|
)
|
||||||
|
switch axisQuery := firstInput.(type) {
|
||||||
|
case *ancestorQuery:
|
||||||
|
if _, ok := axisQuery.Input.(*contextQuery); !ok {
|
||||||
|
parent = axisQuery.Input
|
||||||
|
axisQuery.Input = rootQuery
|
||||||
|
}
|
||||||
|
case *attributeQuery:
|
||||||
|
if _, ok := axisQuery.Input.(*contextQuery); !ok {
|
||||||
|
parent = axisQuery.Input
|
||||||
|
axisQuery.Input = rootQuery
|
||||||
|
}
|
||||||
|
case *childQuery:
|
||||||
|
if _, ok := axisQuery.Input.(*contextQuery); !ok {
|
||||||
|
parent = axisQuery.Input
|
||||||
|
axisQuery.Input = rootQuery
|
||||||
|
}
|
||||||
|
case *cachedChildQuery:
|
||||||
|
if _, ok := axisQuery.Input.(*contextQuery); !ok {
|
||||||
|
parent = axisQuery.Input
|
||||||
|
axisQuery.Input = rootQuery
|
||||||
|
}
|
||||||
|
case *descendantQuery:
|
||||||
|
if _, ok := axisQuery.Input.(*contextQuery); !ok {
|
||||||
|
parent = axisQuery.Input
|
||||||
|
axisQuery.Input = rootQuery
|
||||||
|
}
|
||||||
|
case *followingQuery:
|
||||||
|
if _, ok := axisQuery.Input.(*contextQuery); !ok {
|
||||||
|
parent = axisQuery.Input
|
||||||
|
axisQuery.Input = rootQuery
|
||||||
|
}
|
||||||
|
case *precedingQuery:
|
||||||
|
if _, ok := axisQuery.Input.(*contextQuery); !ok {
|
||||||
|
parent = axisQuery.Input
|
||||||
|
axisQuery.Input = rootQuery
|
||||||
|
}
|
||||||
|
case *parentQuery:
|
||||||
|
if _, ok := axisQuery.Input.(*contextQuery); !ok {
|
||||||
|
parent = axisQuery.Input
|
||||||
|
axisQuery.Input = rootQuery
|
||||||
|
}
|
||||||
|
case *selfQuery:
|
||||||
|
if _, ok := axisQuery.Input.(*contextQuery); !ok {
|
||||||
|
parent = axisQuery.Input
|
||||||
|
axisQuery.Input = rootQuery
|
||||||
|
}
|
||||||
|
case *groupQuery:
|
||||||
|
if _, ok := axisQuery.Input.(*contextQuery); !ok {
|
||||||
|
parent = axisQuery.Input
|
||||||
|
axisQuery.Input = rootQuery
|
||||||
|
}
|
||||||
|
case *descendantOverDescendantQuery:
|
||||||
|
if _, ok := axisQuery.Input.(*contextQuery); !ok {
|
||||||
|
parent = axisQuery.Input
|
||||||
|
axisQuery.Input = rootQuery
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.firstInput = nil
|
||||||
|
if parent != nil {
|
||||||
|
return &mergeQuery{Input: parent, Child: qyInput}, nil
|
||||||
|
}
|
||||||
|
return qyInput, nil
|
||||||
|
}
|
||||||
|
b.firstInput = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
resultQuery := &filterQuery{
|
||||||
|
Input: qyInput,
|
||||||
|
Predicate: cond,
|
||||||
|
NoPosition: (propsCond & builderProps.HasPosition) == 0,
|
||||||
|
}
|
||||||
|
return resultQuery, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// processFunctionNode processes query for the XPath function node.
|
// processFunctionNode processes query for the XPath function node.
|
||||||
func (b *builder) processFunctionNode(root *functionNode) (query, error) {
|
func (b *builder) processFunction(root *functionNode, props *builderProp) (query, error) {
|
||||||
|
// Reset builder props
|
||||||
|
*props = builderProps.None
|
||||||
|
|
||||||
var qyOutput query
|
var qyOutput query
|
||||||
switch root.FuncName {
|
switch root.FuncName {
|
||||||
|
case "lower-case":
|
||||||
|
arg, err := b.processNode(root.Args[0], flagsEnum.None, props)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
qyOutput = &functionQuery{Input: arg, Func: lowerCaseFunc}
|
||||||
case "starts-with":
|
case "starts-with":
|
||||||
arg1, err := b.processNode(root.Args[0])
|
arg1, err := b.processNode(root.Args[0], flagsEnum.None, props)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
arg2, err := b.processNode(root.Args[1])
|
arg2, err := b.processNode(root.Args[1], flagsEnum.None, props)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
qyOutput = &functionQuery{Input: b.firstInput, Func: startwithFunc(arg1, arg2)}
|
qyOutput = &functionQuery{Func: startwithFunc(arg1, arg2)}
|
||||||
case "ends-with":
|
case "ends-with":
|
||||||
arg1, err := b.processNode(root.Args[0])
|
arg1, err := b.processNode(root.Args[0], flagsEnum.None, props)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
arg2, err := b.processNode(root.Args[1])
|
arg2, err := b.processNode(root.Args[1], flagsEnum.None, props)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
qyOutput = &functionQuery{Input: b.firstInput, Func: endwithFunc(arg1, arg2)}
|
qyOutput = &functionQuery{Func: endwithFunc(arg1, arg2)}
|
||||||
case "contains":
|
case "contains":
|
||||||
arg1, err := b.processNode(root.Args[0])
|
arg1, err := b.processNode(root.Args[0], flagsEnum.None, props)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
arg2, err := b.processNode(root.Args[1])
|
arg2, err := b.processNode(root.Args[1], flagsEnum.None, props)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
qyOutput = &functionQuery{Input: b.firstInput, Func: containsFunc(arg1, arg2)}
|
qyOutput = &functionQuery{Func: containsFunc(arg1, arg2)}
|
||||||
case "matches":
|
case "matches":
|
||||||
//matches(string , pattern)
|
//matches(string , pattern)
|
||||||
if len(root.Args) != 2 {
|
if len(root.Args) != 2 {
|
||||||
@ -212,10 +383,10 @@ func (b *builder) processFunctionNode(root *functionNode) (query, error) {
|
|||||||
arg1, arg2 query
|
arg1, arg2 query
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
if arg1, err = b.processNode(root.Args[0]); err != nil {
|
if arg1, err = b.processNode(root.Args[0], flagsEnum.None, props); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if arg2, err = b.processNode(root.Args[1]); err != nil {
|
if arg2, err = b.processNode(root.Args[1], flagsEnum.None, props); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Issue #92, testing the regular expression before.
|
// Issue #92, testing the regular expression before.
|
||||||
@ -224,7 +395,7 @@ func (b *builder) processFunctionNode(root *functionNode) (query, error) {
|
|||||||
return nil, fmt.Errorf("matches() got error. %v", err)
|
return nil, fmt.Errorf("matches() got error. %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
qyOutput = &functionQuery{Input: b.firstInput, Func: matchesFunc(arg1, arg2)}
|
qyOutput = &functionQuery{Func: matchesFunc(arg1, arg2)}
|
||||||
case "substring":
|
case "substring":
|
||||||
//substring( string , start [, length] )
|
//substring( string , start [, length] )
|
||||||
if len(root.Args) < 2 {
|
if len(root.Args) < 2 {
|
||||||
@ -234,18 +405,18 @@ func (b *builder) processFunctionNode(root *functionNode) (query, error) {
|
|||||||
arg1, arg2, arg3 query
|
arg1, arg2, arg3 query
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
if arg1, err = b.processNode(root.Args[0]); err != nil {
|
if arg1, err = b.processNode(root.Args[0], flagsEnum.None, props); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if arg2, err = b.processNode(root.Args[1]); err != nil {
|
if arg2, err = b.processNode(root.Args[1], flagsEnum.None, props); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if len(root.Args) == 3 {
|
if len(root.Args) == 3 {
|
||||||
if arg3, err = b.processNode(root.Args[2]); err != nil {
|
if arg3, err = b.processNode(root.Args[2], flagsEnum.None, props); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
qyOutput = &functionQuery{Input: b.firstInput, Func: substringFunc(arg1, arg2, arg3)}
|
qyOutput = &functionQuery{Func: substringFunc(arg1, arg2, arg3)}
|
||||||
case "substring-before", "substring-after":
|
case "substring-before", "substring-after":
|
||||||
//substring-xxxx( haystack, needle )
|
//substring-xxxx( haystack, needle )
|
||||||
if len(root.Args) != 2 {
|
if len(root.Args) != 2 {
|
||||||
@ -255,31 +426,30 @@ func (b *builder) processFunctionNode(root *functionNode) (query, error) {
|
|||||||
arg1, arg2 query
|
arg1, arg2 query
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
if arg1, err = b.processNode(root.Args[0]); err != nil {
|
if arg1, err = b.processNode(root.Args[0], flagsEnum.None, props); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if arg2, err = b.processNode(root.Args[1]); err != nil {
|
if arg2, err = b.processNode(root.Args[1], flagsEnum.None, props); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
qyOutput = &functionQuery{
|
qyOutput = &functionQuery{
|
||||||
Input: b.firstInput,
|
Func: substringIndFunc(arg1, arg2, root.FuncName == "substring-after"),
|
||||||
Func: substringIndFunc(arg1, arg2, root.FuncName == "substring-after"),
|
|
||||||
}
|
}
|
||||||
case "string-length":
|
case "string-length":
|
||||||
// string-length( [string] )
|
// string-length( [string] )
|
||||||
if len(root.Args) < 1 {
|
if len(root.Args) < 1 {
|
||||||
return nil, errors.New("xpath: string-length function must have at least one parameter")
|
return nil, errors.New("xpath: string-length function must have at least one parameter")
|
||||||
}
|
}
|
||||||
arg1, err := b.processNode(root.Args[0])
|
arg1, err := b.processNode(root.Args[0], flagsEnum.None, props)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
qyOutput = &functionQuery{Input: b.firstInput, Func: stringLengthFunc(arg1)}
|
qyOutput = &functionQuery{Func: stringLengthFunc(arg1)}
|
||||||
case "normalize-space":
|
case "normalize-space":
|
||||||
if len(root.Args) == 0 {
|
if len(root.Args) == 0 {
|
||||||
return nil, errors.New("xpath: normalize-space function must have at least one parameter")
|
return nil, errors.New("xpath: normalize-space function must have at least one parameter")
|
||||||
}
|
}
|
||||||
argQuery, err := b.processNode(root.Args[0])
|
argQuery, err := b.processNode(root.Args[0], flagsEnum.None, props)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -293,16 +463,16 @@ func (b *builder) processFunctionNode(root *functionNode) (query, error) {
|
|||||||
arg1, arg2, arg3 query
|
arg1, arg2, arg3 query
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
if arg1, err = b.processNode(root.Args[0]); err != nil {
|
if arg1, err = b.processNode(root.Args[0], flagsEnum.None, props); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if arg2, err = b.processNode(root.Args[1]); err != nil {
|
if arg2, err = b.processNode(root.Args[1], flagsEnum.None, props); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if arg3, err = b.processNode(root.Args[2]); err != nil {
|
if arg3, err = b.processNode(root.Args[2], flagsEnum.None, props); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
qyOutput = &functionQuery{Input: b.firstInput, Func: replaceFunc(arg1, arg2, arg3)}
|
qyOutput = &functionQuery{Func: replaceFunc(arg1, arg2, arg3)}
|
||||||
case "translate":
|
case "translate":
|
||||||
//translate( string , string, string )
|
//translate( string , string, string )
|
||||||
if len(root.Args) != 3 {
|
if len(root.Args) != 3 {
|
||||||
@ -312,21 +482,21 @@ func (b *builder) processFunctionNode(root *functionNode) (query, error) {
|
|||||||
arg1, arg2, arg3 query
|
arg1, arg2, arg3 query
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
if arg1, err = b.processNode(root.Args[0]); err != nil {
|
if arg1, err = b.processNode(root.Args[0], flagsEnum.None, props); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if arg2, err = b.processNode(root.Args[1]); err != nil {
|
if arg2, err = b.processNode(root.Args[1], flagsEnum.None, props); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if arg3, err = b.processNode(root.Args[2]); err != nil {
|
if arg3, err = b.processNode(root.Args[2], flagsEnum.None, props); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
qyOutput = &functionQuery{Input: b.firstInput, Func: translateFunc(arg1, arg2, arg3)}
|
qyOutput = &functionQuery{Func: translateFunc(arg1, arg2, arg3)}
|
||||||
case "not":
|
case "not":
|
||||||
if len(root.Args) == 0 {
|
if len(root.Args) == 0 {
|
||||||
return nil, errors.New("xpath: not function must have at least one parameter")
|
return nil, errors.New("xpath: not function must have at least one parameter")
|
||||||
}
|
}
|
||||||
argQuery, err := b.processNode(root.Args[0])
|
argQuery, err := b.processNode(root.Args[0], flagsEnum.None, props)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -340,46 +510,46 @@ func (b *builder) processFunctionNode(root *functionNode) (query, error) {
|
|||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
if len(root.Args) == 1 {
|
if len(root.Args) == 1 {
|
||||||
arg, err = b.processNode(root.Args[0])
|
arg, err = b.processNode(root.Args[0], flagsEnum.None, props)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch root.FuncName {
|
switch root.FuncName {
|
||||||
case "name":
|
case "name":
|
||||||
qyOutput = &functionQuery{Input: b.firstInput, Func: nameFunc(arg)}
|
qyOutput = &functionQuery{Func: nameFunc(arg)}
|
||||||
case "local-name":
|
case "local-name":
|
||||||
qyOutput = &functionQuery{Input: b.firstInput, Func: localNameFunc(arg)}
|
qyOutput = &functionQuery{Func: localNameFunc(arg)}
|
||||||
case "namespace-uri":
|
case "namespace-uri":
|
||||||
qyOutput = &functionQuery{Input: b.firstInput, Func: namespaceFunc(arg)}
|
qyOutput = &functionQuery{Func: namespaceFunc(arg)}
|
||||||
}
|
}
|
||||||
case "true", "false":
|
case "true", "false":
|
||||||
val := root.FuncName == "true"
|
val := root.FuncName == "true"
|
||||||
qyOutput = &functionQuery{
|
qyOutput = &functionQuery{
|
||||||
Input: b.firstInput,
|
|
||||||
Func: func(_ query, _ iterator) interface{} {
|
Func: func(_ query, _ iterator) interface{} {
|
||||||
return val
|
return val
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
case "last":
|
case "last":
|
||||||
switch typ := b.firstInput.(type) {
|
//switch typ := b.firstInput.(type) {
|
||||||
case *groupQuery, *filterQuery:
|
//case *groupQuery, *filterQuery:
|
||||||
// https://github.com/antchfx/xpath/issues/76
|
// https://github.com/antchfx/xpath/issues/76
|
||||||
// https://github.com/antchfx/xpath/issues/78
|
// https://github.com/antchfx/xpath/issues/78
|
||||||
qyOutput = &lastQuery{Input: typ}
|
//qyOutput = &lastQuery{Input: typ}
|
||||||
default:
|
//default:
|
||||||
qyOutput = &functionQuery{Input: b.firstInput, Func: lastFunc}
|
qyOutput = &functionQuery{Func: lastFunc}
|
||||||
}
|
//}
|
||||||
|
*props |= builderProps.HasLast
|
||||||
case "position":
|
case "position":
|
||||||
qyOutput = &functionQuery{Input: b.firstInput, Func: positionFunc}
|
qyOutput = &functionQuery{Func: positionFunc}
|
||||||
|
*props |= builderProps.HasPosition
|
||||||
case "boolean", "number", "string":
|
case "boolean", "number", "string":
|
||||||
inp := b.firstInput
|
var inp query
|
||||||
if len(root.Args) > 1 {
|
if len(root.Args) > 1 {
|
||||||
return nil, fmt.Errorf("xpath: %s function must have at most one parameter", root.FuncName)
|
return nil, fmt.Errorf("xpath: %s function must have at most one parameter", root.FuncName)
|
||||||
}
|
}
|
||||||
if len(root.Args) == 1 {
|
if len(root.Args) == 1 {
|
||||||
argQuery, err := b.processNode(root.Args[0])
|
argQuery, err := b.processNode(root.Args[0], flagsEnum.None, props)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -396,13 +566,10 @@ func (b *builder) processFunctionNode(root *functionNode) (query, error) {
|
|||||||
}
|
}
|
||||||
qyOutput = f
|
qyOutput = f
|
||||||
case "count":
|
case "count":
|
||||||
//if b.firstInput == nil {
|
|
||||||
// return nil, errors.New("xpath: expression must evaluate to node-set")
|
|
||||||
//}
|
|
||||||
if len(root.Args) == 0 {
|
if len(root.Args) == 0 {
|
||||||
return nil, fmt.Errorf("xpath: count(node-sets) function must with have parameters node-sets")
|
return nil, fmt.Errorf("xpath: count(node-sets) function must with have parameters node-sets")
|
||||||
}
|
}
|
||||||
argQuery, err := b.processNode(root.Args[0])
|
argQuery, err := b.processNode(root.Args[0], flagsEnum.None, props)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -411,7 +578,7 @@ func (b *builder) processFunctionNode(root *functionNode) (query, error) {
|
|||||||
if len(root.Args) == 0 {
|
if len(root.Args) == 0 {
|
||||||
return nil, fmt.Errorf("xpath: sum(node-sets) function must with have parameters node-sets")
|
return nil, fmt.Errorf("xpath: sum(node-sets) function must with have parameters node-sets")
|
||||||
}
|
}
|
||||||
argQuery, err := b.processNode(root.Args[0])
|
argQuery, err := b.processNode(root.Args[0], flagsEnum.None, props)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -420,7 +587,7 @@ func (b *builder) processFunctionNode(root *functionNode) (query, error) {
|
|||||||
if len(root.Args) == 0 {
|
if len(root.Args) == 0 {
|
||||||
return nil, fmt.Errorf("xpath: ceiling(node-sets) function must with have parameters node-sets")
|
return nil, fmt.Errorf("xpath: ceiling(node-sets) function must with have parameters node-sets")
|
||||||
}
|
}
|
||||||
argQuery, err := b.processNode(root.Args[0])
|
argQuery, err := b.processNode(root.Args[0], flagsEnum.None, props)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -440,18 +607,18 @@ func (b *builder) processFunctionNode(root *functionNode) (query, error) {
|
|||||||
}
|
}
|
||||||
var args []query
|
var args []query
|
||||||
for _, v := range root.Args {
|
for _, v := range root.Args {
|
||||||
q, err := b.processNode(v)
|
q, err := b.processNode(v, flagsEnum.None, props)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
args = append(args, q)
|
args = append(args, q)
|
||||||
}
|
}
|
||||||
qyOutput = &functionQuery{Input: b.firstInput, Func: concatFunc(args...)}
|
qyOutput = &functionQuery{Func: concatFunc(args...)}
|
||||||
case "reverse":
|
case "reverse":
|
||||||
if len(root.Args) == 0 {
|
if len(root.Args) == 0 {
|
||||||
return nil, fmt.Errorf("xpath: reverse(node-sets) function must with have parameters node-sets")
|
return nil, fmt.Errorf("xpath: reverse(node-sets) function must with have parameters node-sets")
|
||||||
}
|
}
|
||||||
argQuery, err := b.processNode(root.Args[0])
|
argQuery, err := b.processNode(root.Args[0], flagsEnum.None, props)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -460,11 +627,11 @@ func (b *builder) processFunctionNode(root *functionNode) (query, error) {
|
|||||||
if len(root.Args) != 2 {
|
if len(root.Args) != 2 {
|
||||||
return nil, fmt.Errorf("xpath: string-join(node-sets, separator) function requires node-set and argument")
|
return nil, fmt.Errorf("xpath: string-join(node-sets, separator) function requires node-set and argument")
|
||||||
}
|
}
|
||||||
argQuery, err := b.processNode(root.Args[0])
|
argQuery, err := b.processNode(root.Args[0], flagsEnum.None, props)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
arg1, err := b.processNode(root.Args[1])
|
arg1, err := b.processNode(root.Args[1], flagsEnum.None, props)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -472,22 +639,33 @@ func (b *builder) processFunctionNode(root *functionNode) (query, error) {
|
|||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("not yet support this function %s()", root.FuncName)
|
return nil, fmt.Errorf("not yet support this function %s()", root.FuncName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if funcQuery, ok := qyOutput.(*functionQuery); ok && funcQuery.Input == nil {
|
||||||
|
funcQuery.Input = b.firstInput
|
||||||
|
}
|
||||||
return qyOutput, nil
|
return qyOutput, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *builder) processOperatorNode(root *operatorNode) (query, error) {
|
func (b *builder) processOperator(root *operatorNode, props *builderProp) (query, error) {
|
||||||
left, err := b.processNode(root.Left)
|
var (
|
||||||
|
leftProp builderProp
|
||||||
|
rightProp builderProp
|
||||||
|
)
|
||||||
|
|
||||||
|
left, err := b.processNode(root.Left, flagsEnum.None, &leftProp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
right, err := b.processNode(root.Right)
|
right, err := b.processNode(root.Right, flagsEnum.None, &rightProp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
*props = leftProp | rightProp
|
||||||
|
|
||||||
var qyOutput query
|
var qyOutput query
|
||||||
switch root.Op {
|
switch root.Op {
|
||||||
case "+", "-", "*", "div", "mod": // Numeric operator
|
case "+", "-", "*", "div", "mod": // Numeric operator
|
||||||
var exprFunc func(interface{}, interface{}) interface{}
|
var exprFunc func(iterator, interface{}, interface{}) interface{}
|
||||||
switch root.Op {
|
switch root.Op {
|
||||||
case "+":
|
case "+":
|
||||||
exprFunc = plusFunc
|
exprFunc = plusFunc
|
||||||
@ -525,41 +703,45 @@ func (b *builder) processOperatorNode(root *operatorNode) (query, error) {
|
|||||||
}
|
}
|
||||||
qyOutput = &booleanQuery{Left: left, Right: right, IsOr: isOr}
|
qyOutput = &booleanQuery{Left: left, Right: right, IsOr: isOr}
|
||||||
case "|":
|
case "|":
|
||||||
|
*props |= builderProps.NonFlat
|
||||||
qyOutput = &unionQuery{Left: left, Right: right}
|
qyOutput = &unionQuery{Left: left, Right: right}
|
||||||
}
|
}
|
||||||
return qyOutput, nil
|
return qyOutput, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *builder) processNode(root node) (q query, err error) {
|
func (b *builder) processNode(root node, flags flag, props *builderProp) (q query, err error) {
|
||||||
if b.depth = b.depth + 1; b.depth > 1024 {
|
if b.parseDepth = b.parseDepth + 1; b.parseDepth > 1024 {
|
||||||
err = errors.New("the xpath expressions is too complex")
|
err = errors.New("the xpath expressions is too complex")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
*props = builderProps.None
|
||||||
switch root.Type() {
|
switch root.Type() {
|
||||||
case nodeConstantOperand:
|
case nodeConstantOperand:
|
||||||
n := root.(*operandNode)
|
n := root.(*operandNode)
|
||||||
q = &constantQuery{Val: n.Val}
|
q = &constantQuery{Val: n.Val}
|
||||||
case nodeRoot:
|
case nodeRoot:
|
||||||
q = &contextQuery{Root: true}
|
q = &absoluteQuery{}
|
||||||
case nodeAxis:
|
case nodeAxis:
|
||||||
q, err = b.processAxisNode(root.(*axisNode))
|
q, err = b.processAxis(root.(*axisNode), flags, props)
|
||||||
b.firstInput = q
|
b.firstInput = q
|
||||||
case nodeFilter:
|
case nodeFilter:
|
||||||
q, err = b.processFilterNode(root.(*filterNode))
|
q, err = b.processFilter(root.(*filterNode), flags, props)
|
||||||
b.firstInput = q
|
b.firstInput = q
|
||||||
case nodeFunction:
|
case nodeFunction:
|
||||||
q, err = b.processFunctionNode(root.(*functionNode))
|
q, err = b.processFunction(root.(*functionNode), props)
|
||||||
case nodeOperator:
|
case nodeOperator:
|
||||||
q, err = b.processOperatorNode(root.(*operatorNode))
|
q, err = b.processOperator(root.(*operatorNode), props)
|
||||||
case nodeGroup:
|
case nodeGroup:
|
||||||
q, err = b.processNode(root.(*groupNode).Input)
|
q, err = b.processNode(root.(*groupNode).Input, flagsEnum.None, props)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
q = &groupQuery{Input: q}
|
q = &groupQuery{Input: q}
|
||||||
b.firstInput = q
|
if b.firstInput == nil {
|
||||||
|
b.firstInput = q
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
b.parseDepth--
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -579,5 +761,6 @@ func build(expr string, namespaces map[string]string) (q query, err error) {
|
|||||||
}()
|
}()
|
||||||
root := parse(expr, namespaces)
|
root := parse(expr, namespaces)
|
||||||
b := &builder{}
|
b := &builder{}
|
||||||
return b.processNode(root)
|
props := builderProps.None
|
||||||
|
return b.processNode(root, flagsEnum.None, &props)
|
||||||
}
|
}
|
||||||
|
8
vendor/github.com/antchfx/xpath/func.go
generated
vendored
8
vendor/github.com/antchfx/xpath/func.go
generated
vendored
@ -113,7 +113,7 @@ func asNumber(t iterator, o interface{}) float64 {
|
|||||||
case query:
|
case query:
|
||||||
node := typ.Select(t)
|
node := typ.Select(t)
|
||||||
if node == nil {
|
if node == nil {
|
||||||
return float64(0)
|
return math.NaN()
|
||||||
}
|
}
|
||||||
if v, err := strconv.ParseFloat(node.Value(), 64); err == nil {
|
if v, err := strconv.ParseFloat(node.Value(), 64); err == nil {
|
||||||
return v
|
return v
|
||||||
@ -645,3 +645,9 @@ func stringJoinFunc(arg1 query) func(query, iterator) interface{} {
|
|||||||
return strings.Join(parts, separator)
|
return strings.Join(parts, separator)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// lower-case is XPATH function that converts a string to lower case.
|
||||||
|
func lowerCaseFunc(q query, t iterator) interface{} {
|
||||||
|
v := functionArgs(q).Evaluate(t)
|
||||||
|
return strings.ToLower(asString(t, v))
|
||||||
|
}
|
||||||
|
86
vendor/github.com/antchfx/xpath/operator.go
generated
vendored
86
vendor/github.com/antchfx/xpath/operator.go
generated
vendored
@ -1,40 +1,11 @@
|
|||||||
package xpath
|
package xpath
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The XPath number operator function list.
|
// The XPath number operator function list.
|
||||||
|
|
||||||
// valueType is a return value type.
|
|
||||||
type valueType int
|
|
||||||
|
|
||||||
const (
|
|
||||||
booleanType valueType = iota
|
|
||||||
numberType
|
|
||||||
stringType
|
|
||||||
nodeSetType
|
|
||||||
)
|
|
||||||
|
|
||||||
func getValueType(i interface{}) valueType {
|
|
||||||
v := reflect.ValueOf(i)
|
|
||||||
switch v.Kind() {
|
|
||||||
case reflect.Float64:
|
|
||||||
return numberType
|
|
||||||
case reflect.String:
|
|
||||||
return stringType
|
|
||||||
case reflect.Bool:
|
|
||||||
return booleanType
|
|
||||||
default:
|
|
||||||
if _, ok := i.(query); ok {
|
|
||||||
return nodeSetType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
panic(fmt.Errorf("xpath unknown value type: %v", v.Kind()))
|
|
||||||
}
|
|
||||||
|
|
||||||
type logical func(iterator, string, interface{}, interface{}) bool
|
type logical func(iterator, string, interface{}, interface{}) bool
|
||||||
|
|
||||||
var logicalFuncs = [][]logical{
|
var logicalFuncs = [][]logical{
|
||||||
@ -228,91 +199,90 @@ func cmpBooleanBoolean(t iterator, op string, m, n interface{}) bool {
|
|||||||
|
|
||||||
// eqFunc is an `=` operator.
|
// eqFunc is an `=` operator.
|
||||||
func eqFunc(t iterator, m, n interface{}) interface{} {
|
func eqFunc(t iterator, m, n interface{}) interface{} {
|
||||||
t1 := getValueType(m)
|
t1 := getXPathType(m)
|
||||||
t2 := getValueType(n)
|
t2 := getXPathType(n)
|
||||||
return logicalFuncs[t1][t2](t, "=", m, n)
|
return logicalFuncs[t1][t2](t, "=", m, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
// gtFunc is an `>` operator.
|
// gtFunc is an `>` operator.
|
||||||
func gtFunc(t iterator, m, n interface{}) interface{} {
|
func gtFunc(t iterator, m, n interface{}) interface{} {
|
||||||
t1 := getValueType(m)
|
t1 := getXPathType(m)
|
||||||
t2 := getValueType(n)
|
t2 := getXPathType(n)
|
||||||
return logicalFuncs[t1][t2](t, ">", m, n)
|
return logicalFuncs[t1][t2](t, ">", m, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
// geFunc is an `>=` operator.
|
// geFunc is an `>=` operator.
|
||||||
func geFunc(t iterator, m, n interface{}) interface{} {
|
func geFunc(t iterator, m, n interface{}) interface{} {
|
||||||
t1 := getValueType(m)
|
t1 := getXPathType(m)
|
||||||
t2 := getValueType(n)
|
t2 := getXPathType(n)
|
||||||
return logicalFuncs[t1][t2](t, ">=", m, n)
|
return logicalFuncs[t1][t2](t, ">=", m, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ltFunc is an `<` operator.
|
// ltFunc is an `<` operator.
|
||||||
func ltFunc(t iterator, m, n interface{}) interface{} {
|
func ltFunc(t iterator, m, n interface{}) interface{} {
|
||||||
t1 := getValueType(m)
|
t1 := getXPathType(m)
|
||||||
t2 := getValueType(n)
|
t2 := getXPathType(n)
|
||||||
return logicalFuncs[t1][t2](t, "<", m, n)
|
return logicalFuncs[t1][t2](t, "<", m, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
// leFunc is an `<=` operator.
|
// leFunc is an `<=` operator.
|
||||||
func leFunc(t iterator, m, n interface{}) interface{} {
|
func leFunc(t iterator, m, n interface{}) interface{} {
|
||||||
t1 := getValueType(m)
|
t1 := getXPathType(m)
|
||||||
t2 := getValueType(n)
|
t2 := getXPathType(n)
|
||||||
return logicalFuncs[t1][t2](t, "<=", m, n)
|
return logicalFuncs[t1][t2](t, "<=", m, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
// neFunc is an `!=` operator.
|
// neFunc is an `!=` operator.
|
||||||
func neFunc(t iterator, m, n interface{}) interface{} {
|
func neFunc(t iterator, m, n interface{}) interface{} {
|
||||||
t1 := getValueType(m)
|
t1 := getXPathType(m)
|
||||||
t2 := getValueType(n)
|
t2 := getXPathType(n)
|
||||||
return logicalFuncs[t1][t2](t, "!=", m, n)
|
return logicalFuncs[t1][t2](t, "!=", m, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
// orFunc is an `or` operator.
|
// orFunc is an `or` operator.
|
||||||
var orFunc = func(t iterator, m, n interface{}) interface{} {
|
var orFunc = func(t iterator, m, n interface{}) interface{} {
|
||||||
t1 := getValueType(m)
|
t1 := getXPathType(m)
|
||||||
t2 := getValueType(n)
|
t2 := getXPathType(n)
|
||||||
return logicalFuncs[t1][t2](t, "or", m, n)
|
return logicalFuncs[t1][t2](t, "or", m, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
func numericExpr(m, n interface{}, cb func(float64, float64) float64) float64 {
|
func numericExpr(t iterator, m, n interface{}, cb func(float64, float64) float64) float64 {
|
||||||
typ := reflect.TypeOf(float64(0))
|
a := asNumber(t, m)
|
||||||
a := reflect.ValueOf(m).Convert(typ)
|
b := asNumber(t, n)
|
||||||
b := reflect.ValueOf(n).Convert(typ)
|
return cb(a, b)
|
||||||
return cb(a.Float(), b.Float())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// plusFunc is an `+` operator.
|
// plusFunc is an `+` operator.
|
||||||
var plusFunc = func(m, n interface{}) interface{} {
|
var plusFunc = func(t iterator, m, n interface{}) interface{} {
|
||||||
return numericExpr(m, n, func(a, b float64) float64 {
|
return numericExpr(t, m, n, func(a, b float64) float64 {
|
||||||
return a + b
|
return a + b
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// minusFunc is an `-` operator.
|
// minusFunc is an `-` operator.
|
||||||
var minusFunc = func(m, n interface{}) interface{} {
|
var minusFunc = func(t iterator, m, n interface{}) interface{} {
|
||||||
return numericExpr(m, n, func(a, b float64) float64 {
|
return numericExpr(t, m, n, func(a, b float64) float64 {
|
||||||
return a - b
|
return a - b
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// mulFunc is an `*` operator.
|
// mulFunc is an `*` operator.
|
||||||
var mulFunc = func(m, n interface{}) interface{} {
|
var mulFunc = func(t iterator, m, n interface{}) interface{} {
|
||||||
return numericExpr(m, n, func(a, b float64) float64 {
|
return numericExpr(t, m, n, func(a, b float64) float64 {
|
||||||
return a * b
|
return a * b
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// divFunc is an `DIV` operator.
|
// divFunc is an `DIV` operator.
|
||||||
var divFunc = func(m, n interface{}) interface{} {
|
var divFunc = func(t iterator, m, n interface{}) interface{} {
|
||||||
return numericExpr(m, n, func(a, b float64) float64 {
|
return numericExpr(t, m, n, func(a, b float64) float64 {
|
||||||
return a / b
|
return a / b
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// modFunc is an 'MOD' operator.
|
// modFunc is an 'MOD' operator.
|
||||||
var modFunc = func(m, n interface{}) interface{} {
|
var modFunc = func(t iterator, m, n interface{}) interface{} {
|
||||||
return numericExpr(m, n, func(a, b float64) float64 {
|
return numericExpr(t, m, n, func(a, b float64) float64 {
|
||||||
return float64(int(a) % int(b))
|
return float64(int(a) % int(b))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
529
vendor/github.com/antchfx/xpath/query.go
generated
vendored
529
vendor/github.com/antchfx/xpath/query.go
generated
vendored
@ -7,6 +7,44 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// The return type of the XPath expression.
|
||||||
|
type resultType int
|
||||||
|
|
||||||
|
var xpathResultType = struct {
|
||||||
|
Boolean resultType
|
||||||
|
// A numeric value
|
||||||
|
Number resultType
|
||||||
|
String resultType
|
||||||
|
// A node collection.
|
||||||
|
NodeSet resultType
|
||||||
|
// Any of the XPath node types.
|
||||||
|
Any resultType
|
||||||
|
}{
|
||||||
|
Boolean: 0,
|
||||||
|
Number: 1,
|
||||||
|
String: 2,
|
||||||
|
NodeSet: 3,
|
||||||
|
Any: 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
type queryProp int
|
||||||
|
|
||||||
|
var queryProps = struct {
|
||||||
|
None queryProp
|
||||||
|
Position queryProp
|
||||||
|
Count queryProp
|
||||||
|
Cached queryProp
|
||||||
|
Reverse queryProp
|
||||||
|
Merge queryProp
|
||||||
|
}{
|
||||||
|
None: 0,
|
||||||
|
Position: 1,
|
||||||
|
Count: 2,
|
||||||
|
Cached: 4,
|
||||||
|
Reverse: 8,
|
||||||
|
Merge: 16,
|
||||||
|
}
|
||||||
|
|
||||||
type iterator interface {
|
type iterator interface {
|
||||||
Current() NodeNavigator
|
Current() NodeNavigator
|
||||||
}
|
}
|
||||||
@ -20,12 +58,15 @@ type query interface {
|
|||||||
Evaluate(iterator) interface{}
|
Evaluate(iterator) interface{}
|
||||||
|
|
||||||
Clone() query
|
Clone() query
|
||||||
|
|
||||||
|
// ValueType returns the value type of the current query.
|
||||||
|
ValueType() resultType
|
||||||
|
|
||||||
|
Properties() queryProp
|
||||||
}
|
}
|
||||||
|
|
||||||
// nopQuery is an empty query that always return nil for any query.
|
// nopQuery is an empty query that always return nil for any query.
|
||||||
type nopQuery struct {
|
type nopQuery struct{}
|
||||||
query
|
|
||||||
}
|
|
||||||
|
|
||||||
func (nopQuery) Select(iterator) NodeNavigator { return nil }
|
func (nopQuery) Select(iterator) NodeNavigator { return nil }
|
||||||
|
|
||||||
@ -33,21 +74,23 @@ func (nopQuery) Evaluate(iterator) interface{} { return nil }
|
|||||||
|
|
||||||
func (nopQuery) Clone() query { return nopQuery{} }
|
func (nopQuery) Clone() query { return nopQuery{} }
|
||||||
|
|
||||||
|
func (nopQuery) ValueType() resultType { return xpathResultType.NodeSet }
|
||||||
|
|
||||||
|
func (nopQuery) Properties() queryProp {
|
||||||
|
return queryProps.Merge | queryProps.Position | queryProps.Count | queryProps.Cached
|
||||||
|
}
|
||||||
|
|
||||||
// contextQuery is returns current node on the iterator object query.
|
// contextQuery is returns current node on the iterator object query.
|
||||||
type contextQuery struct {
|
type contextQuery struct {
|
||||||
count int
|
count int
|
||||||
Root bool // Moving to root-level node in the current context iterator.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *contextQuery) Select(t iterator) (n NodeNavigator) {
|
func (c *contextQuery) Select(t iterator) NodeNavigator {
|
||||||
if c.count == 0 {
|
if c.count > 0 {
|
||||||
c.count++
|
return nil
|
||||||
n = t.Current().Copy()
|
|
||||||
if c.Root {
|
|
||||||
n.MoveToRoot()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return n
|
c.count++
|
||||||
|
return t.Current().Copy()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *contextQuery) Evaluate(iterator) interface{} {
|
func (c *contextQuery) Evaluate(iterator) interface{} {
|
||||||
@ -56,12 +99,53 @@ func (c *contextQuery) Evaluate(iterator) interface{} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *contextQuery) Clone() query {
|
func (c *contextQuery) Clone() query {
|
||||||
return &contextQuery{Root: c.Root}
|
return &contextQuery{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *contextQuery) ValueType() resultType {
|
||||||
|
return xpathResultType.NodeSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *contextQuery) Properties() queryProp {
|
||||||
|
return queryProps.Merge | queryProps.Position | queryProps.Count | queryProps.Cached
|
||||||
|
}
|
||||||
|
|
||||||
|
type absoluteQuery struct {
|
||||||
|
count int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *absoluteQuery) Select(t iterator) (n NodeNavigator) {
|
||||||
|
if a.count > 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
a.count++
|
||||||
|
n = t.Current().Copy()
|
||||||
|
n.MoveToRoot()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *absoluteQuery) Evaluate(t iterator) interface{} {
|
||||||
|
a.count = 0
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *absoluteQuery) Clone() query {
|
||||||
|
return &absoluteQuery{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *absoluteQuery) ValueType() resultType {
|
||||||
|
return xpathResultType.NodeSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *absoluteQuery) Properties() queryProp {
|
||||||
|
return queryProps.Merge | queryProps.Position | queryProps.Count | queryProps.Cached
|
||||||
}
|
}
|
||||||
|
|
||||||
// ancestorQuery is an XPath ancestor node query.(ancestor::*|ancestor-self::*)
|
// ancestorQuery is an XPath ancestor node query.(ancestor::*|ancestor-self::*)
|
||||||
type ancestorQuery struct {
|
type ancestorQuery struct {
|
||||||
|
name string
|
||||||
iterator func() NodeNavigator
|
iterator func() NodeNavigator
|
||||||
|
table map[uint64]bool
|
||||||
|
|
||||||
Self bool
|
Self bool
|
||||||
Input query
|
Input query
|
||||||
@ -69,6 +153,10 @@ type ancestorQuery struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *ancestorQuery) Select(t iterator) NodeNavigator {
|
func (a *ancestorQuery) Select(t iterator) NodeNavigator {
|
||||||
|
if a.table == nil {
|
||||||
|
a.table = make(map[uint64]bool)
|
||||||
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if a.iterator == nil {
|
if a.iterator == nil {
|
||||||
node := a.Input.Select(t)
|
node := a.Input.Select(t)
|
||||||
@ -78,24 +166,27 @@ func (a *ancestorQuery) Select(t iterator) NodeNavigator {
|
|||||||
first := true
|
first := true
|
||||||
node = node.Copy()
|
node = node.Copy()
|
||||||
a.iterator = func() NodeNavigator {
|
a.iterator = func() NodeNavigator {
|
||||||
if first && a.Self {
|
if first {
|
||||||
first = false
|
first = false
|
||||||
if a.Predicate(node) {
|
if a.Self && a.Predicate(node) {
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for node.MoveToParent() {
|
for node.MoveToParent() {
|
||||||
if !a.Predicate(node) {
|
if a.Predicate(node) {
|
||||||
continue
|
return node
|
||||||
}
|
}
|
||||||
return node
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if node := a.iterator(); node != nil {
|
for node := a.iterator(); node != nil; node = a.iterator() {
|
||||||
return node
|
node_id := getHashCode(node.Copy())
|
||||||
|
if _, ok := a.table[node_id]; !ok {
|
||||||
|
a.table[node_id] = true
|
||||||
|
return node
|
||||||
|
}
|
||||||
}
|
}
|
||||||
a.iterator = nil
|
a.iterator = nil
|
||||||
}
|
}
|
||||||
@ -112,11 +203,20 @@ func (a *ancestorQuery) Test(n NodeNavigator) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *ancestorQuery) Clone() query {
|
func (a *ancestorQuery) Clone() query {
|
||||||
return &ancestorQuery{Self: a.Self, Input: a.Input.Clone(), Predicate: a.Predicate}
|
return &ancestorQuery{name: a.name, Self: a.Self, Input: a.Input.Clone(), Predicate: a.Predicate}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ancestorQuery) ValueType() resultType {
|
||||||
|
return xpathResultType.NodeSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ancestorQuery) Properties() queryProp {
|
||||||
|
return queryProps.Position | queryProps.Count | queryProps.Cached | queryProps.Merge | queryProps.Reverse
|
||||||
}
|
}
|
||||||
|
|
||||||
// attributeQuery is an XPath attribute node query.(@*)
|
// attributeQuery is an XPath attribute node query.(@*)
|
||||||
type attributeQuery struct {
|
type attributeQuery struct {
|
||||||
|
name string
|
||||||
iterator func() NodeNavigator
|
iterator func() NodeNavigator
|
||||||
|
|
||||||
Input query
|
Input query
|
||||||
@ -162,11 +262,20 @@ func (a *attributeQuery) Test(n NodeNavigator) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *attributeQuery) Clone() query {
|
func (a *attributeQuery) Clone() query {
|
||||||
return &attributeQuery{Input: a.Input.Clone(), Predicate: a.Predicate}
|
return &attributeQuery{name: a.name, Input: a.Input.Clone(), Predicate: a.Predicate}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *attributeQuery) ValueType() resultType {
|
||||||
|
return xpathResultType.NodeSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *attributeQuery) Properties() queryProp {
|
||||||
|
return queryProps.Merge
|
||||||
}
|
}
|
||||||
|
|
||||||
// childQuery is an XPath child node query.(child::*)
|
// childQuery is an XPath child node query.(child::*)
|
||||||
type childQuery struct {
|
type childQuery struct {
|
||||||
|
name string
|
||||||
posit int
|
posit int
|
||||||
iterator func() NodeNavigator
|
iterator func() NodeNavigator
|
||||||
|
|
||||||
@ -216,7 +325,15 @@ func (c *childQuery) Test(n NodeNavigator) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *childQuery) Clone() query {
|
func (c *childQuery) Clone() query {
|
||||||
return &childQuery{Input: c.Input.Clone(), Predicate: c.Predicate}
|
return &childQuery{name: c.name, Input: c.Input.Clone(), Predicate: c.Predicate}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *childQuery) ValueType() resultType {
|
||||||
|
return xpathResultType.NodeSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *childQuery) Properties() queryProp {
|
||||||
|
return queryProps.Merge
|
||||||
}
|
}
|
||||||
|
|
||||||
// position returns a position of current NodeNavigator.
|
// position returns a position of current NodeNavigator.
|
||||||
@ -224,8 +341,75 @@ func (c *childQuery) position() int {
|
|||||||
return c.posit
|
return c.posit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type cachedChildQuery struct {
|
||||||
|
name string
|
||||||
|
posit int
|
||||||
|
iterator func() NodeNavigator
|
||||||
|
|
||||||
|
Input query
|
||||||
|
Predicate func(NodeNavigator) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cachedChildQuery) Select(t iterator) 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() 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 *cachedChildQuery) Evaluate(t iterator) interface{} {
|
||||||
|
c.Input.Evaluate(t)
|
||||||
|
c.iterator = nil
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cachedChildQuery) position() int {
|
||||||
|
return c.posit
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cachedChildQuery) Test(n NodeNavigator) bool {
|
||||||
|
return c.Predicate(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cachedChildQuery) Clone() query {
|
||||||
|
return &childQuery{name: c.name, Input: c.Input.Clone(), Predicate: c.Predicate}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cachedChildQuery) ValueType() resultType {
|
||||||
|
return xpathResultType.NodeSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cachedChildQuery) Properties() queryProp {
|
||||||
|
return queryProps.Merge
|
||||||
|
}
|
||||||
|
|
||||||
// descendantQuery is an XPath descendant node query.(descendant::* | descendant-or-self::*)
|
// descendantQuery is an XPath descendant node query.(descendant::* | descendant-or-self::*)
|
||||||
type descendantQuery struct {
|
type descendantQuery struct {
|
||||||
|
name string
|
||||||
iterator func() NodeNavigator
|
iterator func() NodeNavigator
|
||||||
posit int
|
posit int
|
||||||
level int
|
level int
|
||||||
@ -245,14 +429,11 @@ func (d *descendantQuery) Select(t iterator) NodeNavigator {
|
|||||||
}
|
}
|
||||||
node = node.Copy()
|
node = node.Copy()
|
||||||
d.level = 0
|
d.level = 0
|
||||||
positmap := make(map[int]int)
|
|
||||||
first := true
|
first := true
|
||||||
d.iterator = func() NodeNavigator {
|
d.iterator = func() NodeNavigator {
|
||||||
if first && d.Self {
|
if first {
|
||||||
first = false
|
first = false
|
||||||
if d.Predicate(node) {
|
if d.Self && d.Predicate(node) {
|
||||||
d.posit = 1
|
|
||||||
positmap[d.level] = 1
|
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -260,7 +441,6 @@ func (d *descendantQuery) Select(t iterator) NodeNavigator {
|
|||||||
for {
|
for {
|
||||||
if node.MoveToChild() {
|
if node.MoveToChild() {
|
||||||
d.level = d.level + 1
|
d.level = d.level + 1
|
||||||
positmap[d.level] = 0
|
|
||||||
} else {
|
} else {
|
||||||
for {
|
for {
|
||||||
if d.level == 0 {
|
if d.level == 0 {
|
||||||
@ -274,8 +454,6 @@ func (d *descendantQuery) Select(t iterator) NodeNavigator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if d.Predicate(node) {
|
if d.Predicate(node) {
|
||||||
positmap[d.level]++
|
|
||||||
d.posit = positmap[d.level]
|
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -283,6 +461,7 @@ func (d *descendantQuery) Select(t iterator) NodeNavigator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if node := d.iterator(); node != nil {
|
if node := d.iterator(); node != nil {
|
||||||
|
d.posit++
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
d.iterator = nil
|
d.iterator = nil
|
||||||
@ -309,7 +488,15 @@ func (d *descendantQuery) depth() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *descendantQuery) Clone() query {
|
func (d *descendantQuery) Clone() query {
|
||||||
return &descendantQuery{Self: d.Self, Input: d.Input.Clone(), Predicate: d.Predicate}
|
return &descendantQuery{name: d.name, Self: d.Self, Input: d.Input.Clone(), Predicate: d.Predicate}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *descendantQuery) ValueType() resultType {
|
||||||
|
return xpathResultType.NodeSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *descendantQuery) Properties() queryProp {
|
||||||
|
return queryProps.Merge
|
||||||
}
|
}
|
||||||
|
|
||||||
// followingQuery is an XPath following node query.(following::*|following-sibling::*)
|
// followingQuery is an XPath following node query.(following::*|following-sibling::*)
|
||||||
@ -390,6 +577,14 @@ func (f *followingQuery) Clone() query {
|
|||||||
return &followingQuery{Input: f.Input.Clone(), Sibling: f.Sibling, Predicate: f.Predicate}
|
return &followingQuery{Input: f.Input.Clone(), Sibling: f.Sibling, Predicate: f.Predicate}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *followingQuery) ValueType() resultType {
|
||||||
|
return xpathResultType.NodeSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *followingQuery) Properties() queryProp {
|
||||||
|
return queryProps.Merge
|
||||||
|
}
|
||||||
|
|
||||||
func (f *followingQuery) position() int {
|
func (f *followingQuery) position() int {
|
||||||
return f.posit
|
return f.posit
|
||||||
}
|
}
|
||||||
@ -471,6 +666,14 @@ func (p *precedingQuery) Clone() query {
|
|||||||
return &precedingQuery{Input: p.Input.Clone(), Sibling: p.Sibling, Predicate: p.Predicate}
|
return &precedingQuery{Input: p.Input.Clone(), Sibling: p.Sibling, Predicate: p.Predicate}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *precedingQuery) ValueType() resultType {
|
||||||
|
return xpathResultType.NodeSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *precedingQuery) Properties() queryProp {
|
||||||
|
return queryProps.Merge | queryProps.Reverse
|
||||||
|
}
|
||||||
|
|
||||||
func (p *precedingQuery) position() int {
|
func (p *precedingQuery) position() int {
|
||||||
return p.posit
|
return p.posit
|
||||||
}
|
}
|
||||||
@ -503,6 +706,14 @@ func (p *parentQuery) Clone() query {
|
|||||||
return &parentQuery{Input: p.Input.Clone(), Predicate: p.Predicate}
|
return &parentQuery{Input: p.Input.Clone(), Predicate: p.Predicate}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *parentQuery) ValueType() resultType {
|
||||||
|
return xpathResultType.NodeSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parentQuery) Properties() queryProp {
|
||||||
|
return queryProps.Position | queryProps.Count | queryProps.Cached | queryProps.Merge
|
||||||
|
}
|
||||||
|
|
||||||
func (p *parentQuery) Test(n NodeNavigator) bool {
|
func (p *parentQuery) Test(n NodeNavigator) bool {
|
||||||
return p.Predicate(n)
|
return p.Predicate(n)
|
||||||
}
|
}
|
||||||
@ -539,12 +750,22 @@ func (s *selfQuery) Clone() query {
|
|||||||
return &selfQuery{Input: s.Input.Clone(), Predicate: s.Predicate}
|
return &selfQuery{Input: s.Input.Clone(), Predicate: s.Predicate}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *selfQuery) ValueType() resultType {
|
||||||
|
return xpathResultType.NodeSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *selfQuery) Properties() queryProp {
|
||||||
|
return queryProps.Merge
|
||||||
|
}
|
||||||
|
|
||||||
// filterQuery is an XPath query for predicate filter.
|
// filterQuery is an XPath query for predicate filter.
|
||||||
type filterQuery struct {
|
type filterQuery struct {
|
||||||
Input query
|
Input query
|
||||||
Predicate query
|
Predicate query
|
||||||
posit int
|
NoPosition bool
|
||||||
positmap map[int]int
|
|
||||||
|
posit int
|
||||||
|
positmap map[int]int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *filterQuery) do(t iterator) bool {
|
func (f *filterQuery) do(t iterator) bool {
|
||||||
@ -602,6 +823,14 @@ func (f *filterQuery) Clone() query {
|
|||||||
return &filterQuery{Input: f.Input.Clone(), Predicate: f.Predicate.Clone()}
|
return &filterQuery{Input: f.Input.Clone(), Predicate: f.Predicate.Clone()}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *filterQuery) ValueType() resultType {
|
||||||
|
return xpathResultType.NodeSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *filterQuery) Properties() queryProp {
|
||||||
|
return (queryProps.Position | f.Input.Properties()) & (queryProps.Reverse | queryProps.Merge)
|
||||||
|
}
|
||||||
|
|
||||||
// functionQuery is an XPath function that returns a computed value for
|
// functionQuery is an XPath function that returns a computed value for
|
||||||
// the Evaluate call of the current NodeNavigator node. Select call isn't
|
// the Evaluate call of the current NodeNavigator node. Select call isn't
|
||||||
// applicable for functionQuery.
|
// applicable for functionQuery.
|
||||||
@ -624,6 +853,14 @@ func (f *functionQuery) Clone() query {
|
|||||||
return &functionQuery{Input: f.Input.Clone(), Func: f.Func}
|
return &functionQuery{Input: f.Input.Clone(), Func: f.Func}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *functionQuery) ValueType() resultType {
|
||||||
|
return xpathResultType.Any
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *functionQuery) Properties() queryProp {
|
||||||
|
return queryProps.Merge
|
||||||
|
}
|
||||||
|
|
||||||
// transformFunctionQuery diffs from functionQuery where the latter computes a scalar
|
// transformFunctionQuery diffs from functionQuery where the latter computes a scalar
|
||||||
// value (number,string,boolean) for the current NodeNavigator node while the former
|
// value (number,string,boolean) for the current NodeNavigator node while the former
|
||||||
// (transformFunctionQuery) performs a mapping or transform of the current NodeNavigator
|
// (transformFunctionQuery) performs a mapping or transform of the current NodeNavigator
|
||||||
@ -652,6 +889,14 @@ func (f *transformFunctionQuery) Clone() query {
|
|||||||
return &transformFunctionQuery{Input: f.Input.Clone(), Func: f.Func}
|
return &transformFunctionQuery{Input: f.Input.Clone(), Func: f.Func}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *transformFunctionQuery) ValueType() resultType {
|
||||||
|
return xpathResultType.Any
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *transformFunctionQuery) Properties() queryProp {
|
||||||
|
return queryProps.Merge
|
||||||
|
}
|
||||||
|
|
||||||
// constantQuery is an XPath constant operand.
|
// constantQuery is an XPath constant operand.
|
||||||
type constantQuery struct {
|
type constantQuery struct {
|
||||||
Val interface{}
|
Val interface{}
|
||||||
@ -669,6 +914,14 @@ func (c *constantQuery) Clone() query {
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *constantQuery) ValueType() resultType {
|
||||||
|
return getXPathType(c.Val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *constantQuery) Properties() queryProp {
|
||||||
|
return queryProps.Position | queryProps.Count | queryProps.Cached | queryProps.Merge
|
||||||
|
}
|
||||||
|
|
||||||
type groupQuery struct {
|
type groupQuery struct {
|
||||||
posit int
|
posit int
|
||||||
|
|
||||||
@ -692,6 +945,14 @@ func (g *groupQuery) Clone() query {
|
|||||||
return &groupQuery{Input: g.Input.Clone()}
|
return &groupQuery{Input: g.Input.Clone()}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *groupQuery) ValueType() resultType {
|
||||||
|
return g.Input.ValueType()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *groupQuery) Properties() queryProp {
|
||||||
|
return queryProps.Position
|
||||||
|
}
|
||||||
|
|
||||||
func (g *groupQuery) position() int {
|
func (g *groupQuery) position() int {
|
||||||
return g.posit
|
return g.posit
|
||||||
}
|
}
|
||||||
@ -726,11 +987,19 @@ func (l *logicalQuery) Clone() query {
|
|||||||
return &logicalQuery{Left: l.Left.Clone(), Right: l.Right.Clone(), Do: l.Do}
|
return &logicalQuery{Left: l.Left.Clone(), Right: l.Right.Clone(), Do: l.Do}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *logicalQuery) ValueType() resultType {
|
||||||
|
return xpathResultType.Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *logicalQuery) Properties() queryProp {
|
||||||
|
return queryProps.Merge
|
||||||
|
}
|
||||||
|
|
||||||
// numericQuery is an XPath numeric operator expression.
|
// numericQuery is an XPath numeric operator expression.
|
||||||
type numericQuery struct {
|
type numericQuery struct {
|
||||||
Left, Right query
|
Left, Right query
|
||||||
|
|
||||||
Do func(interface{}, interface{}) interface{}
|
Do func(iterator, interface{}, interface{}) interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *numericQuery) Select(t iterator) NodeNavigator {
|
func (n *numericQuery) Select(t iterator) NodeNavigator {
|
||||||
@ -740,13 +1009,21 @@ func (n *numericQuery) Select(t iterator) NodeNavigator {
|
|||||||
func (n *numericQuery) Evaluate(t iterator) interface{} {
|
func (n *numericQuery) Evaluate(t iterator) interface{} {
|
||||||
m := n.Left.Evaluate(t)
|
m := n.Left.Evaluate(t)
|
||||||
k := n.Right.Evaluate(t)
|
k := n.Right.Evaluate(t)
|
||||||
return n.Do(m, k)
|
return n.Do(t, m, k)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *numericQuery) Clone() query {
|
func (n *numericQuery) Clone() query {
|
||||||
return &numericQuery{Left: n.Left.Clone(), Right: n.Right.Clone(), Do: n.Do}
|
return &numericQuery{Left: n.Left.Clone(), Right: n.Right.Clone(), Do: n.Do}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *numericQuery) ValueType() resultType {
|
||||||
|
return xpathResultType.Number
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *numericQuery) Properties() queryProp {
|
||||||
|
return queryProps.Merge
|
||||||
|
}
|
||||||
|
|
||||||
type booleanQuery struct {
|
type booleanQuery struct {
|
||||||
IsOr bool
|
IsOr bool
|
||||||
Left, Right query
|
Left, Right query
|
||||||
@ -837,6 +1114,14 @@ func (b *booleanQuery) Clone() query {
|
|||||||
return &booleanQuery{IsOr: b.IsOr, Left: b.Left.Clone(), Right: b.Right.Clone()}
|
return &booleanQuery{IsOr: b.IsOr, Left: b.Left.Clone(), Right: b.Right.Clone()}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *booleanQuery) ValueType() resultType {
|
||||||
|
return xpathResultType.Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *booleanQuery) Properties() queryProp {
|
||||||
|
return queryProps.Merge
|
||||||
|
}
|
||||||
|
|
||||||
type unionQuery struct {
|
type unionQuery struct {
|
||||||
Left, Right query
|
Left, Right query
|
||||||
iterator func() NodeNavigator
|
iterator func() NodeNavigator
|
||||||
@ -894,6 +1179,14 @@ func (u *unionQuery) Clone() query {
|
|||||||
return &unionQuery{Left: u.Left.Clone(), Right: u.Right.Clone()}
|
return &unionQuery{Left: u.Left.Clone(), Right: u.Right.Clone()}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *unionQuery) ValueType() resultType {
|
||||||
|
return xpathResultType.NodeSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *unionQuery) Properties() queryProp {
|
||||||
|
return queryProps.Merge
|
||||||
|
}
|
||||||
|
|
||||||
type lastQuery struct {
|
type lastQuery struct {
|
||||||
buffer []NodeNavigator
|
buffer []NodeNavigator
|
||||||
counted bool
|
counted bool
|
||||||
@ -923,6 +1216,147 @@ func (q *lastQuery) Clone() query {
|
|||||||
return &lastQuery{Input: q.Input.Clone()}
|
return &lastQuery{Input: q.Input.Clone()}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (q *lastQuery) ValueType() resultType {
|
||||||
|
return xpathResultType.Number
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *lastQuery) Properties() queryProp {
|
||||||
|
return queryProps.Merge
|
||||||
|
}
|
||||||
|
|
||||||
|
type descendantOverDescendantQuery struct {
|
||||||
|
name string
|
||||||
|
level int
|
||||||
|
posit int
|
||||||
|
currentNode NodeNavigator
|
||||||
|
|
||||||
|
Input query
|
||||||
|
MatchSelf bool
|
||||||
|
Predicate func(NodeNavigator) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *descendantOverDescendantQuery) moveToFirstChild() bool {
|
||||||
|
if d.currentNode.MoveToChild() {
|
||||||
|
d.level++
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *descendantOverDescendantQuery) moveUpUntilNext() bool {
|
||||||
|
for !d.currentNode.MoveToNext() {
|
||||||
|
d.level--
|
||||||
|
if d.level == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
d.currentNode.MoveToParent()
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *descendantOverDescendantQuery) Select(t iterator) NodeNavigator {
|
||||||
|
for {
|
||||||
|
if d.level == 0 {
|
||||||
|
node := d.Input.Select(t)
|
||||||
|
if node == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
d.currentNode = node.Copy()
|
||||||
|
d.posit = 0
|
||||||
|
if d.MatchSelf && d.Predicate(d.currentNode) {
|
||||||
|
d.posit = 1
|
||||||
|
return d.currentNode
|
||||||
|
}
|
||||||
|
d.moveToFirstChild()
|
||||||
|
} else if !d.moveUpUntilNext() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for ok := true; ok; ok = d.moveToFirstChild() {
|
||||||
|
if d.Predicate(d.currentNode) {
|
||||||
|
d.posit++
|
||||||
|
return d.currentNode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *descendantOverDescendantQuery) Evaluate(t iterator) interface{} {
|
||||||
|
d.Input.Evaluate(t)
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *descendantOverDescendantQuery) Clone() query {
|
||||||
|
return &descendantOverDescendantQuery{Input: d.Input.Clone(), Predicate: d.Predicate, MatchSelf: d.MatchSelf}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *descendantOverDescendantQuery) ValueType() resultType {
|
||||||
|
return xpathResultType.NodeSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *descendantOverDescendantQuery) Properties() queryProp {
|
||||||
|
return queryProps.Merge
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *descendantOverDescendantQuery) position() int {
|
||||||
|
return d.posit
|
||||||
|
}
|
||||||
|
|
||||||
|
type mergeQuery struct {
|
||||||
|
Input query
|
||||||
|
Child query
|
||||||
|
|
||||||
|
iterator func() NodeNavigator
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mergeQuery) Select(t iterator) NodeNavigator {
|
||||||
|
for {
|
||||||
|
if m.iterator == nil {
|
||||||
|
root := m.Input.Select(t)
|
||||||
|
if root == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
m.Child.Evaluate(t)
|
||||||
|
root = root.Copy()
|
||||||
|
t.Current().MoveTo(root)
|
||||||
|
var list []NodeNavigator
|
||||||
|
for node := m.Child.Select(t); node != nil; node = m.Child.Select(t) {
|
||||||
|
list = append(list, node.Copy())
|
||||||
|
}
|
||||||
|
i := 0
|
||||||
|
m.iterator = func() NodeNavigator {
|
||||||
|
if i >= len(list) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
result := list[i]
|
||||||
|
i++
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if node := m.iterator(); node != nil {
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
m.iterator = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mergeQuery) Evaluate(t iterator) interface{} {
|
||||||
|
m.Input.Evaluate(t)
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mergeQuery) Clone() query {
|
||||||
|
return &mergeQuery{Input: m.Input.Clone(), Child: m.Child.Clone()}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mergeQuery) ValueType() resultType {
|
||||||
|
return xpathResultType.NodeSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mergeQuery) Properties() queryProp {
|
||||||
|
return queryProps.Position | queryProps.Count | queryProps.Cached | queryProps.Merge
|
||||||
|
}
|
||||||
|
|
||||||
func getHashCode(n NodeNavigator) uint64 {
|
func getHashCode(n NodeNavigator) uint64 {
|
||||||
var sb bytes.Buffer
|
var sb bytes.Buffer
|
||||||
switch n.NodeType() {
|
switch n.NodeType() {
|
||||||
@ -958,7 +1392,7 @@ func getHashCode(n NodeNavigator) uint64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
h := fnv.New64a()
|
h := fnv.New64a()
|
||||||
h.Write([]byte(sb.String()))
|
h.Write(sb.Bytes())
|
||||||
return h.Sum64()
|
return h.Sum64()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -981,3 +1415,20 @@ func getNodeDepth(q query) int {
|
|||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getXPathType(i interface{}) resultType {
|
||||||
|
v := reflect.ValueOf(i)
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Float64:
|
||||||
|
return xpathResultType.Number
|
||||||
|
case reflect.String:
|
||||||
|
return xpathResultType.String
|
||||||
|
case reflect.Bool:
|
||||||
|
return xpathResultType.Boolean
|
||||||
|
default:
|
||||||
|
if _, ok := i.(query); ok {
|
||||||
|
return xpathResultType.NodeSet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic(fmt.Errorf("xpath unknown value type: %v", v.Kind()))
|
||||||
|
}
|
||||||
|
12
vendor/github.com/antchfx/xpath/xpath.go
generated
vendored
12
vendor/github.com/antchfx/xpath/xpath.go
generated
vendored
@ -84,13 +84,13 @@ func (t *NodeIterator) Current() NodeNavigator {
|
|||||||
// MoveNext moves Navigator to the next match node.
|
// MoveNext moves Navigator to the next match node.
|
||||||
func (t *NodeIterator) MoveNext() bool {
|
func (t *NodeIterator) MoveNext() bool {
|
||||||
n := t.query.Select(t)
|
n := t.query.Select(t)
|
||||||
if n != nil {
|
if n == nil {
|
||||||
if !t.node.MoveTo(n) {
|
return false
|
||||||
t.node = n.Copy()
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
return false
|
if !t.node.MoveTo(n) {
|
||||||
|
t.node = n.Copy()
|
||||||
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select selects a node set using the specified XPath expression.
|
// Select selects a node set using the specified XPath expression.
|
||||||
|
4
vendor/golang.org/x/net/LICENSE
generated
vendored
4
vendor/golang.org/x/net/LICENSE
generated
vendored
@ -1,4 +1,4 @@
|
|||||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
Copyright 2009 The Go Authors.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are
|
modification, are permitted provided that the following conditions are
|
||||||
@ -10,7 +10,7 @@ notice, this list of conditions and the following disclaimer.
|
|||||||
copyright notice, this list of conditions and the following disclaimer
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
in the documentation and/or other materials provided with the
|
in the documentation and/or other materials provided with the
|
||||||
distribution.
|
distribution.
|
||||||
* Neither the name of Google Inc. nor the names of its
|
* Neither the name of Google LLC nor the names of its
|
||||||
contributors may be used to endorse or promote products derived from
|
contributors may be used to endorse or promote products derived from
|
||||||
this software without specific prior written permission.
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
2
vendor/golang.org/x/net/html/doc.go
generated
vendored
2
vendor/golang.org/x/net/html/doc.go
generated
vendored
@ -104,7 +104,7 @@ tokenization, and tokenization and tree construction stages of the WHATWG HTML
|
|||||||
parsing specification respectively. While the tokenizer parses and normalizes
|
parsing specification respectively. While the tokenizer parses and normalizes
|
||||||
individual HTML tokens, only the parser constructs the DOM tree from the
|
individual HTML tokens, only the parser constructs the DOM tree from the
|
||||||
tokenized HTML, as described in the tree construction stage of the
|
tokenized HTML, as described in the tree construction stage of the
|
||||||
specification, dynamically modifying or extending the docuemnt's DOM tree.
|
specification, dynamically modifying or extending the document's DOM tree.
|
||||||
|
|
||||||
If your use case requires semantically well-formed HTML documents, as defined by
|
If your use case requires semantically well-formed HTML documents, as defined by
|
||||||
the WHATWG specification, the parser should be used rather than the tokenizer.
|
the WHATWG specification, the parser should be used rather than the tokenizer.
|
||||||
|
12
vendor/golang.org/x/net/html/token.go
generated
vendored
12
vendor/golang.org/x/net/html/token.go
generated
vendored
@ -910,9 +910,6 @@ func (z *Tokenizer) readTagAttrKey() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch c {
|
switch c {
|
||||||
case ' ', '\n', '\r', '\t', '\f', '/':
|
|
||||||
z.pendingAttr[0].end = z.raw.end - 1
|
|
||||||
return
|
|
||||||
case '=':
|
case '=':
|
||||||
if z.pendingAttr[0].start+1 == z.raw.end {
|
if z.pendingAttr[0].start+1 == z.raw.end {
|
||||||
// WHATWG 13.2.5.32, if we see an equals sign before the attribute name
|
// WHATWG 13.2.5.32, if we see an equals sign before the attribute name
|
||||||
@ -920,7 +917,9 @@ func (z *Tokenizer) readTagAttrKey() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fallthrough
|
fallthrough
|
||||||
case '>':
|
case ' ', '\n', '\r', '\t', '\f', '/', '>':
|
||||||
|
// WHATWG 13.2.5.33 Attribute name state
|
||||||
|
// We need to reconsume the char in the after attribute name state to support the / character
|
||||||
z.raw.end--
|
z.raw.end--
|
||||||
z.pendingAttr[0].end = z.raw.end
|
z.pendingAttr[0].end = z.raw.end
|
||||||
return
|
return
|
||||||
@ -939,6 +938,11 @@ func (z *Tokenizer) readTagAttrVal() {
|
|||||||
if z.err != nil {
|
if z.err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if c == '/' {
|
||||||
|
// WHATWG 13.2.5.34 After attribute name state
|
||||||
|
// U+002F SOLIDUS (/) - Switch to the self-closing start tag state.
|
||||||
|
return
|
||||||
|
}
|
||||||
if c != '=' {
|
if c != '=' {
|
||||||
z.raw.end--
|
z.raw.end--
|
||||||
return
|
return
|
||||||
|
4
vendor/golang.org/x/text/LICENSE
generated
vendored
4
vendor/golang.org/x/text/LICENSE
generated
vendored
@ -1,4 +1,4 @@
|
|||||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
Copyright 2009 The Go Authors.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are
|
modification, are permitted provided that the following conditions are
|
||||||
@ -10,7 +10,7 @@ notice, this list of conditions and the following disclaimer.
|
|||||||
copyright notice, this list of conditions and the following disclaimer
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
in the documentation and/or other materials provided with the
|
in the documentation and/or other materials provided with the
|
||||||
distribution.
|
distribution.
|
||||||
* Neither the name of Google Inc. nor the names of its
|
* Neither the name of Google LLC nor the names of its
|
||||||
contributors may be used to endorse or promote products derived from
|
contributors may be used to endorse or promote products derived from
|
||||||
this software without specific prior written permission.
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
8
vendor/modules.txt
vendored
8
vendor/modules.txt
vendored
@ -1,7 +1,7 @@
|
|||||||
# github.com/antchfx/xmlquery v1.3.18
|
# github.com/antchfx/xmlquery v1.4.1
|
||||||
## explicit; go 1.14
|
## explicit; go 1.14
|
||||||
github.com/antchfx/xmlquery
|
github.com/antchfx/xmlquery
|
||||||
# github.com/antchfx/xpath v1.2.5
|
# github.com/antchfx/xpath v1.3.1
|
||||||
## explicit; go 1.14
|
## explicit; go 1.14
|
||||||
github.com/antchfx/xpath
|
github.com/antchfx/xpath
|
||||||
# github.com/davecgh/go-spew v1.1.1
|
# github.com/davecgh/go-spew v1.1.1
|
||||||
@ -16,12 +16,12 @@ github.com/influxdata/influxdb1-client/pkg/escape
|
|||||||
github.com/influxdata/influxdb1-client/v2
|
github.com/influxdata/influxdb1-client/v2
|
||||||
# github.com/stretchr/testify v1.7.0
|
# github.com/stretchr/testify v1.7.0
|
||||||
## explicit; go 1.13
|
## explicit; go 1.13
|
||||||
# golang.org/x/net v0.20.0
|
# golang.org/x/net v0.28.0
|
||||||
## explicit; go 1.18
|
## explicit; go 1.18
|
||||||
golang.org/x/net/html
|
golang.org/x/net/html
|
||||||
golang.org/x/net/html/atom
|
golang.org/x/net/html/atom
|
||||||
golang.org/x/net/html/charset
|
golang.org/x/net/html/charset
|
||||||
# golang.org/x/text v0.14.0
|
# golang.org/x/text v0.17.0
|
||||||
## explicit; go 1.18
|
## explicit; go 1.18
|
||||||
golang.org/x/text/encoding
|
golang.org/x/text/encoding
|
||||||
golang.org/x/text/encoding/charmap
|
golang.org/x/text/encoding/charmap
|
||||||
|
Loading…
Reference in New Issue
Block a user