use genawaiter::rc::gen;
use genawaiter::yield_;
use crate::access::NodeEdge;
use crate::id::{NameId, NamespaceId, PrefixId};
use crate::xmlvalue::Element;
use crate::xmlvalue::Value;
use crate::xotdata::{Node, Xot};
#[derive(Debug, PartialEq)]
pub enum Output<'a> {
StartTagOpen(Element),
StartTagClose,
EndTag(Element),
Prefix(PrefixId, NamespaceId),
Attribute(NameId, &'a str),
Text(&'a str),
Comment(&'a str),
ProcessingInstruction(NameId, Option<&'a str>),
}
pub(crate) fn gen_outputs(xot: &Xot, node: Node) -> impl Iterator<Item = (Node, Output)> + '_ {
gen!({
for edge in xot.traverse(node) {
match edge {
NodeEdge::Start(current_node) => {
let gen = gen_edge_start(xot, node, current_node);
for output in gen {
yield_!((current_node, output));
}
}
NodeEdge::End(current_node) => {
let gen = gen_edge_end(xot, current_node);
for output in gen {
yield_!((current_node, output));
}
}
}
}
})
.into_iter()
}
fn gen_edge_start(xot: &Xot, top_node: Node, node: Node) -> impl Iterator<Item = Output> + '_ {
gen!({
let value = xot.value(node);
match value {
Value::Document => {}
Value::Element(element) => {
yield_!(Output::StartTagOpen(*element));
let namespaces = xot.namespaces(node);
if node == top_node {
for (prefix_id, namespace_id) in xot.namespaces_in_scope(node) {
if !namespaces.contains_key(prefix_id) {
yield_!(Output::Prefix(prefix_id, namespace_id,));
}
}
}
for (prefix_id, namespace_id) in namespaces.iter() {
yield_!(Output::Prefix(prefix_id, *namespace_id,));
}
for (name_id, value) in xot.attributes(node).iter() {
yield_!(Output::Attribute(name_id, value));
}
yield_!(Output::StartTagClose);
}
Value::Text(text) => {
yield_!(Output::Text(text.get()));
}
Value::Comment(comment) => {
yield_!(Output::Comment(comment.get()));
}
Value::ProcessingInstruction(pi) => {
yield_!(Output::ProcessingInstruction(pi.target(), pi.data()));
}
Value::Attribute(_) | Value::Namespace(_) => {
}
}
})
.into_iter()
}
fn gen_edge_end(xot: &Xot, node: Node) -> impl Iterator<Item = Output> + '_ {
gen!({
let value = xot.value(node);
if let Value::Element(element) = value {
yield_!(Output::EndTag(*element));
}
})
.into_iter()
}
pub struct OutputToken {
pub space: bool,
pub text: String,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_iter_mkgen() {
let mut xot = Xot::new();
let root = xot.parse(r#"<doc a="A">Text</doc>"#).unwrap();
let a_id = xot.add_name("a");
let doc = xot.document_element(root).unwrap();
let doc_el = xot.element(doc).unwrap();
let mut iter = gen_outputs(&xot, doc);
let v = iter.next().unwrap().1;
assert_eq!(v, Output::StartTagOpen(*doc_el));
let v = iter.next().unwrap().1;
assert_eq!(v, Output::Prefix(xot.xml_prefix(), xot.xml_namespace()));
let v = iter.next().unwrap().1;
assert_eq!(v, Output::Attribute(a_id, "A"));
let v = iter.next().unwrap().1;
assert_eq!(v, Output::StartTagClose);
let v = iter.next().unwrap().1;
assert_eq!(v, Output::Text("Text"));
let v = iter.next().unwrap().1;
assert_eq!(v, Output::EndTag(*doc_el));
assert!(iter.next().is_none());
}
}