1 use simplecss::*;
2
3 struct XmlNode<'a, 'input: 'a>(roxmltree::Node<'a, 'input>);
4
5 impl<'a, 'input: 'a> XmlNode<'a, 'input> {
select(&self, text: &str) -> Vec<roxmltree::Node<'a, 'input>>6 fn select(&self, text: &str) -> Vec<roxmltree::Node<'a, 'input>> {
7 let selectors = Selector::parse(text).unwrap();
8 let mut nodes = Vec::new();
9 for node in self.0.descendants().filter(|n| n.is_element()) {
10 if selectors.matches(&XmlNode(node)) {
11 nodes.push(node);
12 }
13 }
14
15 nodes
16 }
17 }
18
19 impl simplecss::Element for XmlNode<'_, '_> {
parent_element(&self) -> Option<Self>20 fn parent_element(&self) -> Option<Self> {
21 self.0.parent_element().map(XmlNode)
22 }
23
prev_sibling_element(&self) -> Option<Self>24 fn prev_sibling_element(&self) -> Option<Self> {
25 self.0.prev_siblings().filter(|n| n.is_element()).nth(0).map(XmlNode)
26 }
27
has_local_name(&self, local_name: &str) -> bool28 fn has_local_name(&self, local_name: &str) -> bool {
29 self.0.tag_name().name() == local_name
30 }
31
attribute_matches(&self, local_name: &str, operator: AttributeOperator) -> bool32 fn attribute_matches(&self, local_name: &str, operator: AttributeOperator) -> bool {
33 match self.0.attribute(local_name) {
34 Some(value) => operator.matches(value),
35 None => false,
36 }
37 }
38
pseudo_class_matches(&self, class: PseudoClass) -> bool39 fn pseudo_class_matches(&self, class: PseudoClass) -> bool {
40 match class {
41 PseudoClass::FirstChild => self.prev_sibling_element().is_none(),
42 _ => false,
43 }
44 }
45 }
46
47 macro_rules! match_single {
48 ($doc:expr, $selector:expr) => {{
49 let nodes = XmlNode($doc.root_element()).select($selector);
50 assert_eq!(nodes.len(), 1);
51 nodes[0].attribute("id").unwrap()
52 }};
53 }
54
55 macro_rules! match_none {
56 ($doc:expr, $selector:expr) => {{
57 assert_eq!(XmlNode($doc.root_element()).select($selector).len(), 0);
58 }};
59 }
60
61 #[test]
select_01()62 fn select_01() {
63 let doc = roxmltree::Document::parse("<div id='div1'/>").unwrap();
64 assert_eq!(match_single!(doc, "*"), "div1");
65 }
66
67 #[test]
select_02()68 fn select_02() {
69 let doc = roxmltree::Document::parse("<div id='div1'/>").unwrap();
70 assert_eq!(match_single!(doc, "div"), "div1");
71 match_none!(doc, "p");
72 }
73
74 #[test]
select_03()75 fn select_03() {
76 let doc = roxmltree::Document::parse("<div id='div1'/>").unwrap();
77 assert_eq!(match_single!(doc, "#div1"), "div1");
78 match_none!(doc, "#d1");
79 }
80
81 #[test]
select_04()82 fn select_04() {
83 let doc = roxmltree::Document::parse("<div id='div1'/>").unwrap();
84 match_none!(doc, "p#div1");
85 }
86
87 #[test]
select_05()88 fn select_05() {
89 let doc = roxmltree::Document::parse("\
90 <div id='div1'>
91 <p id='p1'/>
92 </div>
93 ").unwrap();
94
95 assert_eq!(match_single!(doc, "div p"), "p1");
96 }
97
98 #[test]
select_06()99 fn select_06() {
100 let doc = roxmltree::Document::parse("\
101 <div id='div1'>
102 <g id='g1'>
103 <p id='p1'/>
104 </g>
105 </div>
106 ").unwrap();
107
108 assert_eq!(match_single!(doc, "div p"), "p1");
109 }
110
111 #[test]
select_07()112 fn select_07() {
113 let doc = roxmltree::Document::parse("\
114 <div id='div1'>
115 <div id='div2'>
116 <g id='g1'>
117 <p id='p1'/>
118 </g>
119 </div>
120 </div>
121 ").unwrap();
122
123 assert_eq!(match_single!(doc, "div p"), "p1");
124 }
125
126 #[test]
select_08()127 fn select_08() {
128 let doc = roxmltree::Document::parse("\
129 <div id='div1'>
130 <g id='g1'>
131 <p id='p1'>
132 <div/>
133 </p>
134 </g>
135 </div>
136 ").unwrap();
137
138 assert_eq!(match_single!(doc, "div p"), "p1");
139 }
140
141 #[test]
select_09()142 fn select_09() {
143 let doc = roxmltree::Document::parse("\
144 <div id='div1'>
145 <g id='g1'>
146 <p id='p1'/>
147 </g>
148 </div>
149 ").unwrap();
150
151 assert_eq!(match_single!(doc, "div g p"), "p1");
152 }
153
154 #[test]
select_10()155 fn select_10() {
156 let doc = roxmltree::Document::parse("\
157 <div id='div1'>
158 <q id='g1'>
159 <p id='p1'/>
160 </q>
161 </div>
162 ").unwrap();
163
164 match_none!(doc, "div g p");
165 }
166
167 #[test]
select_11()168 fn select_11() {
169 let doc = roxmltree::Document::parse("\
170 <div id='div1'>
171 <g id='g1'>
172 <p id='p1'/>
173 </g>
174 </div>
175 ").unwrap();
176
177 assert_eq!(match_single!(doc, "div * p"), "p1");
178 }
179
180 #[test]
select_12()181 fn select_12() {
182 let doc = roxmltree::Document::parse("\
183 <div id='div1'>
184 <p id='p1'>
185 <rect id='rect1'/>
186 <rect id='rect2' color='green'/>
187 </p>
188 </div>
189 ").unwrap();
190
191 assert_eq!(match_single!(doc, "div p *[color]"), "rect2");
192 assert_eq!(match_single!(doc, "div p [color]"), "rect2");
193 }
194
195 #[test]
select_13()196 fn select_13() {
197 let doc = roxmltree::Document::parse("\
198 <div id='div1'>
199 <p id='p1'/>
200 </div>
201 ").unwrap();
202
203 assert_eq!(match_single!(doc, "div > p"), "p1");
204 }
205
206 #[test]
select_14()207 fn select_14() {
208 let doc = roxmltree::Document::parse("\
209 <p id='p1'/>
210 ").unwrap();
211
212 match_none!(doc, "div > p");
213 }
214
215 #[test]
select_15()216 fn select_15() {
217 let doc = roxmltree::Document::parse("\
218 <div id='div1'>
219 <g id='g1'>
220 <p id='p1'/>
221 </g>
222 </div>
223 ").unwrap();
224
225 match_none!(doc, "div > p");
226 }
227
228 #[test]
select_16()229 fn select_16() {
230 let doc = roxmltree::Document::parse("\
231 <div id='div1'>
232 <p>
233 <ol>
234 <li>
235 <g>
236 <p id='p1'/>
237 </g>
238 </li>
239 </ol>
240 </p>
241 </div>
242 ").unwrap();
243
244 assert_eq!(match_single!(doc, "div ol>li p"), "p1");
245 }
246
247 #[test]
select_17()248 fn select_17() {
249 let doc = roxmltree::Document::parse("\
250 <div id='div1'>
251 <p>
252 <ol>
253 <g>
254 <li>
255 <g>
256 <p id='p1'/>
257 </g>
258 </li>
259 </g>
260 </ol>
261 </p>
262 </div>
263 ").unwrap();
264
265 match_none!(doc, "div ol>li p");
266 }
267
268 #[test]
select_18()269 fn select_18() {
270 let doc = roxmltree::Document::parse("\
271 <div id='div1'>
272 <g/>
273 <p id='p1'/>
274 </div>
275 ").unwrap();
276
277 assert_eq!(match_single!(doc, "g + p"), "p1");
278 }
279
280 #[test]
select_19()281 fn select_19() {
282 let doc = roxmltree::Document::parse("\
283 <div id='div1'>
284 <test/>
285 <g/>
286 <p id='p1'/>
287 </div>
288 ").unwrap();
289
290 assert_eq!(match_single!(doc, "g + p"), "p1");
291 }
292
293 #[test]
select_20()294 fn select_20() {
295 let doc = roxmltree::Document::parse("\
296 <div id='div1'>
297 <p id='p1'/>
298 <g/>
299 </div>
300 ").unwrap();
301
302 match_none!(doc, "g + p");
303 }
304
305 #[test]
select_21()306 fn select_21() {
307 let doc = roxmltree::Document::parse("\
308 <div id='div1'>
309 <p id='p1'/>
310 </div>
311 ").unwrap();
312
313 match_none!(doc, "div + p");
314 }
315
316 #[test]
select_22()317 fn select_22() {
318 let doc = roxmltree::Document::parse("\
319 <div id='div1'>
320 <p id='p1'/>
321 </div>
322 ").unwrap();
323
324 assert_eq!(match_single!(doc, "[id=p1]"), "p1");
325 }
326
327 #[test]
select_23()328 fn select_23() {
329 let doc = roxmltree::Document::parse("\
330 <div id='div1'>
331 <p id='p1' class='test warn'/>
332 </div>
333 ").unwrap();
334
335 assert_eq!(match_single!(doc, "[class~=warn]"), "p1");
336 }
337
338 #[test]
select_24()339 fn select_24() {
340 let doc = roxmltree::Document::parse("\
341 <div id='div1'>
342 <p id='p1' class='test warn'/>
343 </div>
344 ").unwrap();
345
346 match_none!(doc, "[class~='test warn']");
347 }
348
349 #[test]
select_25()350 fn select_25() {
351 let doc = roxmltree::Document::parse("\
352 <div id='div1'>
353 <p id='p1' lang='en'/>
354 </div>
355 ").unwrap();
356
357 assert_eq!(match_single!(doc, "[lang=en]"), "p1");
358 assert_eq!(match_single!(doc, "[lang|=en]"), "p1");
359 }
360
361 #[test]
select_26()362 fn select_26() {
363 let doc = roxmltree::Document::parse("\
364 <div id='div1'>
365 <p id='p1' lang='en-US'/>
366 </div>
367 ").unwrap();
368
369 assert_eq!(match_single!(doc, "[lang='en-US']"), "p1");
370 assert_eq!(match_single!(doc, "[lang|=en]"), "p1");
371 }
372
373 #[test]
select_27()374 fn select_27() {
375 let doc = roxmltree::Document::parse("\
376 <div id='div1'>
377 <p id='p1' class='pastoral blue aqua marine'/>
378 </div>
379 ").unwrap();
380
381 assert_eq!(match_single!(doc, ".marine.pastoral"), "p1");
382 }
383
384 #[test]
select_28()385 fn select_28() {
386 let doc = roxmltree::Document::parse("\
387 <div id='div1'>
388 <p id='p1'/>
389 </div>
390 ").unwrap();
391
392 assert_eq!(match_single!(doc, "p:first-child"), "p1");
393 }
394
395 #[test]
select_29()396 fn select_29() {
397 let doc = roxmltree::Document::parse("\
398 <div id='div1'>
399 <rect/>
400 <p id='p1'/>
401 </div>
402 ").unwrap();
403
404 match_none!(doc, "p:first-child");
405 }
406
407 #[test]
select_30()408 fn select_30() {
409 let doc = roxmltree::Document::parse("\
410 <div id='div1'>
411 <p id='p1'/>
412 <p id='p2'/>
413 </div>
414 ").unwrap();
415
416 let nodes = XmlNode(doc.root_element()).select(":first-child");
417 assert_eq!(nodes.len(), 2);
418 assert_eq!(nodes[0].attribute("id").unwrap(), "div1");
419 assert_eq!(nodes[1].attribute("id").unwrap(), "p1");
420 }
421
422 #[test]
to_string()423 fn to_string() {
424 let selectors = Selector::parse("a > b").unwrap();
425 assert_eq!(selectors.to_string(), "a > b");
426 }
427