1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
|
struct XmlNode<'a, 'input: 'a>(roxmltree::Node<'a, 'input>);
impl<'a, 'input: 'a> XmlNode<'a, 'input> {
fn select(&self, text: &str) -> Option<roxmltree::Node<'a, 'input>> {
let selectors = simplecss::Selector::parse(text)?;
for node in self.0.descendants().filter(|n| n.is_element()) {
if selectors.matches(&XmlNode(node)) {
return Some(node);
}
}
None
}
}
impl simplecss::Element for XmlNode<'_, '_> {
fn parent_element(&self) -> Option<Self> {
self.0.parent_element().map(XmlNode)
}
fn prev_sibling_element(&self) -> Option<Self> {
self.0.prev_siblings().filter(|n| n.is_element()).nth(0).map(XmlNode)
}
fn has_local_name(&self, local_name: &str) -> bool {
self.0.tag_name().name() == local_name
}
fn attribute_matches(&self, local_name: &str, operator: simplecss::AttributeOperator) -> bool {
match self.0.attribute(local_name) {
Some(value) => operator.matches(value),
None => false,
}
}
fn pseudo_class_matches(&self, class: simplecss::PseudoClass) -> bool {
match class {
simplecss::PseudoClass::FirstChild => self.prev_sibling_element().is_none(),
_ => false, // Since we are querying a static XML we can ignore other pseudo-classes.
}
}
}
fn main() {
let doc = roxmltree::Document::parse(
"<svg>
<g>
<rect id='rect1' class='round blue'/>
<rect id='rect2' color='red'/>
</g>
</svg>"
).unwrap();
let root = XmlNode(doc.root_element());
assert_eq!(
root.select("rect:first-child").unwrap().attribute("id").unwrap(),
"rect1"
);
assert_eq!(
root.select("[color=red]").unwrap().attribute("id").unwrap(),
"rect2"
);
assert_eq!(
root.select("svg rect").unwrap().attribute("id").unwrap(),
"rect1"
);
assert_eq!(
root.select("svg > g > rect").unwrap().attribute("id").unwrap(),
"rect1"
);
assert_eq!(
root.select(".blue").unwrap().attribute("id").unwrap(),
"rect1"
);
}
|