anyxml 0.15.1

A fully spec-conformant XML library
Documentation
use std::fmt::Write as _;

use anyxml::{
    error::XMLError,
    sax::{ParserOption, XMLReader},
    tree::{TreeBuildHandler, convert::NodeKind},
    uri::URIString,
    xpath::XPathObject,
};

#[test]
fn xpath_evaluation_tests() -> Result<(), XMLError> {
    let mut reader = XMLReader::builder()
        .set_handler(TreeBuildHandler::default())
        .enable_option(ParserOption::ExternalGeneralEntities)
        .build();
    reader.parse_uri(URIString::parse("resources/xpath/testsuite.xml")?, None)?;
    let document = reader.handler.document.clone();

    let test_cases = document.xpath("//test-cases")?.as_nodeset()?;

    for test_cases in test_cases.iter().map(|case| case.as_element().unwrap()) {
        let input_file = test_cases.xpath("./input-file[1]")?.as_nodeset()?[0].text_content();
        reader.parse_uri(URIString::parse(input_file.as_str())?, None)?;
        let document = reader.handler.document.clone();
        for test_case in test_cases.xpath("./test-case")?.as_nodeset()? {
            let xpath = test_case.xpath("./xpath[1]")?.as_nodeset()?[0].text_content();
            let output = test_case.xpath("./output[1]")?.as_nodeset()?[0].text_content();

            let mut buf = String::new();
            eprintln!("input_file: {input_file}, xpath: {xpath}");
            match document.xpath(&xpath).unwrap() {
                XPathObject::Boolean(boolean) => write!(buf, "{boolean},").unwrap(),
                XPathObject::Number(number) => write!(buf, "{number},").unwrap(),
                XPathObject::String(string) => write!(buf, "{string},").unwrap(),
                XPathObject::NodeSet(nodeset) => {
                    for node in &nodeset {
                        match node.downcast() {
                            NodeKind::Document(document) => {
                                let object = XPathObject::from(document);
                                write!(buf, "{},", object.as_string().unwrap()).unwrap()
                            }
                            NodeKind::Element(element) => {
                                let object = XPathObject::from(element);
                                write!(buf, "{},", object.as_string().unwrap()).unwrap()
                            }
                            NodeKind::Attribute(attribute) => {
                                let object = XPathObject::from(attribute);
                                write!(buf, "{},", object.as_string().unwrap()).unwrap()
                            }
                            NodeKind::Namespace(namespace) => {
                                let object = XPathObject::from(namespace);
                                write!(buf, "{},", object.as_string().unwrap()).unwrap()
                            }
                            NodeKind::ProcessingInstruction(pi) => {
                                let object = XPathObject::from(pi);
                                write!(buf, "{},", object.as_string().unwrap()).unwrap()
                            }
                            NodeKind::Comment(comment) => {
                                let object = XPathObject::from(comment);
                                write!(buf, "{},", object.as_string().unwrap()).unwrap()
                            }
                            NodeKind::Text(text) => {
                                let object = XPathObject::from(text);
                                write!(buf, "{},", object.as_string().unwrap()).unwrap()
                            }
                            NodeKind::CDATASection(cdata) => {
                                let object = XPathObject::from(cdata);
                                write!(buf, "{},", object.as_string().unwrap()).unwrap()
                            }
                            _ => unreachable!(),
                        }
                    }
                }
            }

            assert_eq!(
                buf, output,
                "\n--- input-file: {input_file} xpath: {xpath} ---\nbuf: {buf}\noutput:{output}"
            );
        }
    }

    Ok(())
}