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}