|
1 |
| -import pegs, strutils, ../xml |
| 1 | +import strutils, ../xml |
2 | 2 | from streams import newStringStream
|
3 | 3 | from strtabs import hasKey
|
4 | 4 |
|
5 |
| - |
6 |
| -let |
7 |
| - attribute = r"[a-zA-Z][a-zA-Z0-9_\-]*" |
8 |
| - classes = r"{\.[a-zA-Z0-9_][a-zA-Z0-9_\-]*}" |
9 |
| - attributes = r"{\[" & attribute & r"\s*([\*\^\$\~]?\=\s*[\'""]?(\s*\ident\s*)+[\'""]?)?\]}" |
10 |
| - pselectors = peg(r"\s*{\ident}?({'#'\ident})? (" & classes & ")* " & attributes & "*") |
11 |
| - pattributes = peg(r"{\[{" & attribute & r"}\s*({[\*\^\$\~]?}\=\s*[\'""]?{(\s*\ident\s*)+}[\'""]?)?\]}") |
12 |
| - |
13 | 5 | type
|
| 6 | + TokenKind = enum |
| 7 | + TAG |
| 8 | + ID |
| 9 | + CLASS |
| 10 | + ATTR |
14 | 11 | Attribute = object
|
15 | 12 | name: string
|
16 | 13 | operator: char
|
|
26 | 23 | QueryContext = object
|
27 | 24 | root: seq[XmlNode]
|
28 | 25 |
|
29 |
| -proc newSelector(tag, id = "", classes: seq[string] = @[], attributes: seq[Attribute] = @[]): Selector = |
| 26 | +proc push(s: var Selector, kind: TokenKind, name: string) = |
| 27 | + case kind |
| 28 | + of TAG: |
| 29 | + s.tag = name |
| 30 | + of ID: |
| 31 | + s.id = name |
| 32 | + of CLASS: |
| 33 | + s.classes.add(name) |
| 34 | + else: |
| 35 | + echo "parse attribute" |
| 36 | + |
| 37 | +proc newSelector*(tag, id = "", classes: seq[string] = @[], attributes: seq[Attribute] = @[]): Selector = |
30 | 38 | result.combinator = ' '
|
31 | 39 | result.tag = tag
|
32 | 40 | result.id = id
|
@@ -140,32 +148,45 @@ proc searchCombined(parents: var seq[XmlNode], selectors: seq[Selector]) =
|
140 | 148 |
|
141 | 149 | parents = found
|
142 | 150 |
|
143 |
| -proc parseSelector(token: string): Selector = |
| 151 | +proc parseSelector*(token: string): Selector = |
144 | 152 | result = newSelector()
|
145 | 153 | # Universal selector
|
146 | 154 | if token == "*":
|
147 | 155 | result.tag = "*"
|
148 | 156 | # Type selector
|
149 |
| - elif token =~ pselectors: |
150 |
| - for i in 0..matches.len-1: |
151 |
| - if matches[i].isNil: |
| 157 | + else: |
| 158 | + var |
| 159 | + pos: int |
| 160 | + length = token.len |
| 161 | + kind = TAG |
| 162 | + name = "" |
| 163 | + ch: char |
| 164 | + |
| 165 | + while pos < length: |
| 166 | + ch = token[pos] |
| 167 | + if ch in Whitespace: |
| 168 | + inc(pos) |
152 | 169 | continue
|
153 |
| - |
154 |
| - let ch = matches[i][0] |
155 |
| - case ch: |
156 |
| - of '#': |
157 |
| - matches[i].delete(0, 0) |
158 |
| - result.id = matches[i] |
159 |
| - of '.': |
160 |
| - matches[i].delete(0, 0) |
161 |
| - result.classes.add(matches[i]) |
162 |
| - of '[': |
163 |
| - if matches[i] =~ pattributes: |
164 |
| - result.attributes.add(newAttribute(matches[1], matches[2], matches[3])) |
| 170 | + if ch in {'#', '.', '[', '=', ']'}: |
| 171 | + result.push(kind, name) |
| 172 | + if ch == '#': |
| 173 | + kind = ID |
| 174 | + elif ch == '.': |
| 175 | + kind = CLASS |
| 176 | + elif ch == '[': |
| 177 | + kind = ATTR |
| 178 | + name = "" |
| 179 | + #echo "next ", kind |
165 | 180 | else:
|
166 |
| - result.tag = matches[i] |
167 |
| - else: |
168 |
| - discard |
| 181 | + #if name.len == 0: |
| 182 | + # assert ch in IdentStartChars |
| 183 | + name.add(ch) |
| 184 | + |
| 185 | + if pos == length-1: |
| 186 | + result.push(kind, name) |
| 187 | + break |
| 188 | + |
| 189 | + inc(pos) |
169 | 190 |
|
170 | 191 | proc select*(q: QueryContext, s: string = ""): seq[XmlNode] =
|
171 | 192 | ## Return list of nodes matched by CSS selector
|
|
0 commit comments