| 972 | } |
| 973 | |
| 974 | fn compile_xpath(xpath: &str) -> Result<XPath> { |
| 975 | let factory = Factory::new(); |
| 976 | let xpath_with_debug_info = MyXPath::add_debug_string_arg(xpath)?; |
| 977 | let compiled_xpath = factory.build(&xpath_with_debug_info) |
| 978 | .chain_err(|| format!( |
| 979 | "Could not compile XPath for pattern:\n{}{}", |
| 980 | &xpath, more_details(xpath)))?; |
| 981 | return match compiled_xpath { |
| 982 | Some(xpath) => Ok(xpath), |
| 983 | None => bail!("Problem compiling Xpath for pattern:\n{}{}", |
| 984 | &xpath, more_details(xpath)), |
| 985 | }; |
| 986 | |
| 987 | |
| 988 | fn more_details(xpath: &str) -> String { |
| 989 | // try to give a better error message by counting [], (), 's, and "s |
| 990 | if xpath.is_empty() { |
| 991 | return "xpath is empty string".to_string(); |
| 992 | } |
| 993 | let as_bytes = xpath.trim().as_bytes(); |
| 994 | if as_bytes[0] == b'\'' && as_bytes[as_bytes.len()-1] != b'\'' { |
| 995 | return "\nmissing \"'\"".to_string(); |
| 996 | } |
| 997 | if (as_bytes[0] == b'"' && as_bytes[as_bytes.len()-1] != b'"') || |
| 998 | (as_bytes[0] != b'"' && as_bytes[as_bytes.len()-1] == b'"'){ |
| 999 | return "\nmissing '\"'".to_string(); |
| 1000 | } |
| 1001 | |
| 1002 | let mut i_bytes = 0; // keep track of # of bytes into string for error reporting |
| 1003 | let mut paren_count = 0; // counter to make sure they are balanced |
| 1004 | let mut i_paren = 0; // position of the outermost open paren |
| 1005 | let mut bracket_count = 0; |
| 1006 | let mut i_bracket = 0; |
| 1007 | for ch in xpath.chars() { |
| 1008 | if ch == '(' { |
| 1009 | if paren_count == 0 { |
| 1010 | i_paren = i_bytes; |
| 1011 | } |
| 1012 | paren_count += 1; |
| 1013 | } else if ch == '[' { |
| 1014 | if bracket_count == 0 { |
| 1015 | i_bracket = i_bytes; |
| 1016 | } |
| 1017 | bracket_count += 1; |
| 1018 | } else if ch == ')' { |
| 1019 | if paren_count == 0 { |
| 1020 | return format!("\nExtra ')' found after '{}'", &xpath[i_paren..i_bytes]); |
| 1021 | } |
| 1022 | paren_count -= 1; |
| 1023 | if paren_count == 0 && bracket_count > 0 && i_bracket > i_paren { |
| 1024 | return format!("\nUnclosed brackets found at '{}'", &xpath[i_paren..i_bytes]); |
| 1025 | } |
| 1026 | } else if ch == ']' { |
| 1027 | if bracket_count == 0 { |
| 1028 | return format!("\nExtra ']' found after '{}'", &xpath[i_bracket..i_bytes]); |
| 1029 | } |
| 1030 | bracket_count -= 1; |
| 1031 | if bracket_count == 0 && paren_count > 0 && i_paren > i_bracket { |