1 #![forbid(unsafe_code)]
2
3 use std::cmp;
4 use std::collections::HashSet;
5 use std::env;
6 use std::fs::File;
7 use std::io::{self, BufReader, Read};
8
9 use xml::reader::XmlEvent;
10 use xml::ParserConfig;
11
main() -> Result<(), Box<dyn std::error::Error>>12 fn main() -> Result<(), Box<dyn std::error::Error>> {
13 let mut file;
14 let mut stdin;
15 let source: &mut dyn Read = if let Some(file_name) = env::args().nth(1) {
16 file = File::open(file_name).map_err(|e| format!("Cannot open input file: {e}"))?;
17 &mut file
18 } else {
19 stdin = io::stdin();
20 &mut stdin
21 };
22
23 let reader = ParserConfig::new()
24 .whitespace_to_characters(true)
25 .ignore_comments(false)
26 .create_reader(BufReader::new(source));
27
28 let mut processing_instructions = 0;
29 let mut elements = 0;
30 let mut character_blocks = 0;
31 let mut cdata_blocks = 0;
32 let mut characters = 0;
33 let mut comment_blocks = 0;
34 let mut comment_characters = 0;
35 let mut namespaces = HashSet::new();
36 let mut depth = 0;
37 let mut max_depth = 0;
38
39 for e in reader {
40 let e = e.map_err(|e| format!("Error parsing XML document: {e}"))?;
41 match e {
42 XmlEvent::StartDocument { version, encoding, standalone } =>
43 println!(
44 "XML document version {}, encoded in {}, {}standalone",
45 version, encoding, if standalone.unwrap_or(false) { "" } else { "not " }
46 ),
47 XmlEvent::EndDocument => println!("Document finished"),
48 XmlEvent::ProcessingInstruction { .. } => processing_instructions += 1,
49 XmlEvent::Whitespace(_) => {} // can't happen due to configuration
50 XmlEvent::Characters(s) => {
51 character_blocks += 1;
52 characters += s.len();
53 }
54 XmlEvent::CData(s) => {
55 cdata_blocks += 1;
56 characters += s.len();
57 }
58 XmlEvent::Comment(s) => {
59 comment_blocks += 1;
60 comment_characters += s.len();
61 }
62 XmlEvent::StartElement { namespace, .. } => {
63 depth += 1;
64 max_depth = cmp::max(max_depth, depth);
65 elements += 1;
66 namespaces.extend(namespace.0.into_values());
67 }
68 XmlEvent::EndElement { .. } => {
69 depth -= 1;
70 }
71 };
72 }
73
74 namespaces.remove(xml::namespace::NS_EMPTY_URI);
75 namespaces.remove(xml::namespace::NS_XMLNS_URI);
76 namespaces.remove(xml::namespace::NS_XML_URI);
77
78 println!("Elements: {elements}, maximum depth: {max_depth}");
79 println!("Namespaces (excluding built-in): {}", namespaces.len());
80 println!("Characters: {characters}, characters blocks: {character_blocks}, CDATA blocks: {cdata_blocks}");
81 println!("Comment blocks: {comment_blocks}, comment characters: {comment_characters}");
82 println!("Processing instructions (excluding built-in): {processing_instructions}");
83
84 Ok(())
85 }
86