Im parsing XML with xml-rs. I'm looking for ways to make my code more compact, since my current code looks overly verbose and the really relevant parts (the local_name I'm looking for and partially the namespace) sit somewhere within lots of boiler plate. This is my current code (note that as the parsing grows there will be more branches in the match that will basically look the same on the pattern side and that the called function find_sections(parser) will basically have the same shape, just looking for different XML elements etc.):
const NS_2010_MAIN: &str = "http://schemas.microsoft.com/office/powerpoint/2010/main";
fn find_section_list (parser: &mut impl Iterator<Item=xml::reader::Result<XmlEvent>>) {
while let Some(e) = parser.next() {
match e {
Ok(StartElement {
name:
xml::name::OwnedName {
ref local_name,
namespace: Some(ref ns),
..
},
..
}) if local_name == "sectionLst" && ns == NS_2010_MAIN => {
find_sections(parser);
}
Ok(_) => {}
Err(_) => {
panic!("Encountered error parsing XML");
}
}
}
}
I've had these initial ideas, but both fail: (1) it would be nice to be able to write
/* does not compile */
match e {
Ok(StartElement {
name:
xml::name::OwnedName {
local_name: "sectionLst",
namespace: Some(NS_2010_MAIN),
..
}
}) => { ... }
But this doesn't work since local_name and namespace have types String and Option not &str and Option<&str>
(2) I had the idea to use a macro, but if I understand correctly, a macro can only produce a pattern, but not a match arm (pattern plus the if-guard) that I would need here:
/* does not compile */
macro_rules! start_elem {
($ln:expr, $ns:expr) => (
Ok(StartElement {
name:
xml::name::OwnedName {
ref local_name,
namespace: Some(ref ns),
..
},
..
}) if local_name == $ln && ns == $ns
)
}
match e {
start_elem!("sectionLst", NS_2010_MAIN) => { ... }
I'm looking for ways or good ideas to make this parsing more manageable.