#![forbid(unsafe_code)] extern crate xml; use std::cmp; use std::env; use std::io::{self, Read, Write, BufReader}; use std::fs::File; use std::collections::HashSet; use xml::ParserConfig; use xml::reader::XmlEvent; macro_rules! abort { ($code:expr) => {::std::process::exit($code)}; ($code:expr, $($args:tt)+) => {{ writeln!(&mut ::std::io::stderr(), $($args)+).unwrap(); ::std::process::exit($code); }} } fn main() { let mut file; let mut stdin; let source: &mut Read = match env::args().nth(1) { Some(file_name) => { file = File::open(file_name) .unwrap_or_else(|e| abort!(1, "Cannot open input file: {}", e)); &mut file } None => { stdin = io::stdin(); &mut stdin } }; let reader = ParserConfig::new() .whitespace_to_characters(true) .ignore_comments(false) .create_reader(BufReader::new(source)); let mut processing_instructions = 0; let mut elements = 0; let mut character_blocks = 0; let mut cdata_blocks = 0; let mut characters = 0; let mut comment_blocks = 0; let mut comment_characters = 0; let mut namespaces = HashSet::new(); let mut depth = 0; let mut max_depth = 0; for e in reader { match e { Ok(e) => match e { XmlEvent::StartDocument { version, encoding, standalone } => println!( "XML document version {}, encoded in {}, {}standalone", version, encoding, if standalone.unwrap_or(false) { "" } else { "not " } ), XmlEvent::EndDocument => println!("Document finished"), XmlEvent::ProcessingInstruction { .. } => processing_instructions += 1, XmlEvent::Whitespace(_) => {} // can't happen due to configuration XmlEvent::Characters(s) => { character_blocks += 1; characters += s.len(); } XmlEvent::CData(s) => { cdata_blocks += 1; characters += s.len(); } XmlEvent::Comment(s) => { comment_blocks += 1; comment_characters += s.len(); } XmlEvent::StartElement { namespace, .. } => { depth += 1; max_depth = cmp::max(max_depth, depth); elements += 1; namespaces.extend(namespace.0.into_iter().map(|(_, ns_uri)| ns_uri)); } XmlEvent::EndElement { .. } => { depth -= 1; } }, Err(e) => abort!(1, "Error parsing XML document: {}", e) } } namespaces.remove(xml::namespace::NS_EMPTY_URI); namespaces.remove(xml::namespace::NS_XMLNS_URI); namespaces.remove(xml::namespace::NS_XML_URI); println!("Elements: {}, maximum depth: {}", elements, max_depth); println!("Namespaces (excluding built-in): {}", namespaces.len()); println!("Characters: {}, characters blocks: {}, CDATA blocks: {}", characters, character_blocks, cdata_blocks); println!("Comment blocks: {}, comment characters: {}", comment_blocks, comment_characters); println!("Processing instructions (excluding built-in): {}", processing_instructions); }