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
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
// https://www.w3.org/TR/1999/REC-xpath-19991116/#node-tests


use std::fmt;

use markup5ever::{QualName, Namespace as Ns, LocalName};

use crate::{Evaluation, Nodeset, Node as DomNode};

pub trait NodeTest: fmt::Debug {
	fn test(&self, context: &Evaluation, result: &mut Nodeset);
}


// TODO: Convert to markup5ever::QualName
#[derive(Debug, Clone, PartialEq)]
pub struct NameTest { // '*' | NCName ':' '*' | QName
	pub prefix: Option<String>,
	pub local_part: String
}

impl NameTest {
	fn is_match(&self, _context: &Evaluation, qname: &QualName) -> bool {
		let has_wildcard = self.local_part == "*";

		// TODO: Compare prefix

		if has_wildcard {
			true
		} else {
			self.local_part.as_str() == &qname.local
		}
	}
}


// 5.3 Attribute Nodes
// Each element node has an associated set of attribute nodes;
// the element is the parent of each of these attribute nodes;
// however, an attribute node is not a child of its parent element.
//     NOTE: This is different from the DOM, which does not treat the element bearing an attribute as the parent of the attribute (see [DOM]).

// Elements never share attribute nodes:
//  if one element node is not the same node as another element node,
//  then none of the attribute nodes of the one element node will be the same node as the attribute nodes of another element node.
//     NOTE: The = operator tests whether two nodes have the same value, not whether they are the same node.
// 	         Thus attributes of two different elements may compare as equal using =, even though they are not the same node.

// A defaulted attribute is treated the same as a specified attribute.
// If an attribute was declared for the element type in the DTD,
// but the default was declared as #IMPLIED,
// and the attribute was not specified on the element,
// then the element's attribute set does not contain a node for the attribute.

// Some attributes, such as xml:lang and xml:space,
// have the semantics that they apply to all elements that are descendants of the element bearing the attribute,
// unless overridden with an instance of the same attribute on another descendant element.
// However, this does not affect where attribute nodes appear in the tree:
//  an element has attribute nodes only for attributes that were explicitly specified in the start-tag or empty-element tag of that element or that were explicitly declared in the DTD with a default value.

// An attribute node has an expanded-name and a string-value.
// The expanded-name is computed by expanding the QName specified in the tag in the XML document in accordance with the XML Namespaces Recommendation [XML Names].
// The namespace URI of the attribute's name will be null if the QName of the attribute does not have a prefix.
//     NOTE: In the notation of Appendix A.3 of [XML Names],
//           the local part of the expanded-name corresponds to the name attribute of the ExpAName element;
//           the namespace URI of the expanded-name corresponds to the ns attribute of the ExpAName element,
//           and is null if the ns attribute of the ExpAName element is omitted.

// An attribute node has a string-value.
// The string-value is the normalized value as specified by the XML Recommendation [XML].
// An attribute whose normalized value is a zero-length string is not treated specially:
//  it results in an attribute node whose string-value is a zero-length string.
//     NOTE: It is possible for default attributes to be declared in an external DTD or an external parameter entity.
//           The XML Recommendation does not require an XML processor to read an external DTD or an external parameter unless it is validating.
//           A stylesheet or other facility that assumes that the XPath tree contains default attribute values declared in an external DTD or parameter entity may not work with some non-validating XML processors.

// There are no attribute nodes corresponding to attributes that declare namespaces (see [XML Names]).
#[derive(Debug)]
pub struct Attribute {
	name_test: NameTest,
}

impl Attribute {
	pub fn new(name: NameTest) -> Attribute {
		Attribute { name_test: name }
	}
}

impl NodeTest for Attribute {
	fn test(&self, context: &Evaluation, result: &mut Nodeset) {
		if context.node.is_attribute() {
			if let Some(attr) = context.node.attribute() {
				if self.name_test.is_match(context, &attr.attr.name) {
					result.add_node(context.node.clone());
				}
			}
		}
	}
}



// 5.4 Namespace Nodes

// Each element has an associated set of namespace nodes,
// one for each distinct namespace prefix that is in scope for the element
// (including the xml prefix, which is implicitly declared by the XML Namespaces Recommendation [XML Names])
// and one for the default namespace if one is in scope for the element.
// The element is the parent of each of these namespace nodes;
// however, a namespace node is not a child of its parent element.
// Elements never share namespace nodes:
//     if one element node is not the same node as another element node,
//     then none of the namespace nodes of the one element node will be the same node as the namespace nodes of another element node.
// This means that an element will have a namespace node:
//     for every attribute on the element whose name starts with xmlns:;
//     for every attribute on an ancestor element whose name starts xmlns:
//         unless the element itself or a nearer ancestor redeclares the prefix;
//     for an xmlns attribute, if the element or some ancestor has an xmlns attribute,
//     and the value of the xmlns attribute for the nearest such element is non-empty
//         NOTE: An attribute xmlns="" "undeclares" the default namespace (see [XML Names]).

// A namespace node has an expanded-name: the local part is the namespace prefix (this is empty if the namespace node is for the default namespace); the namespace URI is always null.

// The string-value of a namespace node is the namespace URI that is being bound to the namespace prefix; if it is relative, it must be resolved just like a namespace URI in an expanded-name.
#[derive(Debug)]
pub struct Namespace {
	name_test: NameTest,
}

impl Namespace {
	pub fn new(name_test: NameTest) -> Namespace {
		Namespace { name_test }
	}
}

impl NodeTest for Namespace {
	fn test(&self, context: &Evaluation, result: &mut Nodeset) {
		if context.node.is_namespace() && self.name_test.is_match(context, &QualName::new(None, Ns::from(""), LocalName::from(context.node.prefix()))) {
			result.add_node(context.node.clone());
		}
	}
}

#[derive(Debug)]
pub struct Element {
	name_test: NameTest,
}

impl Element {
	pub fn new(name_test: NameTest) -> Element {
		Element { name_test }
	}
}

impl NodeTest for Element {
	fn test(&self, context: &Evaluation, result: &mut Nodeset) {
		if let Some(name) = context.node.name() {
			if context.node.is_element() && self.name_test.is_match(context, &name) {
				result.add_node(context.node.clone());
			}
		}
	}
}

#[allow(missing_copy_implementations)]
#[derive(Debug)]
pub struct Node;

impl NodeTest for Node {
	fn test(&self, context: &Evaluation, result: &mut Nodeset) {
		result.add_node(context.node.clone());
	}
}

#[allow(missing_copy_implementations)]
#[derive(Debug)]
pub struct Text;

impl NodeTest for Text {
	fn test(&self, context: &Evaluation, result: &mut Nodeset) {
		if let DomNode::Text(_) = context.node {
			result.add_node(context.node.clone());
		}
	}
}

#[allow(missing_copy_implementations)]
#[derive(Debug)]
pub struct Comment;

impl NodeTest for Comment {
	fn test(&self, context: &Evaluation, result: &mut Nodeset) {
		if let DomNode::Comment(_) = context.node {
			result.add_node(context.node.clone());
		}
	}
}

#[derive(Debug)]
pub struct ProcessingInstruction {
	target: Option<String>,
}

impl ProcessingInstruction {
	pub fn new(target: Option<String>) -> ProcessingInstruction {
		ProcessingInstruction { target }
	}
}

impl NodeTest for ProcessingInstruction {
	fn test(&self, context: &Evaluation, result: &mut Nodeset) {
		if context.node.is_processing_instruction() {
			match (self.target.as_deref(), context.node.target()) {
				(Some(name), Some(ref context_target)) if name == context_target => result.add_node(context.node.clone()),
				(None, _) => result.add_node(context.node.clone()),
				_ => {}
			}
		}
	}
}