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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
//! Utilities to construct XML
//!
//! See [write_xml!](../macro.write_xml.html) for an example.

#[doc(hidden)]
pub use xml::writer::{EventWriter, Result, XmlEvent};
#[doc(hidden)]
pub use xml::EmitterConfig;
use std::io::Write;

#[doc(hidden)]
pub trait XmlEventWriter {
  fn write(&mut self, event: XmlEvent) -> Result<()>;
}

impl<W: Write> XmlEventWriter for EventWriter<W> {
  fn write(&mut self, event: XmlEvent) -> Result<()> {
    self.write(event)
  }
}

#[doc(hidden)]
pub trait XmlWrite<W: XmlEventWriter> {
  fn write_xml(&self, w: &mut W) -> Result<()>;
}

/// Writes to `XmlEventWriter`
///
/// # Example
/// ```
/// # extern crate xml;
/// # #[macro_use] extern crate xmlhelper;
/// # fn main() {
/// use xml::{EventWriter, EmitterConfig};
/// let mut writer =
///   EventWriter::new_with_config(vec![], EmitterConfig::new().perform_indent(true));
/// let context = vec!["context-value-0", "context-value-1"];
/// 
/// {
///   let w = &mut writer;
///   write_xml!(w,
///     Enevolop[Static="static-value", FromContext=context[0] ][
///       Header[FirstAttr="1", SecondAttr="2" ][]
///       Body[][
///         "Body Content"
///       ]
///       [{
///         write_xml!(w,
///           ContextItems[][
///             [{
///               for (i, v) in context.iter().enumerate() {
///                 let idx = i.to_string();
///                 write_xml!(w,
///                   Item[Index=(&idx)] [
///                     (*v)
///                   ]
///                 ).unwrap();
///               }
///               Ok(())
///             }]
///           ]
///         )
///       }]
///       Footer[][
///         (context[1])
///       ]
///     ]
///   ).unwrap();
/// }
/// let xml = String::from_utf8(writer.into_inner()).unwrap();
/// assert_eq!(
///   xml,
///   r#"<?xml version="1.0" encoding="utf-8"?>
/// <Enevolop Static="static-value" FromContext="context-value-0">
///   <Header FirstAttr="1" SecondAttr="2" />
///   <Body>Body Content</Body>
///   <ContextItems>
///     <Item Index="0">context-value-0</Item>
///     <Item Index="1">context-value-1</Item>
///   </ContextItems>
///   <Footer>context-value-1</Footer>
/// </Enevolop>"#
/// );
/// # }
/// ```
#[macro_export]
macro_rules! write_xml {
  ($w:expr, ) => (Ok(()));

  ($w:expr, [ $b:block ] $($rest:tt)*) => (
    $b.and_then(|_| write_xml!($w, $($rest)*))
  );

  ($w:expr, $e:tt) => ({
    let v: $crate::xmlhelper::encode::XmlCharactersRef = $e.into();
    let event: $crate::xmlhelper::encode::XmlEvent = v.into();
    $w.write(event)
  });

  ($w:expr,
    $tag_name:ident[$($attr_name:ident=$attr_value:expr),*][
      $($inner:tt)*
    ] $($rest:tt)*
  ) => ({
    let event = $crate::xmlhelper::encode::XmlEvent::start_element(stringify!($tag_name));
    $(
      let event = event.attr(stringify!($attr_name), $attr_value);
    )*
    let event: $crate::xmlhelper::encode::XmlEvent = event.into();
    $w.write(event)
      .and_then(|_| {
        write_xml!($w, $($inner)*)
      })
      .and_then(|_| {
        $w.write($crate::xmlhelper::encode::XmlEvent::EndElement { name: None })
      })
      .and_then(|_| {
        write_xml!($w, $($rest)*)
      })
  });
}

#[doc(hidden)]
pub struct XmlCharactersRef<'a>(&'a str);
impl<'a> From<&'a str> for XmlCharactersRef<'a> {
  fn from(v: &str) -> XmlCharactersRef {
    XmlCharactersRef(v)
  }
}
impl<'a> From<&'a String> for XmlCharactersRef<'a> {
  fn from(v: &String) -> XmlCharactersRef {
    XmlCharactersRef(v.as_ref())
  }
}
impl<'a> From<XmlCharactersRef<'a>> for XmlEvent<'a> {
  fn from(v: XmlCharactersRef) -> XmlEvent {
    XmlEvent::characters(v.0)
  }
}