muffy_document/document/
node.rs1use super::element::Element;
2use alloc::sync::Arc;
3use html5ever::{QualName, ns};
4use markup5ever_rcdom::NodeData;
5
6const DEFAULT_NAMESPACES: &[&str] = &[
8 "",
9 "http://www.w3.org/1998/Math/MathML",
10 "http://www.w3.org/1999/xhtml",
11 "http://www.w3.org/2000/svg",
12];
13const NAMESPACE_PREFIXES: &[(&str, &str)] = &[
14 ("http://creativecommons.org/ns#", "cc"),
15 ("http://purl.org/dc/elements/1.1/", "dc"),
16 (
17 "http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd",
18 "sodipodi",
19 ),
20 ("http://www.inkscape.org/namespaces/inkscape", "inkscape"),
21 ("http://www.w3.org/1999/02/22-rdf-syntax-ns#", "rdf"),
22 ("http://www.w3.org/1999/xlink", "xlink"),
23 ("http://www.w3.org/XML/1998/namespace", "xml"),
24];
25
26#[derive(Debug, Eq, PartialEq)]
28pub enum Node {
29 Element(Element),
31 Text(String),
33}
34
35impl Node {
36 pub(crate) fn from_markup5ever(node: &markup5ever_rcdom::Node) -> Option<Self> {
37 match &node.data {
38 NodeData::Element { name, attrs, .. } => Some(Self::Element(
39 Element::new(
40 qualify_name(name),
41 attrs
42 .borrow()
43 .iter()
44 .filter(|attribute| attribute.name.ns != ns!(xmlns))
47 .map(|attribute| {
48 (qualify_name(&attribute.name), attribute.value.to_string())
49 })
50 .collect(),
51 node.children
52 .borrow()
53 .iter()
54 .flat_map(|node| Self::from_markup5ever(node))
55 .map(Arc::new)
56 .collect(),
57 )
58 .set_namespace((!name.ns.is_empty()).then(|| name.ns.to_string())),
59 )),
60 NodeData::Text { contents } => Some(Self::Text(contents.borrow().to_string())),
61 NodeData::Comment { .. }
62 | NodeData::Document
63 | NodeData::Doctype { .. }
64 | NodeData::ProcessingInstruction { .. } => None,
65 }
66 }
67}
68
69fn qualify_name(name: &QualName) -> String {
70 if let Some(prefix) = NAMESPACE_PREFIXES
71 .iter()
72 .find_map(|(namespace, prefix)| (*name.ns == **namespace).then_some(prefix))
73 {
74 format!("{prefix}:{}", name.local)
75 } else if DEFAULT_NAMESPACES.contains(&&*name.ns) {
76 name.local.to_string()
77 } else if let Some(prefix) = &name.prefix {
78 format!("{prefix}:{}", name.local)
79 } else {
80 name.local.to_string()
81 }
82}