use xee_schema_type::Xs;
use xot::Xot;
use xee_xpath_ast::ast;
pub(crate) fn kind_test(kind_test: &ast::KindTest, xot: &Xot, node: xot::Node) -> bool {
match kind_test {
ast::KindTest::Document(dt) => document_test(dt.as_ref(), xot, node),
ast::KindTest::Element(et) => element_test(et.as_ref(), xot, node),
ast::KindTest::SchemaElement(_set) => {
todo!()
}
ast::KindTest::Attribute(at) => attribute_test(at.as_ref(), xot, node),
ast::KindTest::SchemaAttribute(_sat) => {
todo!()
}
ast::KindTest::Any => true,
ast::KindTest::Text => xot.is_text(node),
ast::KindTest::Comment => xot.is_comment(node),
ast::KindTest::NamespaceNode => xot.is_namespace_node(node),
ast::KindTest::PI(pi_test) => {
if !xot.is_processing_instruction(node) {
return false;
}
if let Some(_pi_test) = pi_test {
return false;
}
true
}
}
}
fn element_test(test: Option<&ast::ElementOrAttributeTest>, xot: &Xot, node: xot::Node) -> bool {
element_or_attribute_test(test, xot, node, |node, xot| xot.is_element(node))
}
fn attribute_test(test: Option<&ast::ElementOrAttributeTest>, xot: &Xot, node: xot::Node) -> bool {
element_or_attribute_test(test, xot, node, |node, xot| xot.is_attribute_node(node))
}
fn document_test(test: Option<&ast::DocumentTest>, xot: &Xot, node: xot::Node) -> bool {
if !xot.is_document(node) {
return false;
}
if let Some(document_test) = test {
let document_element_node = xot.document_element(node).unwrap();
match document_test {
ast::DocumentTest::Element(et) => element_test(et.as_ref(), xot, document_element_node),
ast::DocumentTest::SchemaElement(_set) => {
todo!()
}
}
} else {
true
}
}
fn element_or_attribute_test(
test: Option<&ast::ElementOrAttributeTest>,
xot: &Xot,
node: xot::Node,
node_type_match: impl Fn(xot::Node, &Xot) -> bool,
) -> bool {
if !node_type_match(node, xot) {
return false;
}
if let Some(test) = test {
let name_matches = match &test.name_or_wildcard {
ast::NameOrWildcard::Name(name) => {
if let Some(node_name) = xot.node_name_ref(node).unwrap() {
name.maybe_to_ref(xot) == Some(node_name)
} else {
false
}
}
ast::NameOrWildcard::Wildcard => true,
};
if !name_matches {
return false;
}
if let Some(type_name) = &test.type_name {
type_annotation(xot, node).derives_from(type_name.name)
} else {
true
}
} else {
true
}
}
fn type_annotation(_xot: &Xot, _node: xot::Node) -> Xs {
Xs::UntypedAtomic
}
#[cfg(test)]
mod tests {
use xee_xpath_ast::parse_kind_test;
use super::*;
#[test]
fn test_kind_test_any() {
let mut xot = Xot::new();
let doc = xot.parse(r#"<root><a/><b/></root>"#).unwrap();
let doc_el = xot.document_element(doc).unwrap();
let a = xot.first_child(doc_el).unwrap();
let kt = parse_kind_test("node()").unwrap();
assert!(kind_test(&kt, &xot, doc));
assert!(kind_test(&kt, &xot, doc_el));
assert!(kind_test(&kt, &xot, a));
}
#[test]
fn test_kind_test_text() {
let mut xot = Xot::new();
let doc = xot.parse(r#"<root><a>content</a><b/></root>"#).unwrap();
let doc_el = xot.document_element(doc).unwrap();
let a = xot.first_child(doc_el).unwrap();
let a_text = xot.first_child(a).unwrap();
let kt = parse_kind_test("text()").unwrap();
assert!(!kind_test(&kt, &xot, doc));
assert!(!kind_test(&kt, &xot, doc_el));
assert!(!kind_test(&kt, &xot, a));
assert!(kind_test(&kt, &xot, a_text));
}
#[test]
fn test_kind_test_comment() {
let mut xot = Xot::new();
let doc = xot.parse(r#"<root><!-- comment --></root>"#).unwrap();
let doc_el = xot.document_element(doc).unwrap();
let comment = xot.first_child(doc_el).unwrap();
let kt = parse_kind_test("comment()").unwrap();
assert!(!kind_test(&kt, &xot, doc));
assert!(!kind_test(&kt, &xot, doc_el));
assert!(kind_test(&kt, &xot, comment));
}
#[test]
fn test_kind_test_document() {
let mut xot = Xot::new();
let doc = xot.parse(r#"<root></root>"#).unwrap();
let doc_el = xot.document_element(doc).unwrap();
let kt = parse_kind_test("document-node()").unwrap();
assert!(kind_test(&kt, &xot, doc));
assert!(!kind_test(&kt, &xot, doc_el));
}
#[test]
fn test_kind_test_element_without_name() {
let mut xot = Xot::new();
let doc = xot.parse(r#"<root><a>text</a></root>"#).unwrap();
let doc_el = xot.document_element(doc).unwrap();
let a = xot.first_child(doc_el).unwrap();
let text = xot.first_child(a).unwrap();
let kt = parse_kind_test("element()").unwrap();
assert!(!kind_test(&kt, &xot, doc));
assert!(kind_test(&kt, &xot, doc_el));
assert!(kind_test(&kt, &xot, a));
assert!(!kind_test(&kt, &xot, text));
}
#[test]
fn test_kind_test_element_with_wildcard() {
let mut xot = Xot::new();
let doc = xot.parse(r#"<root><a>text</a></root>"#).unwrap();
let doc_el = xot.document_element(doc).unwrap();
let a = xot.first_child(doc_el).unwrap();
let text = xot.first_child(a).unwrap();
let kt = parse_kind_test("element(*)").unwrap();
assert!(!kind_test(&kt, &xot, doc));
assert!(kind_test(&kt, &xot, doc_el));
assert!(kind_test(&kt, &xot, a));
assert!(!kind_test(&kt, &xot, text));
}
#[test]
fn test_kind_test_element_with_name() {
let mut xot = Xot::new();
let doc = xot.parse(r#"<root><a>text</a></root>"#).unwrap();
let doc_el = xot.document_element(doc).unwrap();
let a = xot.first_child(doc_el).unwrap();
let text = xot.first_child(a).unwrap();
let kt = parse_kind_test("element(a)").unwrap();
assert!(!kind_test(&kt, &xot, doc));
assert!(!kind_test(&kt, &xot, doc_el));
assert!(kind_test(&kt, &xot, a));
assert!(!kind_test(&kt, &xot, text));
}
#[test]
fn test_kind_test_element_with_type_name() {
let mut xot = Xot::new();
let doc = xot.parse(r#"<root><a>text</a></root>"#).unwrap();
let doc_el = xot.document_element(doc).unwrap();
let a = xot.first_child(doc_el).unwrap();
let text = xot.first_child(a).unwrap();
let kt = parse_kind_test("element(a, xs:untypedAtomic)").unwrap();
assert!(!kind_test(&kt, &xot, doc));
assert!(!kind_test(&kt, &xot, doc_el));
assert!(kind_test(&kt, &xot, a));
assert!(!kind_test(&kt, &xot, text));
let kt = parse_kind_test("element(a, xs:string)").unwrap();
assert!(!kind_test(&kt, &xot, a));
}
#[test]
fn test_kind_test_attribute_without_name() {
let mut xot = Xot::new();
let alpha = xot.add_name("alpha");
let beta = xot.add_name("beta");
let doc = xot
.parse(r#"<root><a alpha="Alpha" beta="Beta">text</a></root>"#)
.unwrap();
let doc_el = xot.document_element(doc).unwrap();
let a = xot.first_child(doc_el).unwrap();
let text = xot.first_child(a).unwrap();
let alpha = xot.attributes(a).get_node(alpha).unwrap();
let beta = xot.attributes(a).get_node(beta).unwrap();
let kt = parse_kind_test("attribute()").unwrap();
assert!(!kind_test(&kt, &xot, doc));
assert!(!kind_test(&kt, &xot, doc_el));
assert!(!kind_test(&kt, &xot, a));
assert!(kind_test(&kt, &xot, alpha));
assert!(kind_test(&kt, &xot, beta));
assert!(!kind_test(&kt, &xot, text));
}
#[test]
fn test_kind_test_attribute_with_name() {
let mut xot = Xot::new();
let alpha = xot.add_name("alpha");
let beta = xot.add_name("beta");
let doc = xot
.parse(r#"<root><a alpha="Alpha" beta="Beta">text</a></root>"#)
.unwrap();
let doc_el = xot.document_element(doc).unwrap();
let a = xot.first_child(doc_el).unwrap();
let text = xot.first_child(a).unwrap();
let alpha = xot.attributes(a).get_node(alpha).unwrap();
let beta = xot.attributes(a).get_node(beta).unwrap();
let kt = parse_kind_test("attribute(alpha)").unwrap();
assert!(!kind_test(&kt, &xot, doc));
assert!(!kind_test(&kt, &xot, doc_el));
assert!(!kind_test(&kt, &xot, a));
assert!(kind_test(&kt, &xot, alpha));
assert!(!kind_test(&kt, &xot, beta));
assert!(!kind_test(&kt, &xot, text));
}
#[test]
fn test_kind_test_attribute_with_type_name() {
let mut xot = Xot::new();
let alpha = xot.add_name("alpha");
let beta = xot.add_name("beta");
let doc = xot
.parse(r#"<root><a alpha="Alpha" beta="Beta">text</a></root>"#)
.unwrap();
let doc_el = xot.document_element(doc).unwrap();
let a = xot.first_child(doc_el).unwrap();
let text = xot.first_child(a).unwrap();
let alpha = xot.attributes(a).get_node(alpha).unwrap();
let beta = xot.attributes(a).get_node(beta).unwrap();
let kt = parse_kind_test("attribute(alpha, xs:untypedAtomic)").unwrap();
assert!(!kind_test(&kt, &xot, doc));
assert!(!kind_test(&kt, &xot, doc_el));
assert!(!kind_test(&kt, &xot, a));
assert!(kind_test(&kt, &xot, alpha));
assert!(!kind_test(&kt, &xot, beta));
assert!(!kind_test(&kt, &xot, text));
let kt = parse_kind_test("attribute(alpha, xs:string)").unwrap();
assert!(!kind_test(&kt, &xot, alpha));
}
#[test]
fn test_kind_test_document_with_name() {
let mut xot = Xot::new();
let doc = xot.parse(r#"<root><a>text</a></root>"#).unwrap();
let doc_el = xot.document_element(doc).unwrap();
let a = xot.first_child(doc_el).unwrap();
let text = xot.first_child(a).unwrap();
let kt = parse_kind_test("document-node(element(root))").unwrap();
assert!(kind_test(&kt, &xot, doc));
assert!(!kind_test(&kt, &xot, doc_el));
assert!(!kind_test(&kt, &xot, a));
assert!(!kind_test(&kt, &xot, text));
let kt = parse_kind_test("document-node(element(a))").unwrap();
assert!(!kind_test(&kt, &xot, doc));
assert!(!kind_test(&kt, &xot, a));
}
}