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