Skip to content

Commit b94a535

Browse files
committed
fix #104
1 parent 47df8f8 commit b94a535

7 files changed

+254
-259
lines changed

build.go

+45-102
Original file line numberDiff line numberDiff line change
@@ -45,28 +45,9 @@ type builder struct {
4545

4646
// axisPredicate creates a predicate to predicating for this axis node.
4747
func axisPredicate(root *axisNode) func(NodeNavigator) bool {
48-
// get current axix node type.
49-
typ := ElementNode
50-
switch root.AxeType {
51-
case "attribute":
52-
typ = AttributeNode
53-
case "self", "parent":
54-
typ = allNode
55-
default:
56-
switch root.Prop {
57-
case "comment":
58-
typ = CommentNode
59-
case "text":
60-
typ = TextNode
61-
// case "processing-instruction":
62-
// typ = ProcessingInstructionNode
63-
case "node":
64-
typ = allNode
65-
}
66-
}
6748
nametest := root.LocalName != "" || root.Prefix != ""
6849
predicate := func(n NodeNavigator) bool {
69-
if typ == n.NodeType() || typ == allNode {
50+
if root.typeTest == n.NodeType() || root.typeTest == allNode {
7051
if nametest {
7152
type namespaceURL interface {
7253
NamespaceURL() string
@@ -102,42 +83,35 @@ func (b *builder) processAxis(root *axisNode, flags flag, props *builderProp) (q
10283
*props = builderProps.None
10384
} else {
10485
inputFlags := flagsEnum.None
105-
if root.AxeType == "child" && (root.Input.Type() == nodeAxis) {
106-
if input := root.Input.(*axisNode); input.AxeType == "descendant-or-self" {
107-
var qyGrandInput query
108-
if input.Input != nil {
109-
qyGrandInput, err = b.processNode(input.Input, flagsEnum.SmartDesc, props)
110-
if err != nil {
111-
return nil, err
86+
if (flags & flagsEnum.Filter) == 0 {
87+
if root.AxisType == "child" && (root.Input.Type() == nodeAxis) {
88+
if input := root.Input.(*axisNode); input.AxisType == "descendant-or-self" {
89+
var qyGrandInput query
90+
if input.Input != nil {
91+
qyGrandInput, err = b.processNode(input.Input, flagsEnum.SmartDesc, props)
92+
if err != nil {
93+
return nil, err
94+
}
95+
} else {
96+
qyGrandInput = &contextQuery{}
11297
}
113-
} else {
114-
qyGrandInput = &contextQuery{}
98+
qyOutput = &descendantQuery{name: root.LocalName, Input: qyGrandInput, Predicate: predicate, Self: false}
99+
*props |= builderProps.NonFlat
100+
return qyOutput, nil
115101
}
116-
// fix #20: https://github.com/antchfx/htmlquery/issues/20
117-
filter := func(n NodeNavigator) bool {
118-
v := predicate(n)
119-
switch root.Prop {
120-
case "text":
121-
v = v && n.NodeType() == TextNode
122-
case "comment":
123-
v = v && n.NodeType() == CommentNode
124-
}
125-
return v
126-
}
127-
qyOutput = &descendantQuery{name: root.LocalName, Input: qyGrandInput, Predicate: filter, Self: false}
128-
*props |= builderProps.NonFlat
129-
return qyOutput, nil
130102
}
131-
} else if ((flags & flagsEnum.Filter) == 0) && (root.AxeType == "descendant" || root.AxeType == "descendant-or-self") {
132-
inputFlags |= flagsEnum.SmartDesc
103+
if root.AxisType == "descendant" || root.AxisType == "descendant-or-self" {
104+
inputFlags |= flagsEnum.SmartDesc
105+
}
133106
}
107+
134108
qyInput, err = b.processNode(root.Input, inputFlags, props)
135109
if err != nil {
136110
return nil, err
137111
}
138112
}
139113

140-
switch root.AxeType {
114+
switch root.AxisType {
141115
case "ancestor":
142116
qyOutput = &ancestorQuery{name: root.LocalName, Input: qyInput, Predicate: predicate}
143117
*props |= builderProps.NonFlat
@@ -147,22 +121,10 @@ func (b *builder) processAxis(root *axisNode, flags flag, props *builderProp) (q
147121
case "attribute":
148122
qyOutput = &attributeQuery{name: root.LocalName, Input: qyInput, Predicate: predicate}
149123
case "child":
150-
filter := func(n NodeNavigator) bool {
151-
v := predicate(n)
152-
switch root.Prop {
153-
case "text":
154-
v = v && n.NodeType() == TextNode
155-
case "node":
156-
v = v && (n.NodeType() == ElementNode || n.NodeType() == TextNode)
157-
case "comment":
158-
v = v && n.NodeType() == CommentNode
159-
}
160-
return v
161-
}
162124
if (*props & builderProps.NonFlat) == 0 {
163-
qyOutput = &childQuery{name: root.LocalName, Input: qyInput, Predicate: filter}
125+
qyOutput = &childQuery{name: root.LocalName, Input: qyInput, Predicate: predicate}
164126
} else {
165-
qyOutput = &cachedChildQuery{name: root.LocalName, Input: qyInput, Predicate: filter}
127+
qyOutput = &cachedChildQuery{name: root.LocalName, Input: qyInput, Predicate: predicate}
166128
}
167129
case "descendant":
168130
if (flags & flagsEnum.SmartDesc) != flagsEnum.None {
@@ -195,7 +157,7 @@ func (b *builder) processAxis(root *axisNode, flags flag, props *builderProp) (q
195157
case "namespace":
196158
// haha,what will you do someting??
197159
default:
198-
err = fmt.Errorf("unknown axe type: %s", root.AxeType)
160+
err = fmt.Errorf("unknown axe type: %s", root.AxisType)
199161
return nil, err
200162
}
201163
return qyOutput, nil
@@ -238,24 +200,22 @@ func (b *builder) processFilter(root *filterNode, flags flag, props *builderProp
238200
*props |= builderProps.PosFilter
239201
}
240202

241-
merge := (qyInput.Properties() & queryProps.Merge) != 0
242203
if (propsCond & builderProps.HasPosition) != builderProps.None {
243204
if (propsCond & builderProps.HasLast) != 0 {
244205
// https://github.com/antchfx/xpath/issues/76
245206
// https://github.com/antchfx/xpath/issues/78
246207
if qyFunc, ok := cond.(*functionQuery); ok {
247208
switch qyFunc.Input.(type) {
248209
case *filterQuery:
249-
cond = &lastQuery{Input: qyFunc.Input}
210+
cond = &lastFuncQuery{Input: qyFunc.Input}
250211
}
251212
}
252213
}
253214
}
254215

216+
merge := (qyInput.Properties() & queryProps.Merge) != 0
255217
if first && firstInput != nil {
256218
if merge && ((*props & builderProps.PosFilter) != 0) {
257-
qyInput = &filterQuery{Input: qyInput, Predicate: cond, NoPosition: false}
258-
259219
var (
260220
rootQuery = &contextQuery{}
261221
parent query
@@ -318,10 +278,11 @@ func (b *builder) processFilter(root *filterNode, flags flag, props *builderProp
318278
}
319279
}
320280
b.firstInput = nil
281+
child := &filterQuery{Input: qyInput, Predicate: cond, NoPosition: false}
321282
if parent != nil {
322-
return &mergeQuery{Input: parent, Child: qyInput}, nil
283+
return &mergeQuery{Input: parent, Child: child}, nil
323284
}
324-
return qyInput, nil
285+
return child, nil
325286
}
326287
b.firstInput = nil
327288
}
@@ -346,7 +307,7 @@ func (b *builder) processFunction(root *functionNode, props *builderProp) (query
346307
if err != nil {
347308
return nil, err
348309
}
349-
qyOutput = &functionQuery{Input: arg, Func: lowerCaseFunc}
310+
qyOutput = &functionQuery{Func: lowerCaseFunc(arg)}
350311
case "starts-with":
351312
arg1, err := b.processNode(root.Args[0], flagsEnum.None, props)
352313
if err != nil {
@@ -453,16 +414,13 @@ func (b *builder) processFunction(root *functionNode, props *builderProp) (query
453414
if len(root.Args) > 0 {
454415
arg = root.Args[0]
455416
} else {
456-
arg = &axisNode{
457-
AxeType: "self",
458-
nodeType: nodeAxis,
459-
}
417+
arg = newAxisNode("self", allNode, "", "", "", nil)
460418
}
461-
argQuery, err := b.processNode(arg, flagsEnum.None, props)
419+
arg1, err := b.processNode(arg, flagsEnum.None, props)
462420
if err != nil {
463421
return nil, err
464422
}
465-
qyOutput = &functionQuery{Input: argQuery, Func: normalizespaceFunc}
423+
qyOutput = &functionQuery{Func: normalizespaceFunc(arg1)}
466424
case "replace":
467425
//replace( string , string, string )
468426
if len(root.Args) != 3 {
@@ -509,7 +467,7 @@ func (b *builder) processFunction(root *functionNode, props *builderProp) (query
509467
if err != nil {
510468
return nil, err
511469
}
512-
qyOutput = &functionQuery{Input: argQuery, Func: notFunc}
470+
qyOutput = &functionQuery{Func: notFunc(argQuery)}
513471
case "name", "local-name", "namespace-uri":
514472
if len(root.Args) > 1 {
515473
return nil, fmt.Errorf("xpath: %s function must have at most one parameter", root.FuncName)
@@ -540,17 +498,10 @@ func (b *builder) processFunction(root *functionNode, props *builderProp) (query
540498
},
541499
}
542500
case "last":
543-
//switch typ := b.firstInput.(type) {
544-
//case *groupQuery, *filterQuery:
545-
// https://github.com/antchfx/xpath/issues/76
546-
// https://github.com/antchfx/xpath/issues/78
547-
//qyOutput = &lastQuery{Input: typ}
548-
//default:
549-
qyOutput = &functionQuery{Func: lastFunc}
550-
//}
501+
qyOutput = &functionQuery{Input: b.firstInput, Func: lastFunc()}
551502
*props |= builderProps.HasLast
552503
case "position":
553-
qyOutput = &functionQuery{Func: positionFunc}
504+
qyOutput = &functionQuery{Input: b.firstInput, Func: positionFunc()}
554505
*props |= builderProps.HasPosition
555506
case "boolean", "number", "string":
556507
var inp query
@@ -564,16 +515,14 @@ func (b *builder) processFunction(root *functionNode, props *builderProp) (query
564515
}
565516
inp = argQuery
566517
}
567-
f := &functionQuery{Input: inp}
568518
switch root.FuncName {
569519
case "boolean":
570-
f.Func = booleanFunc
520+
qyOutput = &functionQuery{Func: booleanFunc(inp)}
571521
case "string":
572-
f.Func = stringFunc
522+
qyOutput = &functionQuery{Func: stringFunc(inp)}
573523
case "number":
574-
f.Func = numberFunc
524+
qyOutput = &functionQuery{Func: numberFunc(inp)}
575525
}
576-
qyOutput = f
577526
case "count":
578527
if len(root.Args) == 0 {
579528
return nil, fmt.Errorf("xpath: count(node-sets) function must with have parameters node-sets")
@@ -582,7 +531,7 @@ func (b *builder) processFunction(root *functionNode, props *builderProp) (query
582531
if err != nil {
583532
return nil, err
584533
}
585-
qyOutput = &functionQuery{Input: argQuery, Func: countFunc}
534+
qyOutput = &functionQuery{Func: countFunc(argQuery)}
586535
case "sum":
587536
if len(root.Args) == 0 {
588537
return nil, fmt.Errorf("xpath: sum(node-sets) function must with have parameters node-sets")
@@ -591,7 +540,7 @@ func (b *builder) processFunction(root *functionNode, props *builderProp) (query
591540
if err != nil {
592541
return nil, err
593542
}
594-
qyOutput = &functionQuery{Input: argQuery, Func: sumFunc}
543+
qyOutput = &functionQuery{Func: sumFunc(argQuery)}
595544
case "ceiling", "floor", "round":
596545
if len(root.Args) == 0 {
597546
return nil, fmt.Errorf("xpath: ceiling(node-sets) function must with have parameters node-sets")
@@ -600,16 +549,14 @@ func (b *builder) processFunction(root *functionNode, props *builderProp) (query
600549
if err != nil {
601550
return nil, err
602551
}
603-
f := &functionQuery{Input: argQuery}
604552
switch root.FuncName {
605553
case "ceiling":
606-
f.Func = ceilingFunc
554+
qyOutput = &functionQuery{Func: ceilingFunc(argQuery)}
607555
case "floor":
608-
f.Func = floorFunc
556+
qyOutput = &functionQuery{Func: floorFunc(argQuery)}
609557
case "round":
610-
f.Func = roundFunc
558+
qyOutput = &functionQuery{Func: roundFunc(argQuery)}
611559
}
612-
qyOutput = f
613560
case "concat":
614561
if len(root.Args) < 2 {
615562
return nil, fmt.Errorf("xpath: concat() must have at least two arguments")
@@ -636,22 +583,18 @@ func (b *builder) processFunction(root *functionNode, props *builderProp) (query
636583
if len(root.Args) != 2 {
637584
return nil, fmt.Errorf("xpath: string-join(node-sets, separator) function requires node-set and argument")
638585
}
639-
argQuery, err := b.processNode(root.Args[0], flagsEnum.None, props)
586+
input, err := b.processNode(root.Args[0], flagsEnum.None, props)
640587
if err != nil {
641588
return nil, err
642589
}
643590
arg1, err := b.processNode(root.Args[1], flagsEnum.None, props)
644591
if err != nil {
645592
return nil, err
646593
}
647-
qyOutput = &functionQuery{Input: argQuery, Func: stringJoinFunc(arg1)}
594+
qyOutput = &functionQuery{Func: stringJoinFunc(input, arg1)}
648595
default:
649596
return nil, fmt.Errorf("not yet support this function %s()", root.FuncName)
650597
}
651-
652-
if funcQuery, ok := qyOutput.(*functionQuery); ok && funcQuery.Input == nil {
653-
funcQuery.Input = b.firstInput
654-
}
655598
return qyOutput, nil
656599
}
657600

0 commit comments

Comments
 (0)