• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

.github/workflows/H03-May-2022-3225

src/H03-May-2022-5,2113,523

tests/H03-May-2022-1,055909

.cargo-checksum.jsonH A D03-May-202289 11

.cargo_vcs_info.jsonH A D01-Jan-197074 65

.gitignoreH A D01-Jan-197053 88

Cargo.lockH A D01-Jan-1970591 2420

Cargo.tomlH A D01-Jan-19701 KiB3732

Cargo.toml.orig-cargoH A D01-Jan-1970487 2420

Changelog.mdH A D01-Jan-19703.7 KiB12775

LICENSEH A D01-Jan-19701.1 KiB2217

Readme.mdH A D01-Jan-19708.3 KiB237180

design.mdH A D01-Jan-19701.3 KiB3831

Readme.md

1xml-rs, an XML library for Rust
2===============================
3
4[![Build Status][build-status-img]](https://github.com/netvl/xml-rs/actions?query=workflow%3ACI)
5[![crates.io][crates-io-img]](https://crates.io/crates/xml-rs)
6[![docs][docs-img]](https://docs.rs/xml-rs/)
7
8[Documentation](https://docs.rs/xml-rs/)
9
10  [build-status-img]: https://img.shields.io/github/workflow/status/netvl/xml-rs/CI/master?style=flat-square
11  [crates-io-img]: https://img.shields.io/crates/v/xml-rs.svg?style=flat-square
12  [docs-img]: https://img.shields.io/badge/docs-latest%20release-6495ed.svg?style=flat-square
13
14xml-rs is an XML library for [Rust](http://www.rust-lang.org/) programming language.
15It is heavily inspired by Java [Streaming API for XML (StAX)][stax].
16
17  [stax]: https://en.wikipedia.org/wiki/StAX
18
19This library currently contains pull parser much like [StAX event reader][stax-reader].
20It provides iterator API, so you can leverage Rust's existing iterators library features.
21
22  [stax-reader]: http://docs.oracle.com/javase/8/docs/api/javax/xml/stream/XMLEventReader.html
23
24It also provides a streaming document writer much like [StAX event writer][stax-writer].
25This writer consumes its own set of events, but reader events can be converted to
26writer events easily, and so it is possible to write XML transformation chains in a pretty
27clean manner.
28
29  [stax-writer]: http://docs.oracle.com/javase/8/docs/api/javax/xml/stream/XMLEventWriter.html
30
31This parser is mostly full-featured, however, there are limitations:
32* no other encodings but UTF-8 are supported yet, because no stream-based encoding library
33  is available now; when (or if) one will be available, I'll try to make use of it;
34* DTD validation is not supported, `<!DOCTYPE>` declarations are completely ignored; thus no
35  support for custom entities too; internal DTD declarations are likely to cause parsing errors;
36* attribute value normalization is not performed, and end-of-line characters are not normalized too.
37
38Other than that the parser tries to be mostly XML-1.0-compliant.
39
40Writer is also mostly full-featured with the following limitations:
41* no support for encodings other than UTF-8, for the same reason as above;
42* no support for emitting `<!DOCTYPE>` declarations;
43* more validations of input are needed, for example, checking that namespace prefixes are bounded
44  or comments are well-formed.
45
46What is planned (highest priority first, approximately):
47
480. missing features required by XML standard (e.g. aforementioned normalization and
49   proper DTD parsing);
501. miscellaneous features of the writer;
512. parsing into a DOM tree and its serialization back to XML text;
523. SAX-like callback-based parser (fairly easy to implement over pull parser);
534. DTD validation;
545. (let's dream a bit) XML Schema validation.
55
56Building and using
57------------------
58
59xml-rs uses [Cargo](http://crates.io), so just add a dependency section in your project's manifest:
60
61```toml
62[dependencies]
63xml-rs = "0.8"
64```
65
66The package exposes a single crate called `xml`:
67
68```rust
69extern crate xml;
70```
71
72Reading XML documents
73---------------------
74
75`xml::reader::EventReader` requires a `Read` instance to read from. When a proper stream-based encoding
76library is available, it is likely that xml-rs will be switched to use whatever character stream structure
77this library would provide, but currently it is a `Read`.
78
79Using `EventReader` is very straightforward. Just provide a `Read` instance to obtain an iterator
80over events:
81
82```rust,no_run
83extern crate xml;
84
85use std::fs::File;
86use std::io::BufReader;
87
88use xml::reader::{EventReader, XmlEvent};
89
90fn indent(size: usize) -> String {
91    const INDENT: &'static str = "    ";
92    (0..size).map(|_| INDENT)
93             .fold(String::with_capacity(size*INDENT.len()), |r, s| r + s)
94}
95
96fn main() {
97    let file = File::open("file.xml").unwrap();
98    let file = BufReader::new(file);
99
100    let parser = EventReader::new(file);
101    let mut depth = 0;
102    for e in parser {
103        match e {
104            Ok(XmlEvent::StartElement { name, .. }) => {
105                println!("{}+{}", indent(depth), name);
106                depth += 1;
107            }
108            Ok(XmlEvent::EndElement { name }) => {
109                depth -= 1;
110                println!("{}-{}", indent(depth), name);
111            }
112            Err(e) => {
113                println!("Error: {}", e);
114                break;
115            }
116            _ => {}
117        }
118    }
119}
120```
121
122`EventReader` implements `IntoIterator` trait, so you can just use it in a `for` loop directly.
123Document parsing can end normally or with an error. Regardless of exact cause, the parsing
124process will be stopped, and iterator will terminate normally.
125
126You can also have finer control over when to pull the next event from the parser using its own
127`next()` method:
128
129```rust,ignore
130match parser.next() {
131    ...
132}
133```
134
135Upon the end of the document or an error the parser will remember that last event and will always
136return it in the result of `next()` call afterwards. If iterator is used, then it will yield
137error or end-of-document event once and will produce `None` afterwards.
138
139It is also possible to tweak parsing process a little using `xml::reader::ParserConfig` structure.
140See its documentation for more information and examples.
141
142You can find a more extensive example of using `EventReader` in `src/analyze.rs`, which is a
143small program (BTW, it is built with `cargo build` and can be run after that) which shows various
144statistics about specified XML document. It can also be used to check for well-formedness of
145XML documents - if a document is not well-formed, this program will exit with an error.
146
147Writing XML documents
148---------------------
149
150xml-rs also provides a streaming writer much like StAX event writer. With it you can write an
151XML document to any `Write` implementor.
152
153```rust,no_run
154extern crate xml;
155
156use std::fs::File;
157use std::io::{self, Write};
158
159use xml::writer::{EventWriter, EmitterConfig, XmlEvent, Result};
160
161fn handle_event<W: Write>(w: &mut EventWriter<W>, line: String) -> Result<()> {
162    let line = line.trim();
163    let event: XmlEvent = if line.starts_with("+") && line.len() > 1 {
164        XmlEvent::start_element(&line[1..]).into()
165    } else if line.starts_with("-") {
166        XmlEvent::end_element().into()
167    } else {
168        XmlEvent::characters(&line).into()
169    };
170    w.write(event)
171}
172
173fn main() {
174    let mut file = File::create("output.xml").unwrap();
175
176    let mut input = io::stdin();
177    let mut output = io::stdout();
178    let mut writer = EmitterConfig::new().perform_indent(true).create_writer(&mut file);
179    loop {
180        print!("> "); output.flush().unwrap();
181        let mut line = String::new();
182        match input.read_line(&mut line) {
183            Ok(0) => break,
184            Ok(_) => match handle_event(&mut writer, line) {
185                Ok(_) => {}
186                Err(e) => panic!("Write error: {}", e)
187            },
188            Err(e) => panic!("Input error: {}", e)
189        }
190    }
191}
192```
193
194The code example above also demonstrates how to create a writer out of its configuration.
195Similar thing also works with `EventReader`.
196
197The library provides an XML event building DSL which helps to construct complex events,
198e.g. ones having namespace definitions. Some examples:
199
200```rust,ignore
201// <a:hello a:param="value" xmlns:a="urn:some:document">
202XmlEvent::start_element("a:hello").attr("a:param", "value").ns("a", "urn:some:document")
203
204// <hello b:config="name" xmlns="urn:default:uri">
205XmlEvent::start_element("hello").attr("b:config", "value").default_ns("urn:defaul:uri")
206
207// <![CDATA[some unescaped text]]>
208XmlEvent::cdata("some unescaped text")
209```
210
211Of course, one can create `XmlEvent` enum variants directly instead of using the builder DSL.
212There are more examples in `xml::writer::XmlEvent` documentation.
213
214The writer has multiple configuration options; see `EmitterConfig` documentation for more
215information.
216
217Other things
218------------
219
220No performance tests or measurements are done. The implementation is rather naive, and no specific
221optimizations are made. Hopefully the library is sufficiently fast to process documents of common size.
222I intend to add benchmarks in future, but not until more important features are added.
223
224Known issues
225------------
226
227All known issues are present on GitHub issue tracker: <http://github.com/netvl/xml-rs/issues>.
228Feel free to post any found problems there.
229
230License
231-------
232
233This library is licensed under MIT license.
234
235---
236Copyright (C) Vladimir Matveev, 2014-2020
237