xpather/lib.rs
1use html5ever::tendril::TendrilSink;
2
3
4pub mod value;
5pub mod result;
6pub mod parser;
7pub mod tokens;
8pub mod context;
9pub mod factory;
10pub mod functions;
11pub mod expressions;
12pub mod nodetest;
13
14pub use nodetest::{NodeTest, NameTest};
15pub use result::{Result, Error};
16pub use value::{Value, Node, Nodeset};
17pub use tokens::{ExprToken, AxisName, NodeType, Operator, PrincipalNodeType};
18pub use context::Evaluation;
19pub use parser::Tokenizer;
20pub use factory::{Factory, Document};
21
22
23pub static DEBUG: bool = false;
24
25
26pub fn parse_doc<R: std::io::Read>(data: &mut R) -> Document {
27 let parse: markup5ever_rcdom::RcDom = html5ever::parse_document(markup5ever_rcdom::RcDom::default(), Default::default())
28 .from_utf8()
29 .read_from(data)
30 .expect("html5ever");
31
32 Document::new(parse.document.into())
33}
34
35
36#[cfg(test)]
37mod tests {
38 use std::fs::File;
39
40 pub use crate::nodetest::{NodeTest, NameTest};
41 pub use crate::result::{Result, Error};
42 pub use crate::value::{Value, Node, Nodeset};
43 pub use crate::tokens::{ExprToken, AxisName, NodeType, Operator, PrincipalNodeType};
44 pub use crate::context::Evaluation;
45 pub use crate::parser::Tokenizer;
46 pub use crate::factory::{Factory, Document};
47 pub use crate::parse_doc;
48
49 #[test]
50 fn paths() {
51 // let doc = parse_doc(&mut File::open("./doc/example.html").expect("File::open"));
52
53 println!("Location Paths (Unabbreviated Syntax)");
54 // assert_eq!(doc.evaluate("//head/title"), Ok(Value::Nodeset(vec![].into()))); // selects the document root (which is always the parent of the document element)
55 // dbg!(doc.evaluate("self::para")); // selects the context node if it is a para element, and otherwise selects nothing
56 // dbg!(doc.evaluate("child::para")); // selects the para element children of the context node
57 // dbg!(doc.evaluate("child::*")); // selects all element children of the context node
58 // dbg!(doc.evaluate("child::text()")); // selects all text node children of the context node
59 // dbg!(doc.evaluate("child::node()")); // selects all the children of the context node, whatever their node type
60 // dbg!(doc.evaluate("child::chapter/descendant::para")); // selects the para element descendants of the chapter element children of the context node
61 // dbg!(doc.evaluate("child::*/child::para")); // selects all para grandchildren of the context node
62 // dbg!(doc.evaluate("child::para[position()=1]")); // selects the first para child of the context node
63 // dbg!(doc.evaluate("child::para[position()=last()]")); // selects the last para child of the context node
64 // dbg!(doc.evaluate("child::para[position()=last()-1]")); // selects the last but one para child of the context node
65 // dbg!(doc.evaluate("child::para[position()>1]")); // selects all the para children of the context node other than the first para child of the context node
66 // dbg!(doc.evaluate("/child::doc/child::chapter[position()=5]/child::section[position()=2]")); // selects the second section of the fifth chapter of the doc document element
67 // dbg!(doc.evaluate("child::para[attribute::type=\"warning\"]")); // selects all para children of the context node that have a type attribute with value warning
68 // dbg!(doc.evaluate("child::para[attribute::type='warning'][position()=5]")); // selects the fifth para child of the context node that has a type attribute with value warning
69 // dbg!(doc.evaluate("child::para[position()=5][attribute::type=\"warning\"]")); // selects the fifth para child of the context node if that child has a type attribute with value warning
70 // dbg!(doc.evaluate("child::chapter[child::title='Introduction']")); // selects the chapter children of the context node that have one or more title children with string-value equal to Introduction
71 // dbg!(doc.evaluate("child::chapter[child::title]")); // selects the chapter children of the context node that have one or more title children
72 // dbg!(doc.evaluate("child::*[self::chapter or self::appendix]")); // selects the chapter and appendix children of the context node
73 // dbg!(doc.evaluate("child::*[self::chapter or self::appendix][position()=last()]")); // selects the last chapter or appendix child of the context node
74 // dbg!(doc.evaluate("attribute::name")); // selects the name attribute of the context node
75 // dbg!(doc.evaluate("attribute::*")); // selects all the attributes of the context node
76 // dbg!(doc.evaluate("ancestor::div")); // selects all div ancestors of the context node
77 // dbg!(doc.evaluate("ancestor-or-self::div")); // selects the div ancestors of the context node and, if the context node is a div element, the context node as well
78 // dbg!(doc.evaluate("following-sibling::chapter[position()=1]")); // selects the next chapter sibling of the context node
79 // dbg!(doc.evaluate("preceding-sibling::chapter[position()=1]")); // selects the previous chapter sibling of the context node
80 // dbg!(doc.evaluate("descendant::para")); // selects the para element descendants of the context node
81 // dbg!(doc.evaluate("descendant-or-self::para")); // selects the para element descendants of the context node and, if the context node is a para element, the context node as well
82 // dbg!(doc.evaluate("/descendant::para")); // selects all the para elements in the same document as the context node
83 // dbg!(doc.evaluate("/descendant::olist/child::item")); // selects all the item elements that have an olist parent and that are in the same document as the context node
84 // dbg!(doc.evaluate("/descendant::figure[position()=42]")); // selects the forty-second figure element in the document
85 }
86
87 #[test]
88 fn paths_abbreviated() {
89 // println!("Location Paths (Abbreviated Syntax)");
90 // para selects the para element children of the context node
91 // * selects all element children of the context node
92 // text() selects all text node children of the context node
93 // @name selects the name attribute of the context node
94 // @* selects all the attributes of the context node
95 // para[1] selects the first para child of the context node
96 // para[last()] selects the last para child of the context node
97 // */para selects all para grandchildren of the context node
98 // /doc/chapter[5]/section[2] selects the second section of the fifth chapter of the doc
99 // chapter//para selects the para element descendants of the chapter element children of the context node
100 // //para selects all the para descendants of the document root and thus selects all para elements in the same document as the context node
101 // //olist/item selects all the item elements in the same document as the context node that have an olist parent
102 // . selects the context node
103 // .//para selects the para element descendants of the context node
104 // .. selects the parent of the context node
105 // ../@lang selects the lang attribute of the parent of the context node
106 // para[@type="warning"] selects all para children of the context node that have a type attribute with value warning
107 // para[@type="warning"][5] selects the fifth para child of the context node that has a type attribute with value warning
108 // para[5][@type="warning"] selects the fifth para child of the context node if that child has a type attribute with value warning
109 // chapter[title="Introduction"] selects the chapter children of the context node that have one or more title children with string-value equal to Introduction
110 // chapter[title] selects the chapter children of the context node that have one or more title children
111 // employee[@secretary and @assistant] selects all the employee children of the context node that have both a secretary attribute and an assistant attribute
112 }
113
114 #[test]
115 fn general_examples() {
116 // println!("Examples");
117 // dbg!(doc.evaluate("//*[@id='rcTEST']//*[contains(text(), 'TEST Interactive')]/../button[2]"));
118 // dbg!(doc.evaluate("//*[@id='rcTEST']//*[contains(text(), 'TEST Interactive')]/..//*[contains(text(), 'Setting')]"));
119 // dbg!(doc.evaluate("//*[@id='rcTEST']//*[contains(text(), 'TEST Interactive')]/following-sibling::button"));
120 // dbg!(doc.evaluate("// address[@class='ng-scope ng-isolate-scope']//div[contains('Testing') and @id='msgTitle']"));
121 // dbg!(doc.evaluate("//*[@name='myForm']//table[@id='tbl_ testdm']/tbody/tr/td[6]/"));
122 // dbg!(doc.evaluate("input[@value='Open RFS']"));
123 // dbg!(doc.evaluate("//*[@title='Songs List Applet']//table//td[contains(text(),'Author')]"));
124 // dbg!(doc.evaluate("//*[@id='parameters']//*[@id='testUpdateTime']"));
125 // dbg!(doc.evaluate("//*[@id='MODEL/PLAN']/div[1]/div[2]/div[1]/div[1]/widget/section/div[1]/div/div[1]/div/div/button[1]"));
126 // dbg!(doc.evaluate("//*[contains(text(),'Watch Dial')]/../div/select[@data-ng-model='context.questions[subqts.subHandleSubId]']"));
127 // dbg!(doc.evaluate("//*[@id='RESEARCH/PLAN']//*[contains(@id, 'A4')]/../../following-sibling::div[1]/div[1]/span[1]/span[1]"));
128 // dbg!(doc.evaluate("//*[@id='ALARMDATA']//*[contains(@id, 'AFC2')]/../../preceding-sibling::div[1]/div[1]/span[1]/span[1]"));
129 // dbg!(doc.evaluate("//*[@id='RESEARCH/REVIEW']//widget/section/div[1]/div/div[2]/div[1]/div[3]/div[1]//span[@class='details']"));
130 // dbg!(doc.evaluate("//a[contains(.,'Parameter Data Manual Entry')]"));
131 // dbg!(doc.evaluate("//*[contains(@style,'display: block; top:')]//input[@name='daterangepicker_end']"));
132 // dbg!(doc.evaluate("//*[@id='dropdown-filter-serviceTools']/following-sibling::ul/descendant::a[text()='Notepad']"));
133 // dbg!(doc.evaluate("//*[@id='dropdown-filter-serviceTools']/following-sibling::ul/descendant::a[text()='Trigger Dashboard']"));
134 // dbg!(doc.evaluate("//h3[text()='Internal Debrief']"));
135 // dbg!(doc.evaluate("//h3[contains(text(),'Helium Level')]/following-sibling::div/label/input"));
136 // dbg!(doc.evaluate("//div[div[p[contains(text(),'Status')]]]/preceding-sibling::div/div/span[3]/span"));
137 // dbg!(doc.evaluate("//*[@id='COUPLING']//*[contains(text(),'COUPLE Trend')]/../div/select"));
138 // dbg!(doc.evaluate("//*[@id='ffaHeaderDropdown']//a[contains(text(),'Start Workflow')]"));
139 }
140}