From 4b104db32689d84a0ea5d270517f01a3c0c76721 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Nov 2024 12:53:53 +0000 Subject: [PATCH] Go Dependency: Bump github.com/antchfx/xpath from 1.3.1 to 1.3.2 Bumps [github.com/antchfx/xpath](https://github.com/antchfx/xpath) from 1.3.1 to 1.3.2. - [Release notes](https://github.com/antchfx/xpath/releases) - [Commits](https://github.com/antchfx/xpath/compare/v1.3.1...v1.3.2) --- updated-dependencies: - dependency-name: github.com/antchfx/xpath dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 3 +- vendor/github.com/antchfx/xpath/build.go | 146 ++++-------- vendor/github.com/antchfx/xpath/func.go | 280 +++++++++++++---------- vendor/github.com/antchfx/xpath/parse.go | 100 +++++--- vendor/github.com/antchfx/xpath/query.go | 17 +- vendor/modules.txt | 2 +- 7 files changed, 284 insertions(+), 266 deletions(-) diff --git a/go.mod b/go.mod index e5941ae5..a1054e22 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( ) require ( - github.com/antchfx/xpath v1.3.1 // indirect + github.com/antchfx/xpath v1.3.2 // indirect github.com/fatih/color v1.18.0 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect diff --git a/go.sum b/go.sum index 87ad5e93..41d07e5c 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,8 @@ 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.3.1 h1:PNbFuUqHwWl0xRjvUPjJ95Agbmdj2uzzIwmQKgu4oCk= github.com/antchfx/xpath v1.3.1/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= +github.com/antchfx/xpath v1.3.2 h1:LNjzlsSjinu3bQpw9hWMY9ocB80oLOWuQqFvO6xt51U= +github.com/antchfx/xpath v1.3.2/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= github.com/apex/log v1.9.0 h1:FHtw/xuaM8AgmvDDTI9fiwoAL25Sq2cxojnZICUU8l0= github.com/apex/log v1.9.0/go.mod h1:m82fZlWIuiWzWP04XCTXmnX0xRkYYbCdYn8jbJeLBEA= github.com/apex/logs v1.0.0/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo= diff --git a/vendor/github.com/antchfx/xpath/build.go b/vendor/github.com/antchfx/xpath/build.go index 44f87d8d..a93c8eb5 100644 --- a/vendor/github.com/antchfx/xpath/build.go +++ b/vendor/github.com/antchfx/xpath/build.go @@ -45,28 +45,9 @@ type builder struct { // axisPredicate creates a predicate to predicating for this axis node. func axisPredicate(root *axisNode) func(NodeNavigator) bool { - // get current axix node type. - typ := ElementNode - switch root.AxeType { - case "attribute": - typ = AttributeNode - case "self", "parent": - typ = allNode - default: - switch root.Prop { - case "comment": - typ = CommentNode - case "text": - typ = TextNode - // case "processing-instruction": - // typ = ProcessingInstructionNode - case "node": - typ = allNode - } - } nametest := root.LocalName != "" || root.Prefix != "" predicate := func(n NodeNavigator) bool { - if typ == n.NodeType() || typ == allNode { + if root.typeTest == n.NodeType() || root.typeTest == allNode { if nametest { type namespaceURL interface { NamespaceURL() string @@ -102,39 +83,35 @@ func (b *builder) processAxis(root *axisNode, flags flag, props *builderProp) (q *props = builderProps.None } else { inputFlags := flagsEnum.None - if root.AxeType == "child" && (root.Input.Type() == nodeAxis) { - if input := root.Input.(*axisNode); input.AxeType == "descendant-or-self" { - var qyGrandInput query - if input.Input != nil { - qyGrandInput, _ = b.processNode(input.Input, flagsEnum.SmartDesc, props) - } else { - qyGrandInput = &contextQuery{} - } - // fix #20: https://github.com/antchfx/htmlquery/issues/20 - filter := func(n NodeNavigator) bool { - v := predicate(n) - switch root.Prop { - case "text": - v = v && n.NodeType() == TextNode - case "comment": - v = v && n.NodeType() == CommentNode + if (flags & flagsEnum.Filter) == 0 { + if root.AxisType == "child" && (root.Input.Type() == nodeAxis) { + if input := root.Input.(*axisNode); input.AxisType == "descendant-or-self" { + var qyGrandInput query + if input.Input != nil { + qyGrandInput, err = b.processNode(input.Input, flagsEnum.SmartDesc, props) + if err != nil { + return nil, err + } + } else { + qyGrandInput = &contextQuery{} } - return v + qyOutput = &descendantQuery{name: root.LocalName, Input: qyGrandInput, Predicate: predicate, Self: false} + *props |= builderProps.NonFlat + return qyOutput, nil } - qyOutput = &descendantQuery{name: root.LocalName, Input: qyGrandInput, Predicate: filter, Self: false} - *props |= builderProps.NonFlat - return qyOutput, nil } - } else if ((flags & flagsEnum.Filter) == 0) && (root.AxeType == "descendant" || root.AxeType == "descendant-or-self") { - inputFlags |= flagsEnum.SmartDesc + if root.AxisType == "descendant" || root.AxisType == "descendant-or-self" { + inputFlags |= flagsEnum.SmartDesc + } } + qyInput, err = b.processNode(root.Input, inputFlags, props) if err != nil { return nil, err } } - switch root.AxeType { + switch root.AxisType { case "ancestor": qyOutput = &ancestorQuery{name: root.LocalName, Input: qyInput, Predicate: predicate} *props |= builderProps.NonFlat @@ -144,22 +121,10 @@ func (b *builder) processAxis(root *axisNode, flags flag, props *builderProp) (q case "attribute": qyOutput = &attributeQuery{name: root.LocalName, Input: qyInput, Predicate: predicate} case "child": - filter := func(n NodeNavigator) bool { - v := predicate(n) - switch root.Prop { - case "text": - v = v && n.NodeType() == TextNode - case "node": - v = v && (n.NodeType() == ElementNode || n.NodeType() == TextNode) - case "comment": - v = v && n.NodeType() == CommentNode - } - return v - } if (*props & builderProps.NonFlat) == 0 { - qyOutput = &childQuery{name: root.LocalName, Input: qyInput, Predicate: filter} + qyOutput = &childQuery{name: root.LocalName, Input: qyInput, Predicate: predicate} } else { - qyOutput = &cachedChildQuery{name: root.LocalName, Input: qyInput, Predicate: filter} + qyOutput = &cachedChildQuery{name: root.LocalName, Input: qyInput, Predicate: predicate} } case "descendant": if (flags & flagsEnum.SmartDesc) != flagsEnum.None { @@ -192,7 +157,7 @@ func (b *builder) processAxis(root *axisNode, flags flag, props *builderProp) (q case "namespace": // haha,what will you do someting?? default: - err = fmt.Errorf("unknown axe type: %s", root.AxeType) + err = fmt.Errorf("unknown axe type: %s", root.AxisType) return nil, err } return qyOutput, nil @@ -235,7 +200,6 @@ func (b *builder) processFilter(root *filterNode, flags flag, props *builderProp *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 @@ -243,16 +207,15 @@ func (b *builder) processFilter(root *filterNode, flags flag, props *builderProp if qyFunc, ok := cond.(*functionQuery); ok { switch qyFunc.Input.(type) { case *filterQuery: - cond = &lastQuery{Input: qyFunc.Input} + cond = &lastFuncQuery{Input: qyFunc.Input} } } } } + merge := (qyInput.Properties() & queryProps.Merge) != 0 if first && firstInput != nil { if merge && ((*props & builderProps.PosFilter) != 0) { - qyInput = &filterQuery{Input: qyInput, Predicate: cond, NoPosition: false} - var ( rootQuery = &contextQuery{} parent query @@ -315,10 +278,11 @@ func (b *builder) processFilter(root *filterNode, flags flag, props *builderProp } } b.firstInput = nil + child := &filterQuery{Input: qyInput, Predicate: cond, NoPosition: false} if parent != nil { - return &mergeQuery{Input: parent, Child: qyInput}, nil + return &mergeQuery{Input: parent, Child: child}, nil } - return qyInput, nil + return child, nil } b.firstInput = nil } @@ -343,7 +307,7 @@ func (b *builder) processFunction(root *functionNode, props *builderProp) (query if err != nil { return nil, err } - qyOutput = &functionQuery{Input: arg, Func: lowerCaseFunc} + qyOutput = &functionQuery{Func: lowerCaseFunc(arg)} case "starts-with": arg1, err := b.processNode(root.Args[0], flagsEnum.None, props) if err != nil { @@ -446,14 +410,17 @@ func (b *builder) processFunction(root *functionNode, props *builderProp) (query } qyOutput = &functionQuery{Func: stringLengthFunc(arg1)} case "normalize-space": - if len(root.Args) == 0 { - return nil, errors.New("xpath: normalize-space function must have at least one parameter") + var arg node + if len(root.Args) > 0 { + arg = root.Args[0] + } else { + arg = newAxisNode("self", allNode, "", "", "", nil) } - argQuery, err := b.processNode(root.Args[0], flagsEnum.None, props) + arg1, err := b.processNode(arg, flagsEnum.None, props) if err != nil { return nil, err } - qyOutput = &functionQuery{Input: argQuery, Func: normalizespaceFunc} + qyOutput = &functionQuery{Func: normalizespaceFunc(arg1)} case "replace": //replace( string , string, string ) if len(root.Args) != 3 { @@ -500,7 +467,7 @@ func (b *builder) processFunction(root *functionNode, props *builderProp) (query if err != nil { return nil, err } - qyOutput = &functionQuery{Input: argQuery, Func: notFunc} + qyOutput = &functionQuery{Func: notFunc(argQuery)} case "name", "local-name", "namespace-uri": if len(root.Args) > 1 { return nil, fmt.Errorf("xpath: %s function must have at most one parameter", root.FuncName) @@ -531,17 +498,10 @@ func (b *builder) processFunction(root *functionNode, props *builderProp) (query }, } case "last": - //switch typ := b.firstInput.(type) { - //case *groupQuery, *filterQuery: - // https://github.com/antchfx/xpath/issues/76 - // https://github.com/antchfx/xpath/issues/78 - //qyOutput = &lastQuery{Input: typ} - //default: - qyOutput = &functionQuery{Func: lastFunc} - //} + qyOutput = &functionQuery{Input: b.firstInput, Func: lastFunc()} *props |= builderProps.HasLast case "position": - qyOutput = &functionQuery{Func: positionFunc} + qyOutput = &functionQuery{Input: b.firstInput, Func: positionFunc()} *props |= builderProps.HasPosition case "boolean", "number", "string": var inp query @@ -555,16 +515,14 @@ func (b *builder) processFunction(root *functionNode, props *builderProp) (query } inp = argQuery } - f := &functionQuery{Input: inp} switch root.FuncName { case "boolean": - f.Func = booleanFunc + qyOutput = &functionQuery{Func: booleanFunc(inp)} case "string": - f.Func = stringFunc + qyOutput = &functionQuery{Func: stringFunc(inp)} case "number": - f.Func = numberFunc + qyOutput = &functionQuery{Func: numberFunc(inp)} } - qyOutput = f case "count": if len(root.Args) == 0 { return nil, fmt.Errorf("xpath: count(node-sets) function must with have parameters node-sets") @@ -573,7 +531,7 @@ func (b *builder) processFunction(root *functionNode, props *builderProp) (query if err != nil { return nil, err } - qyOutput = &functionQuery{Input: argQuery, Func: countFunc} + qyOutput = &functionQuery{Func: countFunc(argQuery)} case "sum": if len(root.Args) == 0 { return nil, fmt.Errorf("xpath: sum(node-sets) function must with have parameters node-sets") @@ -582,7 +540,7 @@ func (b *builder) processFunction(root *functionNode, props *builderProp) (query if err != nil { return nil, err } - qyOutput = &functionQuery{Input: argQuery, Func: sumFunc} + qyOutput = &functionQuery{Func: sumFunc(argQuery)} case "ceiling", "floor", "round": if len(root.Args) == 0 { return nil, fmt.Errorf("xpath: ceiling(node-sets) function must with have parameters node-sets") @@ -591,16 +549,14 @@ func (b *builder) processFunction(root *functionNode, props *builderProp) (query if err != nil { return nil, err } - f := &functionQuery{Input: argQuery} switch root.FuncName { case "ceiling": - f.Func = ceilingFunc + qyOutput = &functionQuery{Func: ceilingFunc(argQuery)} case "floor": - f.Func = floorFunc + qyOutput = &functionQuery{Func: floorFunc(argQuery)} case "round": - f.Func = roundFunc + qyOutput = &functionQuery{Func: roundFunc(argQuery)} } - qyOutput = f case "concat": if len(root.Args) < 2 { return nil, fmt.Errorf("xpath: concat() must have at least two arguments") @@ -627,7 +583,7 @@ func (b *builder) processFunction(root *functionNode, props *builderProp) (query if len(root.Args) != 2 { return nil, fmt.Errorf("xpath: string-join(node-sets, separator) function requires node-set and argument") } - argQuery, err := b.processNode(root.Args[0], flagsEnum.None, props) + input, err := b.processNode(root.Args[0], flagsEnum.None, props) if err != nil { return nil, err } @@ -635,14 +591,10 @@ func (b *builder) processFunction(root *functionNode, props *builderProp) (query if err != nil { return nil, err } - qyOutput = &functionQuery{Input: argQuery, Func: stringJoinFunc(arg1)} + qyOutput = &functionQuery{Func: stringJoinFunc(input, arg1)} default: 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 } diff --git a/vendor/github.com/antchfx/xpath/func.go b/vendor/github.com/antchfx/xpath/func.go index a5e88ba8..4079a194 100644 --- a/vendor/github.com/antchfx/xpath/func.go +++ b/vendor/github.com/antchfx/xpath/func.go @@ -37,75 +37,83 @@ func predicate(q query) func(NodeNavigator) bool { } // positionFunc is a XPath Node Set functions position(). -func positionFunc(q query, t iterator) interface{} { - var ( - count = 1 - node = t.Current().Copy() - ) - test := predicate(q) - for node.MoveToPrevious() { - if test(node) { - count++ +func positionFunc() func(query, iterator) interface{} { + return func(q query, t iterator) interface{} { + var ( + count = 1 + node = t.Current().Copy() + ) + test := predicate(q) + for node.MoveToPrevious() { + if test(node) { + count++ + } } + return float64(count) } - return float64(count) } // lastFunc is a XPath Node Set functions last(). -func lastFunc(q query, t iterator) interface{} { - var ( - count = 0 - node = t.Current().Copy() - ) - node.MoveToFirst() - test := predicate(q) - for { - if test(node) { - count++ - } - if !node.MoveToNext() { - break +func lastFunc() func(query, iterator) interface{} { + return func(q query, t iterator) interface{} { + var ( + count = 0 + node = t.Current().Copy() + ) + test := predicate(q) + node.MoveToFirst() + for { + if test(node) { + count++ + } + if !node.MoveToNext() { + break + } } + return float64(count) } - return float64(count) } // countFunc is a XPath Node Set functions count(node-set). -func countFunc(q query, t iterator) interface{} { - var count = 0 - q = functionArgs(q) - test := predicate(q) - switch typ := q.Evaluate(t).(type) { - case query: - for node := typ.Select(t); node != nil; node = typ.Select(t) { - if test(node) { - count++ +func countFunc(arg query) func(query, iterator) interface{} { + return func(_ query, t iterator) interface{} { + var count = 0 + q := functionArgs(arg) + test := predicate(q) + switch typ := q.Evaluate(t).(type) { + case query: + for node := typ.Select(t); node != nil; node = typ.Select(t) { + if test(node) { + count++ + } } } + return float64(count) } - return float64(count) } // sumFunc is a XPath Node Set functions sum(node-set). -func sumFunc(q query, t iterator) interface{} { - var sum float64 - switch typ := functionArgs(q).Evaluate(t).(type) { - case query: - for node := typ.Select(t); node != nil; node = typ.Select(t) { - if v, err := strconv.ParseFloat(node.Value(), 64); err == nil { - sum += v +func sumFunc(arg query) func(query, iterator) interface{} { + return func(_ query, t iterator) interface{} { + var sum float64 + switch typ := functionArgs(arg).Evaluate(t).(type) { + case query: + for node := typ.Select(t); node != nil; node = typ.Select(t) { + if v, err := strconv.ParseFloat(node.Value(), 64); err == nil { + sum += v + } } + case float64: + sum = typ + case string: + v, err := strconv.ParseFloat(typ, 64) + if err != nil { + panic(errors.New("sum() function argument type must be a node-set or number")) + } + sum = v } - case float64: - sum = typ - case string: - v, err := strconv.ParseFloat(typ, 64) - if err != nil { - panic(errors.New("sum() function argument type must be a node-set or number")) - } - sum = v + return sum } - return sum } func asNumber(t iterator, o interface{}) float64 { @@ -130,30 +138,36 @@ func asNumber(t iterator, o interface{}) float64 { } // ceilingFunc is a XPath Node Set functions ceiling(node-set). -func ceilingFunc(q query, t iterator) interface{} { - val := asNumber(t, functionArgs(q).Evaluate(t)) - // if math.IsNaN(val) { - // panic(errors.New("ceiling() function argument type must be a valid number")) - // } - return math.Ceil(val) +func ceilingFunc(arg query) func(query, iterator) interface{} { + return func(_ query, t iterator) interface{} { + val := asNumber(t, functionArgs(arg).Evaluate(t)) + // if math.IsNaN(val) { + // panic(errors.New("ceiling() function argument type must be a valid number")) + // } + return math.Ceil(val) + } } // floorFunc is a XPath Node Set functions floor(node-set). -func floorFunc(q query, t iterator) interface{} { - val := asNumber(t, functionArgs(q).Evaluate(t)) - return math.Floor(val) +func floorFunc(arg query) func(query, iterator) interface{} { + return func(_ query, t iterator) interface{} { + val := asNumber(t, functionArgs(arg).Evaluate(t)) + return math.Floor(val) + } } // roundFunc is a XPath Node Set functions round(node-set). -func roundFunc(q query, t iterator) interface{} { - val := asNumber(t, functionArgs(q).Evaluate(t)) - //return math.Round(val) - return round(val) +func roundFunc(arg query) func(query, iterator) interface{} { + return func(_ query, t iterator) interface{} { + val := asNumber(t, functionArgs(arg).Evaluate(t)) + //return math.Round(val) + return round(val) + } } // nameFunc is a XPath functions name([node-set]). func nameFunc(arg query) func(query, iterator) interface{} { - return func(q query, t iterator) interface{} { + return func(_ query, t iterator) interface{} { var v NodeNavigator if arg == nil { v = t.Current() @@ -173,7 +187,7 @@ func nameFunc(arg query) func(query, iterator) interface{} { // localNameFunc is a XPath functions local-name([node-set]). func localNameFunc(arg query) func(query, iterator) interface{} { - return func(q query, t iterator) interface{} { + return func(_ query, t iterator) interface{} { var v NodeNavigator if arg == nil { v = t.Current() @@ -189,7 +203,7 @@ func localNameFunc(arg query) func(query, iterator) interface{} { // namespaceFunc is a XPath functions namespace-uri([node-set]). func namespaceFunc(arg query) func(query, iterator) interface{} { - return func(q query, t iterator) interface{} { + return func(_ query, t iterator) interface{} { var v NodeNavigator if arg == nil { v = t.Current() @@ -256,26 +270,32 @@ func asString(t iterator, v interface{}) string { } // booleanFunc is a XPath functions boolean([node-set]). -func booleanFunc(q query, t iterator) interface{} { - v := functionArgs(q).Evaluate(t) - return asBool(t, v) +func booleanFunc(arg1 query) func(query, iterator) interface{} { + return func(_ query, t iterator) interface{} { + v := functionArgs(arg1).Evaluate(t) + return asBool(t, v) + } } // numberFunc is a XPath functions number([node-set]). -func numberFunc(q query, t iterator) interface{} { - v := functionArgs(q).Evaluate(t) - return asNumber(t, v) +func numberFunc(arg1 query) func(query, iterator) interface{} { + return func(_ query, t iterator) interface{} { + v := functionArgs(arg1).Evaluate(t) + return asNumber(t, v) + } } // stringFunc is a XPath functions string([node-set]). -func stringFunc(q query, t iterator) interface{} { - v := functionArgs(q).Evaluate(t) - return asString(t, v) +func stringFunc(arg1 query) func(query, iterator) interface{} { + return func(_ query, t iterator) interface{} { + v := functionArgs(arg1).Evaluate(t) + return asString(t, v) + } } // startwithFunc is a XPath functions starts-with(string, string). func startwithFunc(arg1, arg2 query) func(query, iterator) interface{} { - return func(q query, t iterator) interface{} { + return func(_ query, t iterator) interface{} { var ( m, n string ok bool @@ -302,7 +322,7 @@ func startwithFunc(arg1, arg2 query) func(query, iterator) interface{} { // endwithFunc is a XPath functions ends-with(string, string). func endwithFunc(arg1, arg2 query) func(query, iterator) interface{} { - return func(q query, t iterator) interface{} { + return func(_ query, t iterator) interface{} { var ( m, n string ok bool @@ -329,7 +349,7 @@ func endwithFunc(arg1, arg2 query) func(query, iterator) interface{} { // containsFunc is a XPath functions contains(string or @attr, string). func containsFunc(arg1, arg2 query) func(query, iterator) interface{} { - return func(q query, t iterator) interface{} { + return func(_ query, t iterator) interface{} { var ( m, n string ok bool @@ -360,7 +380,7 @@ func containsFunc(arg1, arg2 query) func(query, iterator) interface{} { // Note: does not support https://www.w3.org/TR/xpath-functions-31/#func-matches 3rd optional `flags` argument; if // needed, directly put flags in the regexp pattern, such as `(?i)^pattern$` for `i` flag. func matchesFunc(arg1, arg2 query) func(query, iterator) interface{} { - return func(q query, t iterator) interface{} { + return func(_ query, t iterator) interface{} { var s string switch typ := functionArgs(arg1).Evaluate(t).(type) { case string: @@ -386,43 +406,45 @@ func matchesFunc(arg1, arg2 query) func(query, iterator) interface{} { } // normalizespaceFunc is XPath functions normalize-space(string?) -func normalizespaceFunc(q query, t iterator) interface{} { - var m string - switch typ := functionArgs(q).Evaluate(t).(type) { - case string: - m = typ - case query: - node := typ.Select(t) - if node == nil { - return "" +func normalizespaceFunc(arg1 query) func(query, iterator) interface{} { + return func(_ query, t iterator) interface{} { + var m string + switch typ := functionArgs(arg1).Evaluate(t).(type) { + case string: + m = typ + case query: + node := typ.Select(t) + if node == nil { + return "" + } + m = node.Value() } - m = node.Value() - } - var b = builderPool.Get().(stringBuilder) - b.Grow(len(m)) - - runeStr := []rune(strings.TrimSpace(m)) - l := len(runeStr) - for i := range runeStr { - r := runeStr[i] - isSpace := unicode.IsSpace(r) - if !(isSpace && (i+1 < l && unicode.IsSpace(runeStr[i+1]))) { - if isSpace { - r = ' ' + var b = builderPool.Get().(stringBuilder) + b.Grow(len(m)) + + runeStr := []rune(strings.TrimSpace(m)) + l := len(runeStr) + for i := range runeStr { + r := runeStr[i] + isSpace := unicode.IsSpace(r) + if !(isSpace && (i+1 < l && unicode.IsSpace(runeStr[i+1]))) { + if isSpace { + r = ' ' + } + b.WriteRune(r) } - b.WriteRune(r) } - } - result := b.String() - b.Reset() - builderPool.Put(b) + result := b.String() + b.Reset() + builderPool.Put(b) - return result + return result + } } // substringFunc is XPath functions substring function returns a part of a given string. func substringFunc(arg1, arg2, arg3 query) func(query, iterator) interface{} { - return func(q query, t iterator) interface{} { + return func(_ query, t iterator) interface{} { var m string switch typ := functionArgs(arg1).Evaluate(t).(type) { case string: @@ -461,7 +483,7 @@ func substringFunc(arg1, arg2, arg3 query) func(query, iterator) interface{} { // substringIndFunc is XPath functions substring-before/substring-after function returns a part of a given string. func substringIndFunc(arg1, arg2 query, after bool) func(query, iterator) interface{} { - return func(q query, t iterator) interface{} { + return func(_ query, t iterator) interface{} { var str string switch v := functionArgs(arg1).Evaluate(t).(type) { case string: @@ -502,7 +524,7 @@ func substringIndFunc(arg1, arg2 query, after bool) func(query, iterator) interf // stringLengthFunc is XPATH string-length( [string] ) function that returns a number // equal to the number of characters in a given string. func stringLengthFunc(arg1 query) func(query, iterator) interface{} { - return func(q query, t iterator) interface{} { + return func(_ query, t iterator) interface{} { switch v := functionArgs(arg1).Evaluate(t).(type) { case string: return float64(len(v)) @@ -519,7 +541,7 @@ func stringLengthFunc(arg1 query) func(query, iterator) interface{} { // translateFunc is XPath functions translate() function returns a replaced string. func translateFunc(arg1, arg2, arg3 query) func(query, iterator) interface{} { - return func(q query, t iterator) interface{} { + return func(_ query, t iterator) interface{} { str := asString(t, functionArgs(arg1).Evaluate(t)) src := asString(t, functionArgs(arg2).Evaluate(t)) dst := asString(t, functionArgs(arg3).Evaluate(t)) @@ -538,7 +560,7 @@ func translateFunc(arg1, arg2, arg3 query) func(query, iterator) interface{} { // replaceFunc is XPath functions replace() function returns a replaced string. func replaceFunc(arg1, arg2, arg3 query) func(query, iterator) interface{} { - return func(q query, t iterator) interface{} { + return func(_ query, t iterator) interface{} { str := asString(t, functionArgs(arg1).Evaluate(t)) src := asString(t, functionArgs(arg2).Evaluate(t)) dst := asString(t, functionArgs(arg3).Evaluate(t)) @@ -548,15 +570,17 @@ func replaceFunc(arg1, arg2, arg3 query) func(query, iterator) interface{} { } // notFunc is XPATH functions not(expression) function operation. -func notFunc(q query, t iterator) interface{} { - switch v := functionArgs(q).Evaluate(t).(type) { - case bool: - return !v - case query: - node := v.Select(t) - return node == nil - default: - return false +func notFunc(arg1 query) func(query, iterator) interface{} { + return func(_ query, t iterator) interface{} { + switch v := functionArgs(arg1).Evaluate(t).(type) { + case bool: + return !v + case query: + node := v.Select(t) + return node == nil + default: + return false + } } } @@ -564,7 +588,7 @@ func notFunc(q query, t iterator) interface{} { // strings and returns the resulting string. // concat( string1 , string2 [, stringn]* ) func concatFunc(args ...query) func(query, iterator) interface{} { - return func(q query, t iterator) interface{} { + return func(_ query, t iterator) interface{} { b := builderPool.Get().(stringBuilder) for _, v := range args { v = functionArgs(v) @@ -616,8 +640,8 @@ func reverseFunc(q query, t iterator) func() NodeNavigator { } // string-join is a XPath Node Set functions string-join(node-set, separator). -func stringJoinFunc(arg1 query) func(query, iterator) interface{} { - return func(q query, t iterator) interface{} { +func stringJoinFunc(q, arg1 query) func(query, iterator) interface{} { + return func(_ query, t iterator) interface{} { var separator string switch v := functionArgs(arg1).Evaluate(t).(type) { case string: @@ -647,7 +671,9 @@ func stringJoinFunc(arg1 query) func(query, iterator) interface{} { } // 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)) +func lowerCaseFunc(arg1 query) func(query, iterator) interface{} { + return func(_ query, t iterator) interface{} { + v := functionArgs(arg1).Evaluate(t) + return strings.ToLower(asString(t, v)) + } } diff --git a/vendor/github.com/antchfx/xpath/parse.go b/vendor/github.com/antchfx/xpath/parse.go index cbd289ac..5b44cd82 100644 --- a/vendor/github.com/antchfx/xpath/parse.go +++ b/vendor/github.com/antchfx/xpath/parse.go @@ -6,6 +6,7 @@ import ( "fmt" "strconv" "unicode" + "unicode/utf8" ) // A XPath expression token type. @@ -85,12 +86,13 @@ func newOperandNode(v interface{}) node { } // newAxisNode returns new axis node AxisNode. -func newAxisNode(axeTyp, localName, prefix, prop string, n node, opts ...func(p *axisNode)) node { +func newAxisNode(axisType string, typeTest NodeType, localName, prefix, prop string, n node, opts ...func(p *axisNode)) node { a := axisNode{ nodeType: nodeAxis, + typeTest: typeTest, LocalName: localName, Prefix: prefix, - AxeType: axeTyp, + AxisType: axisType, Prop: prop, Input: n, } @@ -228,8 +230,9 @@ Loop: } // RelationalExpr ::= AdditiveExpr | RelationalExpr '<' AdditiveExpr | RelationalExpr '>' AdditiveExpr -// | RelationalExpr '<=' AdditiveExpr -// | RelationalExpr '>=' AdditiveExpr +// +// | RelationalExpr '<=' AdditiveExpr +// | RelationalExpr '>=' AdditiveExpr func (p *parser) parseRelationalExpr(n node) node { opnd := p.parseAdditiveExpr(n) Loop: @@ -274,7 +277,8 @@ Loop: } // MultiplicativeExpr ::= UnaryExpr | MultiplicativeExpr MultiplyOperator(*) UnaryExpr -// | MultiplicativeExpr 'div' UnaryExpr | MultiplicativeExpr 'mod' UnaryExpr +// +// | MultiplicativeExpr 'div' UnaryExpr | MultiplicativeExpr 'mod' UnaryExpr func (p *parser) parseMultiplicativeExpr(n node) node { opnd := p.parseUnaryExpr(n) Loop: @@ -308,7 +312,7 @@ func (p *parser) parseUnaryExpr(n node) node { return opnd } -// UnionExpr ::= PathExpr | UnionExpr '|' PathExpr +// UnionExpr ::= PathExpr | UnionExpr '|' PathExpr func (p *parser) parseUnionExpr(n node) node { opnd := p.parsePathExpr(n) Loop: @@ -335,7 +339,7 @@ func (p *parser) parsePathExpr(n node) node { opnd = p.parseRelativeLocationPath(opnd) case itemSlashSlash: p.next() - opnd = p.parseRelativeLocationPath(newAxisNode("descendant-or-self", "", "", "", opnd)) + opnd = p.parseRelativeLocationPath(newAxisNode("descendant-or-self", allNode, "", "", "", opnd)) } } else { opnd = p.parseLocationPath(nil) @@ -352,7 +356,7 @@ func (p *parser) parseFilterExpr(n node) node { return opnd } -// Predicate ::= '[' PredicateExpr ']' +// Predicate ::= '[' PredicateExpr ']' func (p *parser) parsePredicate(n node) node { p.skipItem(itemLBracket) opnd := p.parseExpression(n) @@ -372,7 +376,7 @@ func (p *parser) parseLocationPath(n node) (opnd node) { case itemSlashSlash: p.next() opnd = newRootNode("//") - opnd = p.parseRelativeLocationPath(newAxisNode("descendant-or-self", "", "", "", opnd)) + opnd = p.parseRelativeLocationPath(newAxisNode("descendant-or-self", allNode, "", "", "", opnd)) default: opnd = p.parseRelativeLocationPath(n) } @@ -388,7 +392,7 @@ Loop: switch p.r.typ { case itemSlashSlash: p.next() - opnd = newAxisNode("descendant-or-self", "", "", "", opnd) + opnd = newAxisNode("descendant-or-self", allNode, "", "", "", opnd) case itemSlash: p.next() default: @@ -400,30 +404,33 @@ Loop: // Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep func (p *parser) parseStep(n node) (opnd node) { - axeTyp := "child" // default axes value. if p.r.typ == itemDot || p.r.typ == itemDotDot { if p.r.typ == itemDot { - axeTyp = "self" + opnd = newAxisNode("self", allNode, "", "", "", n) } else { - axeTyp = "parent" + opnd = newAxisNode("parent", allNode, "", "", "", n) } p.next() - opnd = newAxisNode(axeTyp, "", "", "", n) if p.r.typ != itemLBracket { return opnd } } else { + axisType := "child" // default axes value. switch p.r.typ { case itemAt: + axisType = "attribute" p.next() - axeTyp = "attribute" case itemAxe: - axeTyp = p.r.name + axisType = p.r.name p.next() case itemLParens: return p.parseSequence(n) } - opnd = p.parseNodeTest(n, axeTyp) + matchType := ElementNode + if axisType == "attribute" { + matchType = AttributeNode + } + opnd = p.parseNodeTest(n, axisType, matchType) } for p.r.typ == itemLBracket { opnd = newFilterNode(opnd, p.parsePredicate(opnd)) @@ -447,8 +454,8 @@ func (p *parser) parseSequence(n node) (opnd node) { return opnd } -// NodeTest ::= NameTest | nodeType '(' ')' | 'processing-instruction' '(' Literal ')' -func (p *parser) parseNodeTest(n node, axeTyp string) (opnd node) { +// NodeTest ::= NameTest | nodeType '(' ')' | 'processing-instruction' '(' Literal ')' +func (p *parser) parseNodeTest(n node, axeTyp string, matchType NodeType) (opnd node) { switch p.r.typ { case itemName: if p.r.canBeFunc && isNodeType(p.r) { @@ -466,7 +473,19 @@ func (p *parser) parseNodeTest(n node, axeTyp string) (opnd node) { p.next() } p.skipItem(itemRParens) - opnd = newAxisNode(axeTyp, name, "", prop, n) + switch prop { + case "comment": + matchType = CommentNode + case "text": + matchType = TextNode + case "processing-instruction": + case "node": + matchType = allNode + default: + matchType = RootNode + } + + opnd = newAxisNode(axeTyp, matchType, name, "", prop, n) } else { prefix := p.r.prefix name := p.r.name @@ -474,7 +493,7 @@ func (p *parser) parseNodeTest(n node, axeTyp string) (opnd node) { if p.r.name == "*" { name = "" } - opnd = newAxisNode(axeTyp, name, prefix, "", n, func(a *axisNode) { + opnd = newAxisNode(axeTyp, matchType, name, prefix, "", n, func(a *axisNode) { if prefix != "" && p.namespaces != nil { if ns, ok := p.namespaces[prefix]; ok { a.hasNamespaceURI = true @@ -486,7 +505,7 @@ func (p *parser) parseNodeTest(n node, axeTyp string) (opnd node) { }) } case itemStar: - opnd = newAxisNode(axeTyp, "", "", "", n) + opnd = newAxisNode(axeTyp, matchType, "", "", "", n) p.next() default: panic("expression must evaluate to a node-set") @@ -579,17 +598,18 @@ type axisNode struct { nodeType Input node Prop string // node-test name.[comment|text|processing-instruction|node] - AxeType string // name of the axes.[attribute|ancestor|child|....] + AxisType string // name of the axis.[attribute|ancestor|child|....] LocalName string // local part name of node. Prefix string // prefix name of node. namespaceURI string // namespace URI of node hasNamespaceURI bool // if namespace URI is set (can be "") + typeTest NodeType } func (a *axisNode) String() string { var b bytes.Buffer - if a.AxeType != "" { - b.Write([]byte(a.AxeType + "::")) + if a.AxisType != "" { + b.Write([]byte(a.AxisType + "::")) } if a.Prefix != "" { b.Write([]byte(a.Prefix + ":")) @@ -672,6 +692,7 @@ type scanner struct { pos int curr rune + currSize int typ itemType strval string // text value at current pos numval float64 // number value at current pos @@ -681,10 +702,18 @@ type scanner struct { func (s *scanner) nextChar() bool { if s.pos >= len(s.text) { s.curr = rune(0) + s.currSize = 1 return false } - s.curr = rune(s.text[s.pos]) - s.pos++ + + r, size := rune(s.text[s.pos]), 1 + if r >= 0x80 { // handle multi-byte runes + r, size = utf8.DecodeRuneInString(s.text[s.pos:]) + } + + s.curr = r + s.currSize = size + s.pos += size return true } @@ -843,12 +872,15 @@ func (s *scanner) scanString() string { end = s.curr ) s.nextChar() - i := s.pos - 1 + i := s.pos - s.currSize + if s.currSize > 1 { + c++ + } for s.curr != end { if !s.nextChar() { panic(errors.New("xpath: scanString got unclosed string")) } - c++ + c += s.currSize } s.nextChar() return s.text[i : i+c] @@ -856,14 +888,18 @@ func (s *scanner) scanString() string { func (s *scanner) scanName() string { var ( - c int - i = s.pos - 1 + c = s.currSize - 1 + i = s.pos - s.currSize ) + + // Detect current rune size + for isName(s.curr) { - c++ if !s.nextChar() { + c += s.currSize break } + c += s.currSize } return s.text[i : i+c] } diff --git a/vendor/github.com/antchfx/xpath/query.go b/vendor/github.com/antchfx/xpath/query.go index a4d1dceb..75c43361 100644 --- a/vendor/github.com/antchfx/xpath/query.go +++ b/vendor/github.com/antchfx/xpath/query.go @@ -850,6 +850,9 @@ func (f *functionQuery) Evaluate(t iterator) interface{} { } func (f *functionQuery) Clone() query { + if f.Input == nil { + return &functionQuery{Func: f.Func} + } return &functionQuery{Input: f.Input.Clone(), Func: f.Func} } @@ -1187,18 +1190,18 @@ func (u *unionQuery) Properties() queryProp { return queryProps.Merge } -type lastQuery struct { +type lastFuncQuery struct { buffer []NodeNavigator counted bool Input query } -func (q *lastQuery) Select(t iterator) NodeNavigator { +func (q *lastFuncQuery) Select(t iterator) NodeNavigator { return nil } -func (q *lastQuery) Evaluate(t iterator) interface{} { +func (q *lastFuncQuery) Evaluate(t iterator) interface{} { if !q.counted { for { node := q.Input.Select(t) @@ -1212,15 +1215,15 @@ func (q *lastQuery) Evaluate(t iterator) interface{} { return float64(len(q.buffer)) } -func (q *lastQuery) Clone() query { - return &lastQuery{Input: q.Input.Clone()} +func (q *lastFuncQuery) Clone() query { + return &lastFuncQuery{Input: q.Input.Clone()} } -func (q *lastQuery) ValueType() resultType { +func (q *lastFuncQuery) ValueType() resultType { return xpathResultType.Number } -func (q *lastQuery) Properties() queryProp { +func (q *lastFuncQuery) Properties() queryProp { return queryProps.Merge } diff --git a/vendor/modules.txt b/vendor/modules.txt index 8ed84028..9a55f1c4 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,7 +1,7 @@ # github.com/antchfx/xmlquery v1.4.1 ## explicit; go 1.14 github.com/antchfx/xmlquery -# github.com/antchfx/xpath v1.3.1 +# github.com/antchfx/xpath v1.3.2 ## explicit; go 1.14 github.com/antchfx/xpath # github.com/apex/log v1.9.0