1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
//! Macro simplification for emitting XML.

#[allow(unused_imports)]
use xml::writer::XmlEvent;

/// Write [`XmlEvent`]s to the supplied writer.
///
/// The first argument to the macro is always the writer object.
/// When writing elements, the second argument is the tag name, followed by an
/// optional list of `attr: "value"` pairs, separated by commas.
///
/// If the content of the element is just text, the above will be followed by a `;`
/// and an expression giving the text.
///
/// If the content is more XML, the start definition will be followed by `=>` and
/// a block. The block contains further XML writing code must return a [`Result`];
///
/// If you want to just send text to the XML, the only thing following the writer
/// should be a `;` and and expression giving the text.
///
/// ## Examples
///
/// ```rust, no_run
/// # use std::fs::File;
/// use xml::writer::{EmitterConfig, XmlEvent};
/// use timelog::emit_xml;
/// use timelog::Result;
///
/// # fn main() -> Result<()> {
/// let mut file = File::create("output.html").expect("Can't open file");
/// let mut w = EmitterConfig::new()
///     .perform_indent(true)
///     .write_document_declaration(false)
///     .create_writer(&mut file);
///
///     emit_xml!(w, html => {
///         emit_xml!(w, head => {
///             emit_xml!(w, title; "This is the page")
///         })?;
///         emit_xml!(w, body => {
///             emit_xml!(w, div, class: "group" => {
///                 emit_xml!(w, h1; &format!("Page for {}", "me"))?;
///                 emit_xml!(w, p, class: "stuff"; "Useless text")?;
///                 emit_xml!(w, br)
///             })?;
///             emit_xml!(w, p => {
///                 emit_xml!(w; "This is some random text.")?;
///                 emit_xml!(w, em; "That is part of more formatted text.")
///             })
///         })
///     })?;
///
/// # Ok(())
/// # }
/// ```
#[macro_export]
macro_rules! emit_xml {
    ($target:expr; $text:expr) => {
        {
            $target.write(XmlEvent::from(XmlEvent::characters($text)))?;
            crate::Result::Ok(())
        }
    };
    ($target:expr, $tag:ident; $text:expr) => {
        {
            $target.write(XmlEvent::from(XmlEvent::start_element(stringify!($tag))))?;
            $target.write(XmlEvent::from(XmlEvent::characters($text)))?;
            $target.write(XmlEvent::from(XmlEvent::end_element().name(stringify!($tag))))?;
            crate::Result::Ok(())
        }
    };
    ($target:expr, $tag:ident, $($attr:ident: $val:expr),+; $text:expr) => {
        {
            $target.write(XmlEvent::from(XmlEvent::start_element(stringify!($tag))
                $(
                    .attr(stringify!($attr), $val)
                )+
            ))?;
            $target.write(XmlEvent::from(XmlEvent::characters($text)))?;
            $target.write(XmlEvent::from(XmlEvent::end_element().name(stringify!($tag))))?;
            crate::Result::Ok(())
        }
    };
    ($target:expr, $tag:ident => $block:block) => {
        {
            $target.write(XmlEvent::from(XmlEvent::start_element(stringify!($tag))))?;
            $block?;
            $target.write(XmlEvent::from(XmlEvent::end_element().name(stringify!($tag))))?;
            crate::Result::Ok(())
        }
    };
    ($target:expr, $tag:ident, $($attr:ident: $val:expr),+ => $block:block) => {
        {
            $target.write(XmlEvent::from(XmlEvent::start_element(stringify!($tag))
                $(
                    .attr(stringify!($attr), $val)
                )+
            ))?;
            let result: crate::Result<()> = $block;
            result?;
            $target.write(XmlEvent::from(XmlEvent::end_element().name(stringify!($tag))))?;
            crate::Result::Ok(())
        }
    };
    ($target:expr, $tag:ident) => {
        {
            $target.write(XmlEvent::from(XmlEvent::start_element(stringify!($tag))))?;
            $target.write(XmlEvent::from(XmlEvent::end_element().name(stringify!($tag))))?;
            crate::Result::Ok(())
        }
    };
    ($target:expr, $tag:ident, $($attr:ident: $val:expr),+) => {
        {
            $target.write(XmlEvent::from(XmlEvent::start_element(stringify!($tag))
                $(
                    .attr(stringify!($attr), $val)
                )+
            ))?;
            $target.write(XmlEvent::from(XmlEvent::end_element().name(stringify!($tag))))?;
            crate::Result::Ok(())
        }
    };
}