Skip to main content

winprint_ext/ticket/document/
writer.rs

1use super::{NS_PSF, NS_XSI};
2use std::{borrow::Cow, io::Write};
3use xml::{
4    attribute::Attribute, name::OwnedName, namespace::Namespace, writer::XmlEvent, EmitterConfig,
5    EventWriter,
6};
7
8// mark document root
9impl XmlDocumentRoot for super::PrintCapabilitiesDocument {}
10impl XmlDocumentRoot for super::PrintTicketDocument {}
11
12/// A trait for serializing as XML element.
13pub trait XmlSerializer {
14    /// Collect the namespace URIs and prefixes used in the XML element.
15    fn collect_namespace(&self, ns: &mut Namespace);
16    /// Write the XML element to the writer.
17    fn write_to<W: Write>(&self, writer: &mut EventWriter<W>) -> Result<(), xml::writer::Error>;
18}
19
20/// A trait for serializing as XML document.
21pub trait XmlDocumentRoot: XmlSerializer {
22    /// Convert the struct to XML.
23    fn to_xml(&self) -> Vec<u8> {
24        let mut writer = EmitterConfig::new()
25            .perform_indent(false)
26            .create_writer(Vec::new());
27        let mut ns = Namespace::empty();
28        self.collect_namespace(&mut ns);
29        self.write_to(&mut writer).unwrap();
30        writer.into_inner()
31    }
32}
33
34impl XmlSerializer for super::PrintCapabilitiesDocument {
35    fn collect_namespace(&self, ns: &mut Namespace) {
36        ns.put("psf", NS_PSF);
37        self.properties.iter().for_each(|x| x.collect_namespace(ns));
38        self.parameter_defs
39            .iter()
40            .for_each(|x| x.collect_namespace(ns));
41        self.features.iter().for_each(|x| x.collect_namespace(ns));
42    }
43
44    fn write_to<W: Write>(&self, writer: &mut EventWriter<W>) -> Result<(), xml::writer::Error> {
45        {
46            let mut ns = Namespace::empty();
47            self.collect_namespace(&mut ns);
48            let event = XmlEvent::StartElement {
49                name: "psf:PrintCapabilities".into(),
50                attributes: Cow::Owned(vec![Attribute::new("version".into(), "1")]),
51                namespace: Cow::Owned(ns),
52            };
53            writer.write(event)?;
54        }
55        self.properties
56            .iter()
57            .try_for_each(|x| x.write_to(writer))?;
58        self.parameter_defs
59            .iter()
60            .try_for_each(|x| x.write_to(writer))?;
61        self.features.iter().try_for_each(|x| x.write_to(writer))?;
62        writer.write(XmlEvent::end_element())?;
63        Ok(())
64    }
65}
66
67impl XmlSerializer for super::PrintTicketDocument {
68    fn collect_namespace(&self, ns: &mut Namespace) {
69        ns.put("psf", NS_PSF);
70        self.properties.iter().for_each(|x| x.collect_namespace(ns));
71        self.parameter_inits
72            .iter()
73            .for_each(|x| x.collect_namespace(ns));
74        self.features.iter().for_each(|x| x.collect_namespace(ns));
75    }
76
77    fn write_to<W: Write>(&self, writer: &mut EventWriter<W>) -> Result<(), xml::writer::Error> {
78        {
79            let mut ns = Namespace::empty();
80            self.collect_namespace(&mut ns);
81            let event = XmlEvent::StartElement {
82                name: "psf:PrintTicket".into(),
83                attributes: Cow::Owned(vec![Attribute::new("version".into(), "1")]),
84                namespace: Cow::Owned(ns),
85            };
86            writer.write(event)?;
87        }
88        self.properties
89            .iter()
90            .try_for_each(|x| x.write_to(writer))?;
91        self.parameter_inits
92            .iter()
93            .try_for_each(|x| x.write_to(writer))?;
94        self.features.iter().try_for_each(|x| x.write_to(writer))?;
95        writer.write(XmlEvent::end_element())?;
96        Ok(())
97    }
98}
99
100impl XmlSerializer for super::PrintFeature {
101    fn collect_namespace(&self, ns: &mut Namespace) {
102        ns.put("psf", NS_PSF);
103        collect_namespace_from_name(&self.name, ns);
104        self.options.iter().for_each(|x| x.collect_namespace(ns));
105        self.properties.iter().for_each(|x| x.collect_namespace(ns));
106        self.features.iter().for_each(|x| x.collect_namespace(ns));
107    }
108
109    fn write_to<W: Write>(&self, writer: &mut EventWriter<W>) -> Result<(), xml::writer::Error> {
110        writer.write(
111            XmlEvent::start_element("psf:Feature").attr("name", format_name(&self.name).as_ref()),
112        )?;
113        self.options.iter().try_for_each(|x| x.write_to(writer))?;
114        self.properties
115            .iter()
116            .try_for_each(|x| x.write_to(writer))?;
117        self.features.iter().try_for_each(|x| x.write_to(writer))?;
118        writer.write(XmlEvent::end_element())?;
119        Ok(())
120    }
121}
122
123impl XmlSerializer for super::ParameterInit {
124    fn collect_namespace(&self, ns: &mut Namespace) {
125        ns.put("psf", NS_PSF);
126        collect_namespace_from_name(&self.name, ns);
127        self.value.collect_namespace(ns);
128    }
129
130    fn write_to<W: Write>(&self, writer: &mut EventWriter<W>) -> Result<(), xml::writer::Error> {
131        writer.write(
132            XmlEvent::start_element("psf:ParameterInit")
133                .attr("name", format_name(&self.name).as_ref()),
134        )?;
135        self.value.write_to(writer)?;
136        writer.write(XmlEvent::end_element())?;
137        Ok(())
138    }
139}
140
141impl XmlSerializer for super::ParameterDef {
142    fn collect_namespace(&self, ns: &mut Namespace) {
143        ns.put("psf", NS_PSF);
144        collect_namespace_from_name(&self.name, ns);
145        for x in &self.properties {
146            x.collect_namespace(ns);
147        }
148    }
149
150    fn write_to<W: Write>(&self, writer: &mut EventWriter<W>) -> Result<(), xml::writer::Error> {
151        writer.write(
152            XmlEvent::start_element("psf:ParameterDef")
153                .attr("name", format_name(&self.name).as_ref()),
154        )?;
155        for x in &self.properties {
156            x.write_to(writer)?;
157        }
158        writer.write(XmlEvent::end_element())?;
159        Ok(())
160    }
161}
162
163impl XmlSerializer for super::PrintFeatureOption {
164    fn collect_namespace(&self, ns: &mut Namespace) {
165        ns.put("psf", NS_PSF);
166        if let Some(name) = &self.name {
167            collect_namespace_from_name(name, ns);
168        }
169        self.scored_properties
170            .iter()
171            .for_each(|x| x.collect_namespace(ns));
172        self.properties.iter().for_each(|x| x.collect_namespace(ns));
173    }
174
175    fn write_to<W: Write>(&self, writer: &mut EventWriter<W>) -> Result<(), xml::writer::Error> {
176        start_element_with_optional_name(writer, "psf:Option", self.name.as_ref())?;
177        self.scored_properties
178            .iter()
179            .try_for_each(|x| x.write_to(writer))?;
180        self.properties
181            .iter()
182            .try_for_each(|x| x.write_to(writer))?;
183        writer.write(XmlEvent::end_element())?;
184        Ok(())
185    }
186}
187
188impl XmlSerializer for super::ScoredProperty {
189    fn collect_namespace(&self, ns: &mut Namespace) {
190        ns.put("psf", NS_PSF);
191        if let Some(name) = &self.name {
192            collect_namespace_from_name(name, ns);
193        }
194        if let Some(parameter_ref) = &self.parameter_ref {
195            collect_namespace_from_name(parameter_ref, ns);
196        }
197        if let Some(value) = &self.value {
198            value.collect_namespace(ns);
199        }
200        self.scored_properties
201            .iter()
202            .for_each(|x| x.collect_namespace(ns));
203        self.properties.iter().for_each(|x| x.collect_namespace(ns));
204    }
205
206    fn write_to<W: Write>(&self, writer: &mut EventWriter<W>) -> Result<(), xml::writer::Error> {
207        start_element_with_optional_name(writer, "psf:ScoredProperty", self.name.as_ref())?;
208        if let Some(parameter_ref) = &self.parameter_ref {
209            writer.write(
210                XmlEvent::start_element("psf:ParameterRef")
211                    .attr("name", format_name(parameter_ref).as_ref()),
212            )?;
213            writer.write(XmlEvent::end_element())?;
214        }
215        if let Some(value) = &self.value {
216            value.write_to(writer)?;
217        }
218        self.scored_properties
219            .iter()
220            .try_for_each(|x| x.write_to(writer))?;
221        self.properties
222            .iter()
223            .try_for_each(|x| x.write_to(writer))?;
224        writer.write(XmlEvent::end_element())?;
225        Ok(())
226    }
227}
228
229impl XmlSerializer for super::Property {
230    fn collect_namespace(&self, ns: &mut Namespace) {
231        ns.put("psf", NS_PSF);
232        collect_namespace_from_name(&self.name, ns);
233        if let Some(value) = &self.value {
234            value.collect_namespace(ns);
235        }
236        self.properties.iter().for_each(|x| x.collect_namespace(ns));
237    }
238
239    fn write_to<W: Write>(&self, writer: &mut EventWriter<W>) -> Result<(), xml::writer::Error> {
240        writer.write(
241            XmlEvent::start_element("psf:Property").attr("name", format_name(&self.name).as_ref()),
242        )?;
243        if let Some(value) = &self.value {
244            value.write_to(writer)?;
245        }
246        self.properties
247            .iter()
248            .try_for_each(|x| x.write_to(writer))?;
249        writer.write(XmlEvent::end_element())?;
250        Ok(())
251    }
252}
253
254impl XmlSerializer for super::PropertyValue {
255    fn collect_namespace(&self, ns: &mut Namespace) {
256        ns.put("psf", NS_PSF);
257        ns.put("xsi", NS_XSI);
258        collect_namespace_from_name(&self.xsi_type(), ns);
259    }
260
261    fn write_to<W: Write>(&self, writer: &mut EventWriter<W>) -> Result<(), xml::writer::Error> {
262        let xsi_type = self.xsi_type();
263        writer.write(
264            XmlEvent::start_element("psf:Value").attr("xsi:type", format_name(&xsi_type).as_ref()),
265        )?;
266        match self {
267            super::PropertyValue::String(s) => {
268                writer.write(XmlEvent::characters(s))?;
269            }
270            super::PropertyValue::Integer(i) => {
271                writer.write(XmlEvent::characters(&i.to_string()))?;
272            }
273            super::PropertyValue::QName(q) => {
274                writer.write(XmlEvent::characters(&q.to_string()))?;
275            }
276            super::PropertyValue::Unknown(_, s) => {
277                writer.write(XmlEvent::characters(s))?;
278            }
279        }
280        writer.write(XmlEvent::end_element())?;
281        Ok(())
282    }
283}
284
285fn collect_namespace_from_name(name: &OwnedName, ns: &mut Namespace) {
286    if let (Some(prefix), Some(namespace)) = (name.prefix_ref(), name.namespace_ref()) {
287        ns.put(prefix, namespace);
288    }
289}
290
291/// Format the name as a string, with the prefix if present. But no namespace URI.
292fn format_name(name: &OwnedName) -> Cow<'_, String> {
293    if let Some(prefix) = name.prefix_ref() {
294        Cow::Owned(format!("{}:{}", prefix, name.local_name))
295    } else {
296        Cow::Borrowed(&name.local_name)
297    }
298}
299
300fn start_element_with_optional_name<W: Write>(
301    writer: &mut EventWriter<W>,
302    elem_name: &str,
303    name: Option<&OwnedName>,
304) -> Result<(), xml::writer::Error> {
305    if let Some(name) = name {
306        writer
307            .write(XmlEvent::start_element(elem_name).attr("name", format_name(name).as_ref()))?;
308    } else {
309        writer.write(XmlEvent::start_element(elem_name))?;
310    }
311    Ok(())
312}
313
314#[cfg(test)]
315mod tests {
316    use super::XmlDocumentRoot;
317    use crate::ticket::document::{
318        reader::ParsableXmlDocument, PrintCapabilitiesDocument, PrintTicketDocument,
319    };
320
321    #[test]
322    fn serialize_for_print_ticket() {
323        let origin = include_bytes!("../../../test_data/print_ticket.xml");
324        let origin_document = PrintTicketDocument::parse_from_bytes(origin).unwrap();
325        let xml1 = origin_document.to_xml();
326        let document = PrintTicketDocument::parse_from_bytes(&xml1).unwrap();
327        let xml2 = document.to_xml();
328        assert_eq!(xml1, xml2);
329    }
330
331    #[test]
332    fn serialize_print_capabilities() {
333        let origin = include_bytes!("../../../test_data/print_capabilities.xml");
334        let origin_document = PrintCapabilitiesDocument::parse_from_bytes(origin).unwrap();
335        let xml1 = origin_document.to_xml();
336        let document = PrintCapabilitiesDocument::parse_from_bytes(&xml1).unwrap();
337        let xml2 = document.to_xml();
338        assert_eq!(xml1, xml2);
339    }
340}