@@ -21,6 +21,24 @@ type JSONStreamReader struct {
21
21
}
22
22
23
23
// streamCandidateCheck checks if sp.cur is a potential stream candidate.
24
+ // Note even if sp.cur is marked, it only means it could potentially be the
25
+ // stream candidate, not guaranteed. E.g., say have a JSON doc looks like this:
26
+ // {
27
+ // "x": {
28
+ // "a": 5
29
+ // },
30
+ // "y": {
31
+ // "a": 2
32
+ // }
33
+ // }
34
+ // And our stream xpath is "/*/a[. < 4]".
35
+ // When the reader first encounters "x/a" node, it has the potential to be the
36
+ // stream candidate since it matches "/*/a". But we haven't finished processing
37
+ // the entire node, thus no way we know if the value of "a" would match the filter
38
+ // or not. So we have to mark it as a potential stream candidate and will let
39
+ // wrapUpCurAndTargetCheck to do the final check when the entire node of "/x/a"
40
+ // is ingested and processed, in which case, "/x/a" will be not be considered
41
+ // as stream target, but later "/x/b" will be.
24
42
func (sp * JSONStreamReader ) streamCandidateCheck () {
25
43
if sp .xpathExpr != nil && sp .stream == nil && MatchAny (sp .root , sp .xpathExpr ) {
26
44
sp .stream = sp .cur
@@ -33,7 +51,7 @@ func (sp *JSONStreamReader) streamCandidateCheck() {
33
51
// - Either we don't have a stream filter xpath or the stream filter xpath matches.
34
52
func (sp * JSONStreamReader ) wrapUpCurAndTargetCheck () * Node {
35
53
cur := sp .cur
36
- // No matter what outcome the wrapUpCurAndTargetCheck() is, the current node is done and
54
+ // No matter what outcome the wrapUpCurAndTargetCheck() is, the current node is done, and
37
55
// we need to adjust sp.cur to its parent.
38
56
sp .cur = sp .cur .Parent
39
57
// Only do stream target check if the finished cur node is the stream candidate
@@ -78,7 +96,7 @@ func (sp *JSONStreamReader) addTextChild(tok interface{}) {
78
96
}
79
97
child := CreateJSONNode (TextNode , data , jtype )
80
98
AddChild (sp .cur , child )
81
- // If the child being added is a value node, there won't be anything else
99
+ // Since the child being added is a value node, there won't be anything else
82
100
// added below it, so no need to advance sp.cur to child.
83
101
}
84
102
@@ -100,7 +118,7 @@ func (sp *JSONStreamReader) parseDelim(tok json.Delim) *Node {
100
118
// already done the check when the property itself is processed.
101
119
sp .cur .FormatSpecific = JSONTypeOf (sp .cur ) | JSONObj
102
120
case IsJSONRoot (sp .cur ):
103
- // if we see "{" directly on root, make the root node a obj type container
121
+ // if we see "{" directly on root, make the root node an obj type container
104
122
// and do stream candidate check.
105
123
sp .cur .FormatSpecific = JSONTypeOf (sp .cur ) | JSONObj
106
124
sp .streamCandidateCheck ()
@@ -138,7 +156,7 @@ func (sp *JSONStreamReader) parseVal(tok json.Token) *Node {
138
156
case IsJSONObj (sp .cur ):
139
157
sp .addElementChild (tok .(string ), JSONProp )
140
158
sp .streamCandidateCheck ()
141
- // similarly we want arr check before prop check.
159
+ // Similarly, we want arr check before prop check.
142
160
case IsJSONArr (sp .cur ):
143
161
// if parent is an array or root, so we're adding a value directly to
144
162
// the array or root, by creating an anonymous element node, then the
@@ -158,7 +176,7 @@ func (sp *JSONStreamReader) parseVal(tok json.Token) *Node {
158
176
}
159
177
case IsJSONRoot (sp .cur ):
160
178
// A value is directly setting on root. We need to do both stream candidate check
161
- // as well as target check.
179
+ // and target check.
162
180
sp .streamCandidateCheck ()
163
181
sp .addTextChild (tok )
164
182
ret := sp .wrapUpCurAndTargetCheck ()
0 commit comments