exile/xdoc/
node.rs

1use std::io::Write;
2
3use crate::xdoc::cdata::write_cdata;
4use crate::xdoc::error::Result;
5use crate::xdoc::write_ops::write_element_text;
6use crate::{Element, Pi, WriteOpts};
7
8#[derive(Debug, Clone, Eq, PartialOrd, Ord, PartialEq, Hash)]
9/// Represents a Node in an XML Document. The Document consists of a recursive nesting of these.
10pub enum Node {
11    /// `<![CDATA[text]]>`
12    CData(String),
13
14    /// Comment, e.g. `<!--some comment-->`
15    Comment(String),
16
17    // TODO - support doctypes https://github.com/webern/exile/issues/22
18    /// `<!DOCTYPE doc>` - not implemented
19    DocType(String),
20
21    /// `<element/>`
22    Element(Element),
23
24    /// Processing Instruction, e.g. `<?target data?>`
25    Pi(Pi),
26
27    /// Text data in an element, i.e. `<x>hello &lt;</x>` where the `Text` is `hello <`.
28    Text(String),
29}
30
31impl Default for Node {
32    fn default() -> Self {
33        Node::Element(crate::Element::default())
34    }
35}
36
37impl Node {
38    /// Serialize the XML Document to a `Write` stream.
39    pub fn write<W>(&self, writer: &mut W, opts: &WriteOpts, depth: usize) -> Result<()>
40    where
41        W: Write,
42    {
43        match self {
44            Node::CData(cdata) => write_cdata(cdata, writer),
45            Node::Comment(comment) => write_comment(writer, opts, depth, comment),
46            Node::DocType(_) => panic!("doctypes unsupported"),
47            Node::Element(data) => data.write(writer, opts, depth),
48            Node::Pi(pi) => pi.write(writer, opts, depth),
49            Node::Text(s) => write_element_text(s.as_str(), writer, opts, depth),
50        }
51    }
52
53    /// Returns true if this node is either a Node::Text or a Node::CData.
54    pub fn is_text(&self) -> bool {
55        matches!(self, Node::Text(_) | Node::CData(_))
56    }
57}
58
59#[derive(Debug, Clone, Eq, PartialOrd, Ord, PartialEq, Hash)]
60// TODO - support Whitespace https://github.com/webern/exile/issues/55
61/// Represents a "Misc" entry, which is a Processing Instruction (PI), Comment, or Whitespace. These
62/// are the types of nodes allowed in the prologue and epilogue of an XML document.
63pub enum Misc {
64    // TODO - support comments https://github.com/webern/exile/issues/22
65    /// `<!-- comment -->` - not implemented
66    Comment(String),
67    /// ProcessingInstruction, e.g. `<?target whatever?>` - not implemented
68    Pi(crate::Pi),
69}
70
71impl Default for Misc {
72    fn default() -> Self {
73        Misc::Comment("".to_owned())
74    }
75}
76
77impl Misc {
78    /// Serialize the XML Document to a `Write` stream.
79    pub(crate) fn write<W>(&self, writer: &mut W, opts: &WriteOpts, depth: usize) -> Result<()>
80    where
81        W: Write,
82    {
83        match self {
84            Misc::Comment(comment) => write_comment(writer, opts, depth, comment),
85            Misc::Pi(pi) => pi.write(writer, opts, depth),
86        }
87    }
88}
89
90fn write_comment<W, S>(writer: &mut W, opts: &WriteOpts, depth: usize, comment: S) -> Result<()>
91where
92    W: Write,
93    S: AsRef<str>,
94{
95    opts.indent(writer, depth)?;
96    xwrite!(writer, "<!--{}-->", comment.as_ref())?;
97    Ok(())
98}