sxd_document/
writer.rs

1//! Formats a DOM structure to a Write
2//!
3//! ### Example
4//! ```
5//! use sxd_document::Package;
6//! use sxd_document::writer::format_document;
7//!
8//! let package = Package::new();
9//! let doc = package.as_document();
10//!
11//! let hello = doc.create_element("hello");
12//! hello.set_attribute_value("planet", "Earth");
13//! doc.root().append_child(hello);
14//!
15//! let mut output = Vec::new();
16//! format_document(&doc, &mut output).expect("unable to output XML");
17//! ```
18//!
19//! ### Potential options to support
20//!
21//! - Space before `/>`
22//! - Single vs double quotes
23//! - Fixed ordering of attributes
24
25use std::borrow::ToOwned;
26use std::io::{self,Write};
27use std::slice;
28
29use self::Content::*;
30
31use super::QName;
32use super::str_ext::{SplitKeepingDelimiterExt,SplitType};
33
34
35use super::dom;
36use super::dom::{ChildOfElement,ChildOfRoot};
37use super::lazy_hash_map::LazyHashMap;
38
39trait WriteStr: Write {
40    fn write_str(&mut self, s: &str) -> io::Result<()> {
41        self.write_all(s.as_bytes())
42    }
43}
44
45impl<W: ?Sized> WriteStr for W where W: Write {}
46
47// TODO: Duplicating the String seems inefficient...
48struct PrefixScope<'d> {
49    ns_to_prefix: LazyHashMap<&'d str, String>,
50    prefix_to_ns: LazyHashMap<String, &'d str>,
51    defined_prefixes: Vec<(String, &'d str)>,
52    default_namespace_uri: Option<&'d str>,
53}
54
55impl<'d> PrefixScope<'d> {
56    fn new() -> PrefixScope<'d> {
57        PrefixScope {
58            ns_to_prefix: LazyHashMap::new(),
59            prefix_to_ns: LazyHashMap::new(),
60            defined_prefixes: Vec::new(),
61            default_namespace_uri: None,
62        }
63    }
64
65    fn has_prefix(&self, prefix: &str) -> bool {
66        self.prefix_to_ns.contains_key(prefix)
67    }
68
69    fn has_namespace_uri(&self, namespace_uri: &str) -> bool {
70        self.ns_to_prefix.contains_key(namespace_uri)
71    }
72
73    fn prefix_is(&self, prefix: &str, namespace_uri: &str) -> bool {
74        match self.prefix_to_ns.get(prefix) {
75            Some(ns) => *ns == namespace_uri,
76            _ => false,
77        }
78    }
79
80    fn namespace_uri_for(&self, prefix: &str) -> Option<&'d str> {
81        self.prefix_to_ns.get(prefix).map(|&ns| ns)
82    }
83
84    fn prefix_for(&self, namespace_uri: &str) -> Option<&str> {
85        self.ns_to_prefix.get(namespace_uri).map(|p| &p[..])
86    }
87
88    fn add_mapping(&mut self, prefix: &str, namespace_uri: &'d str) {
89        let prefix = prefix.to_owned();
90
91        self.prefix_to_ns.insert(prefix.clone(), namespace_uri);
92        self.ns_to_prefix.insert(namespace_uri, prefix);
93    }
94
95    fn define_prefix(&mut self, prefix: String, namespace_uri: &'d str) {
96        self.defined_prefixes.push((prefix, namespace_uri));
97    }
98}
99
100enum NamespaceType<'a> {
101    Default,
102    Prefix(&'a str),
103    Unknown,
104}
105
106struct PrefixMapping<'d> {
107    scopes: Vec<PrefixScope<'d>>,
108    generated_prefix_count: usize,
109}
110
111impl<'d> PrefixMapping<'d> {
112    fn new() -> PrefixMapping<'d> {
113        PrefixMapping {
114            scopes: vec![PrefixScope::new()],
115            generated_prefix_count: 0,
116        }
117    }
118
119    fn push_scope(&mut self) {
120        self.scopes.push(PrefixScope::new());
121    }
122
123    fn pop_scope(&mut self) {
124        self.scopes.pop();
125    }
126
127    fn active_default_namespace_uri(&self) -> Option<&'d str> {
128        self.scopes.iter().rev().filter_map(|s| s.default_namespace_uri).next()
129    }
130
131    fn active_namespace_uri_for_prefix(&self, prefix: &str) -> Option<&'d str> {
132        self.scopes.iter().rev().filter_map(|s| s.namespace_uri_for(prefix)).next()
133    }
134
135    fn default_namespace_uri_in_current_scope(&self) -> Option<&'d str> {
136        self.scopes.last().unwrap().default_namespace_uri
137    }
138
139    fn prefixes_in_current_scope(&self) -> slice::Iter<(String, &'d str)> {
140        self.scopes.last().unwrap().defined_prefixes.iter()
141    }
142
143    fn populate_scope(&mut self, element: &dom::Element<'d>, attributes: &[dom::Attribute<'d>]) {
144        self.scopes.last_mut().unwrap().default_namespace_uri = element.default_namespace_uri();
145
146        if let Some(prefix) = element.preferred_prefix() {
147            let name = element.name();
148            if let Some(uri) = name.namespace_uri {
149                self.set_prefix(prefix, uri);
150            }
151        }
152
153        for attribute in attributes.iter() {
154            if let Some(prefix) = attribute.preferred_prefix() {
155                let name = attribute.name();
156                if let Some(uri) = name.namespace_uri {
157                    self.set_prefix(prefix, uri);
158                }
159            }
160        }
161
162        let name = element.name();
163        if let Some(uri) = name.namespace_uri {
164            self.generate_prefix(uri);
165        }
166
167        for attribute in attributes.iter() {
168            let name = attribute.name();
169            if let Some(uri) = name.namespace_uri {
170                self.generate_prefix(uri);
171            }
172        }
173    }
174
175    fn set_prefix(&mut self, prefix: &str, namespace_uri: &'d str) {
176        let idx_of_last = self.scopes.len().saturating_sub(1);
177        let (parents, current_scope) = self.scopes.split_at_mut(idx_of_last);
178        let current_scope = &mut current_scope[0];
179
180        // If we're already using this prefix, we can't redefine it.
181        if current_scope.has_prefix(prefix) {
182            return;
183        }
184
185        // We are definitely going to use this prefix, claim it
186        current_scope.add_mapping(prefix, namespace_uri);
187
188        for parent_scope in parents.iter().rev() {
189            if parent_scope.prefix_is(prefix, namespace_uri) {
190                // A parent defines it as the URI we want.
191                // Prevent redefining it
192                return;
193            }
194        }
195
196        // Defined by us, must be added to the element
197        current_scope.define_prefix(prefix.to_owned(), namespace_uri);
198    }
199
200    fn generate_prefix(&mut self, namespace_uri: &'d str) {
201        if Some(namespace_uri) == self.active_default_namespace_uri() {
202            // We already map this namespace to the default
203            return;
204        }
205
206        let idx_of_last = self.scopes.len().saturating_sub(1);
207        let (parents, current_scope) = self.scopes.split_at_mut(idx_of_last);
208        let current_scope = &mut current_scope[0];
209
210        if current_scope.has_namespace_uri(namespace_uri) {
211            // We already map this namespace to *some* prefix
212            return;
213        }
214
215        // Check if the parent already defined a prefix for this ns
216        for parent_scope in parents.iter().rev() {
217            if let Some(prefix) = parent_scope.prefix_for(namespace_uri) {
218                // A parent happens to have a prefix for this URI.
219                // Prevent redefining it
220                current_scope.add_mapping(prefix, namespace_uri);
221                return;
222            }
223        }
224
225        loop {
226            let prefix = format!("autons{}", self.generated_prefix_count);
227            self.generated_prefix_count += 1;
228
229            if ! current_scope.has_prefix(&prefix) {
230                current_scope.add_mapping(&prefix, namespace_uri);
231                current_scope.define_prefix(prefix, namespace_uri);
232                break;
233            }
234        }
235    }
236
237    fn namespace_type<'a>(&'a self,
238                          preferred_prefix: Option<&'a str>,
239                          namespace_uri: &str,
240                          ignore_default: bool)
241                          -> NamespaceType<'a>
242    {
243        if !ignore_default && Some(namespace_uri) == self.active_default_namespace_uri() {
244            return NamespaceType::Default;
245        }
246
247        if let Some(prefix) = preferred_prefix {
248            if Some(namespace_uri) == self.active_namespace_uri_for_prefix(prefix) {
249                return NamespaceType::Prefix(prefix);
250            }
251        }
252
253        for scope in self.scopes.iter().rev() {
254            if let Some(prefix) = scope.prefix_for(namespace_uri) {
255                return NamespaceType::Prefix(prefix);
256            }
257        }
258
259        NamespaceType::Unknown
260    }
261}
262
263enum Content<'d> {
264    Element(dom::Element<'d>),
265    ElementEnd(dom::Element<'d>),
266    Text(dom::Text<'d>),
267    Comment(dom::Comment<'d>),
268    ProcessingInstruction(dom::ProcessingInstruction<'d>),
269}
270
271/// Write a document, specifying some formatting options
272///
273/// For example, the default is to use single-quotes for attributes. To use
274/// double quotes for attributes, you need to use `set_single_quotes(false)`.
275///
276/// ```
277/// use sxd_document::{Package, writer::Writer};
278///
279/// // Create a new document
280/// let p = Package::new();
281/// let doc = p.as_document();
282/// let el = doc.create_element("hello");
283/// el.set_attribute_value("a", "b");
284/// doc.root().append_child(el);
285///
286/// // Format the document as bytes
287/// let mut output = Vec::new();
288/// Writer::new().set_single_quotes(false).format_document(&doc, &mut output);
289///
290/// // Check that the output is correct
291/// let output_string = String::from_utf8(output).unwrap();
292/// assert_eq!(output_string, r#"<?xml version="1.0"?><hello a="b"/>"#);
293/// ```
294pub struct Writer {
295    single_quotes: bool,
296    write_encoding: bool,
297}
298
299impl Default for Writer {
300    fn default() -> Self {
301        Self {
302            single_quotes: true,
303            write_encoding: false,
304        }
305    }
306}
307
308impl Writer {
309    /// Create a new `Writer` with default settings.
310    pub fn new() -> Self {
311        Self::default()
312    }
313
314    /// Set whether single quotes should be used for writing a document.
315    pub fn set_single_quotes(mut self, single_quotes: bool) -> Self {
316        self.single_quotes = single_quotes;
317        self
318    }
319
320    /// Set whether the encoding should be specified in the output document header.
321    pub fn set_write_encoding(mut self, write_encoding: bool) -> Self {
322        self.write_encoding = write_encoding;
323        self
324    }
325
326    fn quote_char(&self) -> &'static str {
327        match self.single_quotes {
328            true => "'",
329            false => "\"",
330        }
331    }
332}
333
334impl Writer {
335    fn format_qname<'d, W: ?Sized>(&self,
336                                   q: QName<'d>,
337                                   mapping: &mut PrefixMapping<'d>,
338                                   preferred_prefix: Option<&str>,
339                                   ignore_default: bool,
340                                   writer: &mut W)
341                                   -> io::Result<()>
342        where W: Write
343    {
344        // Can something without a namespace be prefixed? No, because
345        // defining a prefix requires a non-empty URI
346        if let Some(namespace_uri) = q.namespace_uri {
347            match mapping.namespace_type(preferred_prefix, namespace_uri, ignore_default) {
348                NamespaceType::Default => {
349                    // No need to do anything
350                },
351                NamespaceType::Prefix(prefix) => {
352                    try!(writer.write_str(prefix));
353                    try!(writer.write_str(":"));
354                },
355                NamespaceType::Unknown => {
356                    panic!("No namespace prefix available for {}", namespace_uri);
357                },
358            }
359        }
360        writer.write_str(q.local_part)
361    }
362
363    fn format_attribute_value<W: ?Sized>(&self, value: &str, writer: &mut W) -> io::Result<()>
364        where W: Write
365    {
366        for item in value.split_keeping_delimiter(|c| c == '<' || c == '>' || c == '&' || c == '\'' || c == '"') {
367            match item {
368                SplitType::Match(t)        => try!(writer.write_str(t)),
369                SplitType::Delimiter("<")  => try!(writer.write_str("&lt;")),
370                SplitType::Delimiter(">")  => try!(writer.write_str("&gt;")),
371                SplitType::Delimiter("&")  => try!(writer.write_str("&amp;")),
372                SplitType::Delimiter("'")  => try!(writer.write_str("&apos;")),
373                SplitType::Delimiter("\"") => try!(writer.write_str("&quot;")),
374                SplitType::Delimiter(..)   => unreachable!(),
375            }
376        }
377        Ok(())
378    }
379
380    fn format_element<'d, W: ?Sized>(&self,
381                                     element: dom::Element<'d>,
382                                     todo: &mut Vec<Content<'d>>,
383                                     mapping: &mut PrefixMapping<'d>,
384                                     writer: &mut W)
385                                     -> io::Result<()>
386        where W: Write
387    {
388        let attrs = element.attributes();
389
390        mapping.populate_scope(&element, &attrs);
391
392        try!(writer.write_str("<"));
393        try!(self.format_qname(element.name(), mapping, element.preferred_prefix(), false, writer));
394
395        for attr in &attrs {
396            try!(writer.write_str(" "));
397            try!(self.format_qname(attr.name(), mapping, attr.preferred_prefix(), true, writer));
398            try!(write!(writer, "="));
399            try!(write!(writer, "{}", self.quote_char()));
400            try!(self.format_attribute_value(attr.value(), writer));
401            try!(write!(writer, "{}", self.quote_char()));
402        }
403
404        if let Some(ns_uri) = mapping.default_namespace_uri_in_current_scope() {
405            try!(writer.write_str(" xmlns='"));
406            try!(writer.write_str(ns_uri));
407            try!(writer.write_str("'"));
408        }
409
410        for &(ref prefix, ref ns_uri) in mapping.prefixes_in_current_scope() {
411            try!(writer.write_str(" xmlns:"));
412            try!(writer.write_str(prefix));
413            try!(write!(writer, "='{}'", ns_uri));
414        }
415
416        let mut children = element.children();
417        if children.is_empty() {
418            try!(writer.write_str("/>"));
419            mapping.pop_scope();
420            Ok(())
421        } else {
422            try!(writer.write_str(">"));
423
424            todo.push(ElementEnd(element));
425            children.reverse();
426            let x = children.into_iter().map(|c| match c {
427                ChildOfElement::Element(element)         => Element(element),
428                ChildOfElement::Text(t)                  => Text(t),
429                ChildOfElement::Comment(c)               => Comment(c),
430                ChildOfElement::ProcessingInstruction(p) => ProcessingInstruction(p),
431            });
432            todo.extend(x);
433
434            Ok(())
435        }
436    }
437
438    fn format_element_end<'d, W: ?Sized>(&self,
439                                         element: dom::Element<'d>,
440                                         mapping: &mut PrefixMapping<'d>,
441                                         writer: &mut W)
442                                         -> io::Result<()>
443        where W: Write
444    {
445        try!(writer.write_str("</"));
446        try!(self.format_qname(element.name(), mapping, element.preferred_prefix(), false, writer));
447        writer.write_str(">")
448    }
449
450    fn format_text<W: ?Sized>(&self, text: dom::Text, writer: &mut W) -> io::Result<()>
451        where W: Write
452    {
453        for item in text.text().split_keeping_delimiter(|c| c == '<' || c == '>' || c == '&') {
454            match item {
455                SplitType::Match(t)       => try!(writer.write_str(t)),
456                SplitType::Delimiter("<") => try!(writer.write_str("&lt;")),
457                SplitType::Delimiter(">") => try!(writer.write_str("&gt;")),
458                SplitType::Delimiter("&") => try!(writer.write_str("&amp;")),
459                SplitType::Delimiter(..)  => unreachable!(),
460            }
461        }
462        Ok(())
463    }
464
465    fn format_comment<W: ?Sized>(&self, comment: dom::Comment, writer: &mut W) -> io::Result<()>
466        where W: Write
467    {
468        write!(writer, "<!--{}-->", comment.text())
469    }
470
471    fn format_processing_instruction<W: ?Sized>(&self, pi: dom::ProcessingInstruction, writer: &mut W)
472                                                -> io::Result<()>
473        where W: Write
474    {
475        match pi.value() {
476            None    => write!(writer, "<?{}?>", pi.target()),
477            Some(v) => write!(writer, "<?{} {}?>", pi.target(), v),
478        }
479    }
480
481    fn format_one<'d, W: ?Sized>(&self,
482                                 content: Content<'d>,
483                                 todo: &mut Vec<Content<'d>>,
484                                 mapping: &mut PrefixMapping<'d>,
485                                 writer: &mut W)
486                                 -> io::Result<()>
487        where W: Write
488    {
489        match content {
490            Element(e) => {
491                mapping.push_scope();
492                self.format_element(e, todo, mapping, writer)
493            },
494            ElementEnd(e) => {
495                let r = self.format_element_end(e, mapping, writer);
496                mapping.pop_scope();
497                r
498            },
499            Text(t) => self.format_text(t, writer),
500            Comment(c) => self.format_comment(c, writer),
501            ProcessingInstruction(p) => self.format_processing_instruction(p, writer),
502        }
503    }
504
505    fn format_body<W: ?Sized>(&self, element: dom::Element, writer: &mut W) -> io::Result<()>
506        where W: Write
507    {
508        let mut todo = vec![Element(element)];
509        let mut mapping = PrefixMapping::new();
510
511        while ! todo.is_empty() {
512            try!(self.format_one(todo.pop().unwrap(), &mut todo, &mut mapping, writer));
513        }
514
515        Ok(())
516    }
517
518    fn format_declaration<'d, W: ?Sized>(&self, writer: &mut W) -> io::Result<()>
519        where W: Write
520    {
521        try!(write!(writer, "<?xml version={}1.0{}", self.quote_char(), self.quote_char()));
522
523        if self.write_encoding {
524            try!(write!(writer, " encoding={}UTF-8{}", self.quote_char(), self.quote_char()));
525        }
526
527        try!(write!(writer, "?>"));
528
529        Ok(())
530    }
531
532    /// Formats a document into a Write
533    pub fn format_document<'d, W: ?Sized>(&self, doc: &'d dom::Document<'d>, writer: &mut W) -> io::Result<()>
534        where W: Write
535    {
536        try!(self.format_declaration(writer));
537
538        for child in doc.root().children().into_iter() {
539            try!(match child {
540                ChildOfRoot::Element(e) => self.format_body(e, writer),
541                ChildOfRoot::Comment(c) => self.format_comment(c, writer),
542                ChildOfRoot::ProcessingInstruction(p) => self.format_processing_instruction(p, writer),
543            })
544        }
545
546        Ok(())
547    }
548}
549
550/// Formats a document into a `Write` using the default `Writer`
551pub fn format_document<'d, W: ?Sized>(doc: &'d dom::Document<'d>, writer: &mut W) -> io::Result<()>
552    where W: Write
553{
554    Writer::default().format_document(doc, writer)
555}
556
557#[cfg(test)]
558mod test {
559    use super::super::Package;
560    use super::super::dom;
561    use super::Writer;
562
563    fn format_xml<'d>(doc: &'d dom::Document<'d>) -> String {
564        format_xml_writer(Writer::default(), doc)
565    }
566
567    fn format_xml_writer<'d>(writer: Writer, doc: &'d dom::Document) -> String {
568        let mut w = Vec::new();
569        writer.format_document(doc, &mut w).expect("Not formatted");
570        String::from_utf8(w).expect("Not a string")
571    }
572
573    #[test]
574    fn top_element() {
575        let p = Package::new();
576        let d = p.as_document();
577        let e = d.create_element("hello");
578        d.root().append_child(e);
579
580        let xml = format_xml(&d);
581        assert_eq!(xml, "<?xml version='1.0'?><hello/>");
582    }
583
584    #[test]
585    fn element_with_namespace() {
586        let p = Package::new();
587        let d = p.as_document();
588        let e = d.create_element(("namespace", "local-part"));
589        d.root().append_child(e);
590
591        let xml = format_xml(&d);
592        assert_eq!(xml, "<?xml version='1.0'?><autons0:local-part xmlns:autons0='namespace'/>");
593    }
594
595    #[test]
596    fn element_with_default_namespace() {
597        let p = Package::new();
598        let d = p.as_document();
599        let e = d.create_element(("namespace", "local-part"));
600        e.set_default_namespace_uri(Some("namespace"));
601        d.root().append_child(e);
602
603        let xml = format_xml(&d);
604        assert_eq!(xml, "<?xml version='1.0'?><local-part xmlns='namespace'/>");
605    }
606
607    #[test]
608    fn element_with_preferred_namespace_prefix() {
609        let p = Package::new();
610        let d = p.as_document();
611        let e = d.create_element(("namespace", "local-part"));
612        e.set_preferred_prefix(Some("prefix"));
613        d.root().append_child(e);
614
615        let xml = format_xml(&d);
616        assert_eq!(xml, "<?xml version='1.0'?><prefix:local-part xmlns:prefix='namespace'/>");
617    }
618
619    #[test]
620    fn element_with_attributes() {
621        let p = Package::new();
622        let d = p.as_document();
623        let e = d.create_element("hello");
624        e.set_attribute_value("a", "b");
625        d.root().append_child(e);
626
627        let xml = format_xml(&d);
628        assert_eq!(xml, "<?xml version='1.0'?><hello a='b'/>");
629    }
630
631    #[test]
632    fn element_with_attributes_double_quotes() {
633        let p = Package::new();
634        let d = p.as_document();
635        let e = d.create_element("hello");
636        e.set_attribute_value("a", "b");
637        d.root().append_child(e);
638
639        let xml = format_xml_writer(Writer::new().set_single_quotes(false), &d);
640        assert_eq!(xml, r#"<?xml version="1.0"?><hello a="b"/>"#);
641    }
642
643
644    #[test]
645    fn attribute_with_namespace() {
646        let p = Package::new();
647        let d = p.as_document();
648        let e = d.create_element("hello");
649        e.set_attribute_value(("namespace", "a"), "b");
650        d.root().append_child(e);
651
652        let xml = format_xml(&d);
653        assert_eq!(xml, "<?xml version='1.0'?><hello autons0:a='b' xmlns:autons0='namespace'/>");
654    }
655
656    #[test]
657    fn attribute_with_preferred_namespace_prefix() {
658        let p = Package::new();
659        let d = p.as_document();
660        let e = d.create_element("hello");
661        let a = e.set_attribute_value(("namespace", "a"), "b");
662        a.set_preferred_prefix(Some("p"));
663        d.root().append_child(e);
664
665        let xml = format_xml(&d);
666        assert_eq!(xml, "<?xml version='1.0'?><hello p:a='b' xmlns:p='namespace'/>");
667    }
668
669    #[test]
670    fn attribute_with_default_namespace_prefix() {
671        let p = Package::new();
672        let d = p.as_document();
673        let e = d.create_element(("namespace", "hello"));
674        e.set_preferred_prefix(Some("p"));
675        e.set_default_namespace_uri(Some("namespace"));
676        e.set_attribute_value(("namespace", "a"), "b");
677        d.root().append_child(e);
678
679        let xml = format_xml(&d);
680        assert_eq!(xml, "<?xml version='1.0'?><hello p:a='b' xmlns='namespace' xmlns:p='namespace'/>");
681    }
682
683    #[test]
684    fn attributes_with_conflicting_preferred_namespace_prefixes() {
685        let p = Package::new();
686        let d = p.as_document();
687        let e = d.create_element("hello");
688
689        let a = e.set_attribute_value(("namespace1", "a1"), "b1");
690        a.set_preferred_prefix(Some("p"));
691
692        let a = e.set_attribute_value(("namespace2", "a2"), "b2");
693        a.set_preferred_prefix(Some("p"));
694
695        d.root().append_child(e);
696
697        let xml = format_xml(&d);
698        assert_eq!(xml, "<?xml version='1.0'?><hello p:a1='b1' autons0:a2='b2' xmlns:p='namespace1' xmlns:autons0='namespace2'/>");
699    }
700
701    #[test]
702    fn attributes_with_different_preferred_namespace_prefixes_for_same_namespace() {
703        let p = Package::new();
704        let d = p.as_document();
705        let e = d.create_element("hello");
706
707        let a = e.set_attribute_value(("namespace", "a1"), "b1");
708        a.set_preferred_prefix(Some("p1"));
709
710        let a = e.set_attribute_value(("namespace", "a2"), "b2");
711        a.set_preferred_prefix(Some("p2"));
712
713        d.root().append_child(e);
714
715        let xml = format_xml(&d);
716        assert_eq!(xml, "<?xml version='1.0'?><hello p1:a1='b1' p2:a2='b2' xmlns:p1='namespace' xmlns:p2='namespace'/>");
717    }
718
719    #[test]
720    fn attribute_values_with_less_than_greater_than_ampersand_apostrophe_or_quote_are_escaped() {
721        let p = Package::new();
722        let d = p.as_document();
723        let e = d.create_element("hello");
724        e.set_attribute_value("name", r#"'1 < 2' & "4 > 3""#);
725        d.root().append_child(e);
726
727        let xml = format_xml(&d);
728        assert_eq!(xml, "<?xml version='1.0'?><hello name='&apos;1 &lt; 2&apos; &amp; &quot;4 &gt; 3&quot;'/>");
729    }
730
731    #[test]
732    fn nested_element() {
733        let p = Package::new();
734        let d = p.as_document();
735        let hello = d.create_element("hello");
736        let world = d.create_element("world");
737        hello.append_child(world);
738        d.root().append_child(hello);
739
740        let xml = format_xml(&d);
741        assert_eq!(xml, "<?xml version='1.0'?><hello><world/></hello>");
742    }
743
744    #[test]
745    fn nested_element_with_namespaces() {
746        let p = Package::new();
747        let d = p.as_document();
748        let hello = d.create_element(("outer", "hello"));
749        let world = d.create_element(("inner", "world"));
750        hello.append_child(world);
751        d.root().append_child(hello);
752
753        let xml = format_xml(&d);
754        assert_eq!(xml, "<?xml version='1.0'?><autons0:hello xmlns:autons0='outer'><autons1:world xmlns:autons1='inner'/></autons0:hello>");
755    }
756
757    #[test]
758    fn nested_empty_element_with_namespaces() {
759        let p = Package::new();
760        let d = p.as_document();
761
762        let hello = d.create_element(("outer", "hello"));
763        hello.set_default_namespace_uri(Some("outer"));
764        hello.set_preferred_prefix(Some("o"));
765
766        let world = d.create_element("world");
767        world.set_default_namespace_uri(Some("inner"));
768
769        let empty = d.create_element("empty");
770        world.append_child(empty);
771        hello.append_child(world);
772        d.root().append_child(hello);
773
774        let xml = format_xml(&d);
775        assert_eq!(xml, "<?xml version='1.0'?><hello xmlns='outer' xmlns:o='outer'><world xmlns='inner'><empty/></world></hello>");
776    }
777
778    #[test]
779    fn nested_element_with_namespaces_with_reused_namespaces() {
780        let p = Package::new();
781        let d = p.as_document();
782        let hello = d.create_element(("ns", "hello"));
783        let world = d.create_element(("ns", "world"));
784        hello.append_child(world);
785        d.root().append_child(hello);
786
787        let xml = format_xml(&d);
788        assert_eq!(xml, "<?xml version='1.0'?><autons0:hello xmlns:autons0='ns'><autons0:world/></autons0:hello>");
789    }
790
791    #[test]
792    fn nested_element_with_with_conflicting_preferred_namespace_prefixes() {
793        let p = Package::new();
794        let d = p.as_document();
795        let hello = d.create_element(("outer", "hello"));
796        let world = d.create_element(("inner", "world"));
797        hello.set_preferred_prefix(Some("p"));
798        world.set_preferred_prefix(Some("p"));
799        hello.append_child(world);
800        d.root().append_child(hello);
801
802        let xml = format_xml(&d);
803        assert_eq!(xml, "<?xml version='1.0'?><p:hello xmlns:p='outer'><p:world xmlns:p='inner'/></p:hello>");
804    }
805
806    #[test]
807    fn nested_text() {
808        let p = Package::new();
809        let d = p.as_document();
810        let hello = d.create_element("hello");
811        let text = d.create_text("A fine day to you!");
812        hello.append_child(text);
813        d.root().append_child(hello);
814
815        let xml = format_xml(&d);
816        assert_eq!(xml, "<?xml version='1.0'?><hello>A fine day to you!</hello>");
817    }
818
819    #[test]
820    fn text_escapes_less_than_greater_than_and_ampersand() {
821        let p = Package::new();
822        let d = p.as_document();
823        let hello = d.create_element("escaped");
824        let text = d.create_text("1 < 3 & 4 > 2");
825        hello.append_child(text);
826        d.root().append_child(hello);
827
828        let xml = format_xml(&d);
829        assert_eq!(xml, "<?xml version='1.0'?><escaped>1 &lt; 3 &amp; 4 &gt; 2</escaped>");
830    }
831
832    #[test]
833    fn nested_comment() {
834        let p = Package::new();
835        let d = p.as_document();
836        let hello = d.create_element("hello");
837        let comment = d.create_comment(" Fill this in ");
838        hello.append_child(comment);
839        d.root().append_child(hello);
840
841        let xml = format_xml(&d);
842        assert_eq!(xml, "<?xml version='1.0'?><hello><!-- Fill this in --></hello>");
843    }
844
845    #[test]
846    fn nested_processing_instruction_without_value() {
847        let p = Package::new();
848        let d = p.as_document();
849        let hello = d.create_element("hello");
850        let pi = d.create_processing_instruction("display", None);
851        hello.append_child(pi);
852        d.root().append_child(hello);
853
854        let xml = format_xml(&d);
855        assert_eq!(xml, "<?xml version='1.0'?><hello><?display?></hello>");
856    }
857
858    #[test]
859    fn nested_processing_instruction_with_value() {
860        let p = Package::new();
861        let d = p.as_document();
862        let hello = d.create_element("hello");
863        let pi = d.create_processing_instruction("display", Some("screen"));
864        hello.append_child(pi);
865        d.root().append_child(hello);
866
867        let xml = format_xml(&d);
868        assert_eq!(xml, "<?xml version='1.0'?><hello><?display screen?></hello>");
869    }
870
871    #[test]
872    fn top_level_comment() {
873        let p = Package::new();
874        let d = p.as_document();
875        let comment = d.create_comment(" Fill this in ");
876        d.root().append_child(comment);
877
878        let xml = format_xml(&d);
879        assert_eq!(xml, "<?xml version='1.0'?><!-- Fill this in -->");
880    }
881
882    #[test]
883    fn top_level_processing_instruction() {
884        let p = Package::new();
885        let d = p.as_document();
886        let pi = d.create_processing_instruction("display", None);
887        d.root().append_child(pi);
888
889        let xml = format_xml(&d);
890        assert_eq!(xml, "<?xml version='1.0'?><?display?>");
891    }
892
893    #[test]
894    fn declaration_with_encoding() {
895        let p = Package::new();
896        let d = p.as_document();
897        let e = d.create_element("hello");
898        d.root().append_child(e);
899
900        let xml = format_xml_writer(Writer::new().set_write_encoding(true), &d);
901        assert_eq!(xml, "<?xml version='1.0' encoding='UTF-8'?><hello/>");
902    }
903
904    #[test]
905    fn declaration_with_encoding_and_double_quotes() {
906        let p = Package::new();
907        let d = p.as_document();
908        let e = d.create_element("hello");
909        d.root().append_child(e);
910
911        let xml = format_xml_writer(Writer::new()
912                                    .set_write_encoding(true)
913                                    .set_single_quotes(false), &d);
914        assert_eq!(xml, r#"<?xml version="1.0" encoding="UTF-8"?><hello/>"#);
915    }
916}