bard/render/
xml.rs

1//! XML Renderer.
2
3use std::fs::File;
4use std::io;
5use std::io::Write;
6
7use super::Render;
8use super::RenderContext;
9use crate::app::App;
10use crate::prelude::*;
11use crate::ProgramMeta;
12
13use crate::project::Format;
14use crate::project::Output;
15use crate::util::xml_support::*;
16use crate::xml_write;
17
18xml_write!(struct ProgramMeta {
19    name,
20    version,
21    description,
22    homepage,
23    authors,
24} -> |w| {
25    w.tag("program")
26        .content()?
27        .field(name)?
28        .field(version)?
29        .field(description)?
30        .field(homepage)?
31        .field(authors)?
32});
33
34impl XmlWrite for Format {
35    fn write<W>(&self, mut writer: &mut Writer<W>) -> quick_xml::Result<()>
36    where
37        W: io::Write,
38    {
39        writer.write_text(self)
40    }
41}
42
43xml_write!(struct Output {
44    file,
45    template,
46    format,
47    toc_sort,
48    toc_sort_key,
49    sans_font,
50    font_size,
51    dpi,
52    tex_runs,
53    script,
54    book_overrides,
55} -> |w| {
56    let _ = file;
57    let _ = template;
58    let _ = book_overrides;
59    w.tag("output")
60        .content()?
61        .field_opt(format)?
62        .field(sans_font)?
63        .field(font_size)?
64        .field(toc_sort)?
65        .field(toc_sort_key)?
66        .field_opt(dpi)?
67        .field(tex_runs)?
68        .field_opt(script)?
69});
70
71xml_write!(struct RenderContext<'a> {
72    book,
73    songs,
74    songs_sorted,
75    notation,
76    output,
77    program,
78} -> |w| {
79    w.tag("songbook")
80        .attr(notation)
81        .content()?
82        .comment("The [book] section in bard.toml")?
83        .field(book)?
84        .comment("References to <song> elements in alphabetically-sorted order")?
85        .value_wrap("songs-sorted", songs_sorted)?
86        .comment("Fields in the [[output]] section in bard.toml")?
87        .value_wrap("output", output)?
88        .comment("Software metadata")?
89        .value(program)?
90        .comment("Song data")?
91        .field(songs)?
92});
93
94#[derive(Debug, Default)]
95pub struct RXml;
96
97impl RXml {
98    pub fn new() -> Self {
99        Self
100    }
101}
102
103impl Render for RXml {
104    fn render(&self, _app: &App, output: &Path, context: RenderContext) -> anyhow::Result<()> {
105        File::create(output)
106            .map_err(Error::from)
107            .and_then(|f| {
108                let mut writer = Writer::new_with_indent(f, b' ', 2);
109                context.write(&mut writer)?;
110
111                let mut f = writer.into_inner();
112                f.write_all(b"\n")?;
113                Ok(())
114            })
115            .with_context(|| format!("Error writing output file: {:?}", output))
116    }
117}