Skip to main content

muffy_document/document/
node.rs

1use super::element::Element;
2use alloc::sync::Arc;
3use html5ever::{QualName, ns};
4use markup5ever_rcdom::NodeData;
5
6/// A node.
7#[derive(Debug, Eq, PartialEq)]
8pub enum Node {
9    /// An element.
10    Element(Element),
11    /// A text.
12    Text(String),
13}
14
15impl Node {
16    pub(crate) fn from_markup5ever(node: &markup5ever_rcdom::Node) -> Option<Self> {
17        match &node.data {
18            NodeData::Element { name, attrs, .. } => Some(Self::Element(
19                Element::new(
20                    qualify_name(name),
21                    attrs
22                        .borrow()
23                        .iter()
24                        // Namespace declarations on foreign elements are not
25                        // semantic attributes.
26                        .filter(|attribute| attribute.name.ns != ns!(xmlns))
27                        .map(|attribute| {
28                            (qualify_name(&attribute.name), attribute.value.to_string())
29                        })
30                        .collect(),
31                    node.children
32                        .borrow()
33                        .iter()
34                        .flat_map(|node| Self::from_markup5ever(node))
35                        .map(Arc::new)
36                        .collect(),
37                )
38                .set_namespace((!name.ns.is_empty()).then(|| name.ns.to_string())),
39            )),
40            NodeData::Text { contents } => Some(Self::Text(contents.borrow().to_string())),
41            NodeData::Comment { .. }
42            | NodeData::Document
43            | NodeData::Doctype { .. }
44            | NodeData::ProcessingInstruction { .. } => None,
45        }
46    }
47}
48
49fn qualify_name(name: &QualName) -> String {
50    if let Some(prefix) = &name.prefix {
51        format!("{prefix}:{}", name.local)
52    } else {
53        name.local.to_string()
54    }
55}