Skip to main content

xpather/
value.rs

1use std::cell::Cell;
2use std::rc::Rc;
3use std::fmt;
4
5use markup5ever::{Attribute as DomAttribute, QualName};
6use markup5ever_rcdom::{NodeData, Handle as NodeHandle, WeakHandle as WeakNodeHandle, SerializableHandle};
7use html5ever::serialize;
8
9use crate::{Document, Error};
10use crate::result::{Result, ValueError};
11
12#[derive(Debug, Clone)]
13pub enum Value {
14	Boolean(bool),
15	Number(f64),
16	String(String),
17	Nodeset(Nodeset)
18}
19
20impl Value {
21	pub fn exists(&self) -> bool {
22		match self {
23			Value::Boolean(v) => *v,
24			Value::Number(v) => !v.is_nan(),
25			Value::String(v) => !v.is_empty(),
26			Value::Nodeset(v) => !v.nodes.is_empty()
27		}
28	}
29
30	pub fn as_nodeset(&self) -> Result<&Nodeset> {
31		match self {
32			Value::Nodeset(s) =>  Ok(s),
33			_ => Err(ValueError::Nodeset.into())
34		}
35	}
36
37	pub fn into_nodeset(self) -> Result<Nodeset> {
38		match self {
39			Value::Nodeset(s) =>  Ok(s),
40			_ => Err(ValueError::Nodeset.into())
41		}
42	}
43
44	pub fn into_iterset(self) -> Result<NodeIterset> {
45		match self {
46			Value::Nodeset(s) =>  Ok(NodeIterset::new(s.into_iter())),
47			_ => Err(ValueError::Nodeset.into())
48		}
49	}
50
51	pub fn vec_string(self) -> Result<Vec<String>> {
52		let value_iter = self.into_iterset()?
53			.map(|i| i.value().and_then(|v| v.string()))
54			.collect::<Result<Vec<String>>>()?;
55
56		Ok(value_iter)
57	}
58
59
60	pub fn boolean(&self) -> Result<bool> {
61		match self {
62			Value::Boolean(v) =>  Ok(*v),
63			_ => Err(ValueError::Boolean.into())
64		}
65	}
66
67	pub fn number(&self) -> Result<f64> {
68		match self {
69			Value::Number(v) =>  Ok(*v),
70			_ => Err(ValueError::Number.into())
71		}
72	}
73
74	pub fn as_string(&self) -> Result<&String> {
75		match self {
76			Value::String(v) =>  Ok(v),
77			_ => Err(ValueError::String.into())
78		}
79	}
80
81	pub fn string(self) -> Result<String> {
82		match self {
83			Value::String(v) =>  Ok(v),
84			_ => Err(ValueError::String.into())
85		}
86	}
87}
88
89impl PartialEq for Value {
90	fn eq(&self, other: &Value) -> bool {
91		match (self, other) {
92			// Noteset == String
93			(Value::Nodeset(set), Value::String(value)) |
94			(Value::String(value), Value::Nodeset(set)) => {
95
96				if set.nodes.is_empty() {
97					return false;
98				}
99
100				set.nodes.iter()
101				.any(|node| {
102					// TODO: No.
103					if &format!("{:?}", node) == value {
104						true
105					} else {
106						match node {
107							Node::Attribute(attr) => {
108								attr.value() == value
109							}
110
111							Node::Text(handle) => {
112								let upgrade = handle.upgrade().unwrap();
113								if let NodeData::Text { contents } = &upgrade.data {
114									contents.try_borrow().map(|v| v.as_ref() == value).unwrap_or_default()
115								} else {
116									false
117								}
118							}
119
120							_ => false
121						}
122					}
123				})
124			}
125
126			(Value::Nodeset(set1), Value::Nodeset(set2)) => {
127				// TODO: No.
128				format!("{:?}", set1) == format!("{:?}", set2)
129			}
130
131			_ => false
132		}
133	}
134}
135
136// node-set (an unordered collection of nodes without duplicates)
137// boolean (true or false)
138// number (a floating-point number)
139// string (a sequence of UCS characters)
140
141
142#[derive(Clone)]
143pub struct Attribute {
144	pub parent: WeakNodeHandle,
145	pub attr: DomAttribute
146}
147
148impl Attribute {
149	pub fn new(parent: WeakNodeHandle, attr: DomAttribute) -> Self {
150		Self {
151			parent,
152			attr
153		}
154	}
155
156	pub fn from_node(node: &WeakNodeHandle) -> Option<Vec<Attribute>> {
157		if let NodeData::Element { attrs, .. } = &node.upgrade().unwrap().data {
158			Some(attrs.borrow().iter().map(|a| Attribute::new(node.clone(), a.clone())).collect())
159		} else {
160			None
161		}
162	}
163
164	pub fn name(&self) -> &QualName {
165		&self.attr.name
166	}
167
168	pub fn name_string(&self) -> String {
169		let mut comp = String::new();
170
171		if let Some(prefix) = &self.attr.name.prefix {
172			comp.push_str(&prefix);
173			comp.push(':');
174		}
175
176		comp.push_str(&self.attr.name.local);
177
178		comp
179	}
180
181	pub fn value(&self) -> &str {
182		&*self.attr.value
183	}
184}
185
186
187// TODO: Convert to
188// pub struct Node(WeakNodeHandle);
189// - No way to know if it's an Attribute though.
190#[derive(Clone)]
191pub enum Node {
192	Root(NodeHandle),
193    DocType(WeakNodeHandle),
194    Element(WeakNodeHandle),
195    Attribute(Attribute),
196    Text(WeakNodeHandle),
197    Comment(WeakNodeHandle),
198    ProcessingInstruction(WeakNodeHandle),
199    Namespace(WeakNodeHandle), // Mainly used for xml
200}
201
202impl Node {
203	pub fn enum_name(&self) -> String {
204		match self {
205			Node::DocType(_) => "DocType".into(),
206			Node::Namespace(_) => "Namespace".into(),
207			Node::Root(_) => "Root".into(),
208			Node::Element(_) => "Element".into(),
209			Node::Attribute(_) => "Attribute".into(),
210			Node::Text(_) => "Text".into(),
211			Node::Comment(_) => "Comment".into(),
212			Node::ProcessingInstruction(_) => "ProcessingInstruction".into(),
213		}
214	}
215
216	pub fn is_root(&self) -> bool {
217		matches!(self, Node::Root(_))
218	}
219
220	pub fn is_namespace(&self) -> bool {
221		matches!(self, Node::Namespace(_))
222	}
223
224	pub fn is_element(&self) -> bool {
225		matches!(self, Node::Element(_))
226	}
227
228	pub fn is_attribute(&self) -> bool {
229		matches!(self, Node::Attribute(_))
230	}
231
232	pub fn is_text(&self) -> bool {
233		matches!(self, Node::Text(_))
234	}
235
236	pub fn is_comment(&self) -> bool {
237		matches!(self, Node::Comment(_))
238	}
239
240	pub fn is_processing_instruction(&self) -> bool {
241		matches!(self, Node::ProcessingInstruction(_))
242	}
243
244	pub fn value(&self) -> Result<Value> {
245		match self {
246			Node::Attribute(attr) => {
247				Ok(Value::String(attr.value().to_string()))
248			}
249
250			Node::Text(node) => {
251				if let NodeData::Text { contents } = &node.upgrade().unwrap().data {
252					Ok(Value::String(contents.borrow().to_string()))
253				} else {
254					Err(Error::NodeDidNotContainText)
255				}
256			}
257
258			_ => Err(Error::CannotConvertNodeToValue)
259		}
260	}
261
262	pub fn as_simple_html(&self) -> Option<String> {
263		match self {
264			Node::Root(_) => None,
265
266			Node::Attribute(attr) => {
267				Some(format!("@{}={}", attr.name_string(), attr.value()))
268			}
269
270			_ => {
271				let mut st = Vec::new();
272
273				let write = std::io::Cursor::new(&mut st);
274
275				serialize::<_, SerializableHandle>(
276					write,
277					&self.inner_weak()?.upgrade()?.into(),
278					html5ever::serialize::SerializeOpts { traversal_scope: markup5ever::serialize::TraversalScope::IncludeNode, .. Default::default() })
279				.ok()?;
280
281				Some(String::from_utf8(st).ok()?)
282			}
283		}
284	}
285
286	pub fn attribute(&self) -> Option<&Attribute> {
287		match self {
288			Node::Attribute(attr) => Some(attr),
289			_ => None
290		}
291	}
292
293	pub fn parent(&self) -> Option<Node> {
294		match self {
295			Node::Attribute(attr) => attr.parent.upgrade()
296				.and_then(|node| get_opt_node_from_cell(&node.parent).map(Node::Element)),
297			Node::DocType(_) |
298			Node::Namespace(_) |
299			Node::Root(_) => None,
300			Node::Element(weak) => weak.upgrade()
301				.and_then(|node| get_opt_node_from_cell(&node.parent).map(Node::Element)),
302			Node::Text(weak) => weak.upgrade()
303				.and_then(|node| get_opt_node_from_cell(&node.parent).map(Node::Text)),
304			Node::Comment(weak) => weak.upgrade()
305				.and_then(|node| get_opt_node_from_cell(&node.parent).map(Node::Comment)),
306			Node::ProcessingInstruction(weak) => weak.upgrade()
307				.and_then(|node| get_opt_node_from_cell(&node.parent).map(Node::ProcessingInstruction))
308		}
309	}
310
311	pub fn children(&self) -> Vec<Node> {
312		match self {
313			Node::Root(handle) => {
314				let node = handle.as_ref();
315
316				node.children.borrow()
317				.iter()
318				.map(|c| c.into())
319				.collect()
320			}
321
322			Node::Text(handle) |
323			Node::Comment(handle) |
324			Node::DocType(handle) |
325			Node::Element(handle) => {
326				let node = handle.upgrade().unwrap();
327
328				let borrow = node.children.borrow();
329
330				borrow.iter()
331				.map(|c| c.into())
332				.collect()
333			}
334
335			_ => unimplemented!("Node::children(\"{}\")", self.enum_name())
336		}
337	}
338
339
340	pub fn name(&self) -> Option<QualName> {
341		match self {
342			Node::Element(node) => {
343				if let NodeData::Element { name, .. } = &node.upgrade()?.data {
344					Some(name.clone())
345				} else {
346					None
347				}
348			}
349
350			Node::Attribute(attr) => {
351				if let NodeData::Element { name, .. } = &attr.parent.upgrade()?.data {
352					Some(name.clone())
353				} else {
354					None
355				}
356			}
357
358			_ => None
359		}
360	}
361
362	pub fn target(&self) -> Option<String> {
363		match self {
364			Node::ProcessingInstruction(node) => {
365				if let NodeData::ProcessingInstruction { target, .. } = &node.upgrade()?.data {
366					Some(target.to_string())
367				} else {
368					None
369				}
370			}
371
372			_ => None
373		}
374	}
375
376	pub fn prefix(&self) -> String {
377		unimplemented!("Node::prefix()");
378	}
379
380	pub fn inner_weak(&self) -> Option<&WeakNodeHandle> {
381		match self {
382			Node::Root(..) => None,
383			Node::DocType(weak) |
384			Node::Namespace(weak) |
385			Node::Element(weak) |
386			Node::Text(weak) |
387			Node::Comment(weak) |
388			Node::ProcessingInstruction(weak) => Some(weak),
389			Node::Attribute(weak) => Some(&weak.parent)
390		}
391	}
392
393
394	pub fn evaluate_from<S: Into<String>>(&self, search: S, doc: &Document) -> Result<Value> {
395		doc.evaluate_from(search, self.clone())
396	}
397}
398
399impl From<&NodeHandle> for Node {
400	fn from(handle: &NodeHandle) -> Self {
401		match &handle.data {
402			NodeData::Comment{ .. } => {
403				Node::Comment(Rc::downgrade(handle))
404			}
405
406			NodeData::Document => {
407				panic!("Cannot convert borrowed Document to Node.")
408			}
409
410			NodeData::Element{ .. } => {
411				Node::Element(Rc::downgrade(handle))
412			}
413
414			NodeData::ProcessingInstruction{ .. } => {
415				Node::ProcessingInstruction(Rc::downgrade(handle))
416			}
417
418			NodeData::Text{ .. } => {
419				Node::Text(Rc::downgrade(handle))
420			}
421
422			NodeData::Doctype { .. } => {
423				Node::DocType(Rc::downgrade(handle))
424			}
425		}
426	}
427}
428
429impl From<NodeHandle> for Node {
430	fn from(handle: NodeHandle) -> Self {
431		match handle.data {
432			NodeData::Comment{ .. } => {
433				Node::Comment(Rc::downgrade(&handle))
434			}
435
436			NodeData::Document => {
437				Node::Root(handle)
438			}
439
440			NodeData::Element{ .. } => {
441				Node::Element(Rc::downgrade(&handle))
442			}
443
444			NodeData::Doctype { .. } => {
445				Node::DocType(Rc::downgrade(&handle))
446			}
447
448			NodeData::ProcessingInstruction{ .. } => {
449				Node::ProcessingInstruction(Rc::downgrade(&handle))
450			}
451
452			NodeData::Text{ .. } => {
453				Node::Text(Rc::downgrade(&handle))
454			}
455		}
456	}
457}
458
459impl PartialEq for Node {
460	fn eq(&self, other: &Node) -> bool {
461		if self.is_root() || other.is_root() {
462			return self.is_root() == other.is_root();
463		}
464
465		match (self.inner_weak(), other.inner_weak()) {
466			(Some(left), Some(right)) => compare_weak_nodes(left, right),
467			_ => false
468		}
469	}
470}
471
472pub fn compare_weak_nodes(left: &WeakNodeHandle, right: &WeakNodeHandle) -> bool {
473	let left_upgrade = left.upgrade().unwrap();
474	let right_upgrade = right.upgrade().unwrap();
475
476	compare_nodes(&left_upgrade, &right_upgrade)
477}
478
479
480pub fn following_nodes_from_parent(node: &Node) -> Vec<Node> {
481	find_nodes_from_parent(node, |child_pos, node_pos| child_pos > node_pos)
482}
483
484pub fn preceding_nodes_from_parent(node: &Node) -> Vec<Node> {
485	find_nodes_from_parent(node, |child_pos, node_pos| child_pos < node_pos)
486}
487
488fn find_nodes_from_parent<F: Fn(usize, usize) -> bool>(node: &Node, f_capture: F) -> Vec<Node> {
489	let node = match node.inner_weak().and_then(|v| v.upgrade()) {
490		Some(v) => v,
491		None => return Vec::new()
492	};
493
494	// Taken from markup5ever_rcdom
495	if let Some(weak) = node.parent.take() {
496		let parent = weak.upgrade().expect("dangling weak pointer");
497		node.parent.set(Some(weak));
498
499		let children = parent.children.borrow();
500
501		let i = match children
502			.iter()
503			.enumerate()
504			.find(|&(_, child)| Rc::ptr_eq(&child, &node))
505		{
506			Some((i, _)) => i,
507			None => return Vec::new()
508		};
509
510		children
511		.iter()
512		.enumerate()
513		.filter(|c| f_capture(c.0, i))
514		.map(|i| i.1.into())
515		.collect()
516	} else {
517		Vec::new()
518	}
519}
520
521
522
523pub fn compare_nodes(left_upgrade: &NodeHandle, right_upgrade: &NodeHandle) -> bool {
524	let matched = match (&left_upgrade.data, &right_upgrade.data) {
525		(
526			NodeData::Text {
527				contents: b_contents
528			},
529			NodeData::Text {
530				contents
531			}
532		) => {
533			b_contents == contents
534		}
535
536		(
537			NodeData::Comment {
538				contents: b_contents
539			},
540			NodeData::Comment {
541				contents
542			}
543		) => {
544			b_contents == contents
545		}
546
547		(
548			NodeData::Doctype {
549				name: b_name,
550				public_id: b_public_id,
551				system_id: b_system_id
552			},
553			NodeData::Doctype {
554				name,
555				public_id,
556				system_id
557			}
558		) => {
559			b_name == name ||
560			b_public_id == public_id ||
561			b_system_id == system_id
562		}
563
564		(
565			NodeData::Element {
566				name: b_name,
567				attrs: b_attr,
568				template_contents: b_template_contents,
569				mathml_annotation_xml_integration_point: b_mathml
570			},
571			NodeData::Element {
572				name,
573				attrs,
574				template_contents,
575				mathml_annotation_xml_integration_point
576			}
577		) => {
578			b_name == name ||
579			b_attr == attrs ||
580			Some((b_template_contents, template_contents))
581			.filter(|c| c.0.is_some() || c.1.is_some())
582			.map(|i| compare_nodes(i.0.as_ref().unwrap(), i.1.as_ref().unwrap()))
583			.unwrap_or_default() ||
584			b_mathml == mathml_annotation_xml_integration_point
585		}
586
587		(
588			NodeData::ProcessingInstruction {
589				target: b_target,
590				contents: b_contents
591			},
592			NodeData::ProcessingInstruction {
593				target,
594				contents
595			}
596		) => {
597			b_target == target ||
598			b_contents == contents
599		}
600
601		_ => false
602	};
603
604	if matched {
605		return true;
606	}
607
608	// Compare children
609	let l_children = left_upgrade.children.borrow();
610	let r_children = right_upgrade.children.borrow();
611
612	if l_children.len() != r_children.len() {
613		return false;
614	}
615
616	// Find first position where it's false.
617	// If we found a non-equal child it'll return Some(pos)
618	// So we need to ensure it's None
619	l_children.iter()
620	.zip(r_children.iter())
621	.position(|c| !compare_nodes(c.0, c.1))
622	.is_none()
623}
624
625
626// impl From<Attribute> for Node {
627// 	fn from(handle: Attribute) -> Self {
628// 		Node::Attribute(handle)
629// 	}
630// }
631
632// impl From<&Attribute> for Node {
633// 	fn from(handle: &Attribute) -> Self {
634// 		Node::Attribute(handle.clone())
635// 	}
636// }
637
638impl fmt::Debug for Node {
639	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
640		match self {
641			Node::Root(weak) => {
642				f.debug_tuple("Root")
643					.field(&weak)
644					.finish()
645			}
646
647			Node::Attribute(weak) => {
648				f.debug_tuple("Attribute")
649					.field(&weak.parent.upgrade().unwrap().data)
650					.finish()
651			}
652
653			Node::DocType(weak) |
654			Node::Element(weak) |
655			Node::Namespace(weak) |
656			Node::Text(weak) |
657			Node::Comment(weak) |
658			Node::ProcessingInstruction(weak) => {
659				f.debug_tuple("Node")
660					.field(&weak.upgrade().unwrap().data)
661					.finish()
662			}
663		}
664
665	}
666}
667
668// TODO: Ensure no duplicate nodes
669#[derive(Clone)]
670pub struct Nodeset {
671	pub nodes: Vec<Node>
672}
673
674impl Nodeset {
675	pub fn new() -> Self {
676		Default::default()
677	}
678
679	pub fn add_node_handle(&mut self, node: &NodeHandle) {
680		self.nodes.push(node.into());
681	}
682
683	pub fn add_node(&mut self, node: Node) {
684		self.nodes.push(node);
685	}
686
687	pub fn extend(&mut self, nodeset: Nodeset) {
688		self.nodes.extend(nodeset.nodes);
689	}
690
691	pub fn len(&self) -> usize {
692		self.nodes.len()
693	}
694
695	pub fn is_empty(&self) -> bool {
696		self.nodes.is_empty()
697	}
698}
699
700impl Default for Nodeset {
701	fn default() -> Self {
702		Nodeset {
703			nodes: Vec::new()
704		}
705	}
706}
707
708
709impl IntoIterator for Nodeset {
710	type Item = Node;
711	type IntoIter = std::vec::IntoIter<Self::Item>;
712
713	fn into_iter(self) -> Self::IntoIter {
714		self.nodes.into_iter()
715	}
716}
717
718impl From<Vec<Node>> for Nodeset {
719	fn from(nodes: Vec<Node>) -> Self {
720		Self {
721			nodes
722		}
723	}
724}
725
726impl fmt::Debug for Nodeset {
727	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
728		let mut list = f.debug_list();
729
730		self.nodes.iter()
731		.for_each(|node| {
732			list.entry(&node.as_simple_html());
733		});
734
735
736		list.finish()
737	}
738}
739
740pub struct NodeIterset(std::vec::IntoIter<Node>);
741
742impl NodeIterset {
743	pub fn new(set: std::vec::IntoIter<Node>) -> Self {
744		Self(set)
745	}
746}
747
748impl Iterator for NodeIterset {
749	type Item = Node;
750
751	fn next(&mut self) -> Option<Self::Item> {
752		self.0.next()
753	}
754}
755
756pub struct Valueset(Vec<Value>);
757
758impl Valueset {
759	//
760}
761
762
763pub fn get_opt_node_from_cell(cell: &Cell<Option<WeakNodeHandle>>) -> Option<WeakNodeHandle> {
764	let item = cell.take();
765
766	let cloned = item.clone();
767
768	cell.set(item);
769
770	cloned
771}