fast_xml/
lib.rs

1//! Please use [quick-xml]. This project was born as its successor, but [quick-xml]
2//! raised again.
3//!
4//! High performance XML reader/writer.
5//!
6//! ## Description
7//!
8//! fast-xml contains two modes of operation:
9//!
10//! A streaming API based on the [StAX] model. This is suited for larger XML documents which
11//! cannot completely read into memory at once.
12//!
13//! The user has to explicitly _ask_ for the next XML event, similar
14//! to a database cursor.
15//! This is achieved by the following two structs:
16//!
17//! - [`Reader`]: A low level XML pull-reader where buffer allocation/clearing is left to user.
18//! - [`Writer`]: A XML writer. Can be nested with readers if you want to transform XMLs.
19//!
20//! Especially for nested XML elements, the user must keep track _where_ (how deep) in the XML document
21//! the current event is located. This is needed as the
22//!
23//! Furthermore, fast-xml also contains optional [Serde] support to directly serialize and deserialize from
24//! structs, without having to deal with the XML events.
25//!
26//! ## Examples
27//!
28//! ### Reader
29//!
30//! ```rust
31//! use fast_xml::Reader;
32//! use fast_xml::events::Event;
33//!
34//! let xml = r#"<tag1 att1 = "test">
35//!                 <tag2><!--Test comment-->Test</tag2>
36//!                 <tag2>
37//!                     Test 2
38//!                 </tag2>
39//!             </tag1>"#;
40//!
41//! let mut reader = Reader::from_str(xml);
42//! reader.trim_text(true);
43//!
44//! let mut count = 0;
45//! let mut txt = Vec::new();
46//! let mut buf = Vec::new();
47//!
48//! // The `Reader` does not implement `Iterator` because it outputs borrowed data (`Cow`s)
49//! loop {
50//!     match reader.read_event(&mut buf) {
51//!     // for triggering namespaced events, use this instead:
52//!     // match reader.read_namespaced_event(&mut buf) {
53//!         Ok(Event::Start(ref e)) => {
54//!         // for namespaced:
55//!         // Ok((ref namespace_value, Event::Start(ref e)))
56//!             match e.name() {
57//!                 b"tag1" => println!("attributes values: {:?}",
58//!                                     e.attributes().map(|a| a.unwrap().value)
59//!                                     .collect::<Vec<_>>()),
60//!                 b"tag2" => count += 1,
61//!                 _ => (),
62//!             }
63//!         },
64//!         // unescape and decode the text event using the reader encoding
65//!         Ok(Event::Text(e)) => txt.push(e.unescape_and_decode(&reader).unwrap()),
66//!         Ok(Event::Eof) => break, // exits the loop when reaching end of file
67//!         Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
68//!         _ => (), // There are several other `Event`s we do not consider here
69//!     }
70//!
71//!     // if we don't keep a borrow elsewhere, we can clear the buffer to keep memory usage low
72//!     buf.clear();
73//! }
74//! ```
75//!
76//! ### Writer
77//!
78//! ```rust
79//! # use pretty_assertions::assert_eq;
80//! use fast_xml::Writer;
81//! use fast_xml::events::{Event, BytesEnd, BytesStart};
82//! use fast_xml::Reader;
83//! use std::io::Cursor;
84//! use std::iter;
85//!
86//! let xml = r#"<this_tag k1="v1" k2="v2"><child>text</child></this_tag>"#;
87//! let mut reader = Reader::from_str(xml);
88//! reader.trim_text(true);
89//! let mut writer = Writer::new(Cursor::new(Vec::new()));
90//! let mut buf = Vec::new();
91//! loop {
92//!     match reader.read_event(&mut buf) {
93//!         Ok(Event::Start(ref e)) if e.name() == b"this_tag" => {
94//!
95//!             // crates a new element ... alternatively we could reuse `e` by calling
96//!             // `e.into_owned()`
97//!             let mut elem = BytesStart::owned(b"my_elem".to_vec(), "my_elem".len());
98//!
99//!             // collect existing attributes
100//!             elem.extend_attributes(e.attributes().map(|attr| attr.unwrap()));
101//!
102//!             // copy existing attributes, adds a new my-key="some value" attribute
103//!             elem.push_attribute(("my-key", "some value"));
104//!
105//!             // writes the event to the writer
106//!             assert!(writer.write_event(Event::Start(elem)).is_ok());
107//!         },
108//!         Ok(Event::End(ref e)) if e.name() == b"this_tag" => {
109//!             assert!(writer.write_event(Event::End(BytesEnd::borrowed(b"my_elem"))).is_ok());
110//!         },
111//!         Ok(Event::Eof) => break,
112//!         Ok(e) => assert!(writer.write_event(e).is_ok()),
113//!         // or using the buffer
114//!         // Ok(e) => assert!(writer.write(&buf).is_ok()),
115//!         Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
116//!     }
117//!     buf.clear();
118//! }
119//!
120//! let result = writer.into_inner().into_inner();
121//! let expected = r#"<my_elem k1="v1" k2="v2" my-key="some value"><child>text</child></my_elem>"#;
122//! assert_eq!(result, expected.as_bytes());
123//! ```
124//!
125//! # Features
126//!
127//! `fast-xml` supports the following features:
128//!
129//! [StAX]: https://en.wikipedia.org/wiki/StAX
130//! [Serde]: https://serde.rs/
131//! [quick-xml]: https://github.com/tafia/quick-xml
132#![cfg_attr(
133    feature = "document-features",
134    cfg_attr(doc, doc = ::document_features::document_features!())
135)]
136#![forbid(unsafe_code)]
137#![deny(missing_docs)]
138#![recursion_limit = "1024"]
139
140#[cfg(feature = "serialize")]
141pub mod de;
142mod errors;
143mod escapei;
144pub mod escape {
145    //! Manage xml character escapes
146    pub(crate) use crate::escapei::{do_unescape, EscapeError};
147    pub use crate::escapei::{escape, partial_escape, unescape, unescape_with};
148}
149pub mod events;
150mod reader;
151#[cfg(feature = "serialize")]
152pub mod se;
153/// Not an official API, public for integration tests
154#[doc(hidden)]
155pub mod utils;
156mod writer;
157
158// reexports
159#[cfg(feature = "serialize")]
160pub use crate::errors::serialize::DeError;
161pub use crate::errors::{Error, Result};
162pub use crate::reader::Reader;
163pub use crate::writer::{ElementWriter, Writer};