1use quick_xml::XmlVersion;
4use quick_xml::events::BytesStart;
5
6use crate::error::Result;
7
8pub const R_NS: &str = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
10
11pub const MC_NS: &str = "http://schemas.openxmlformats.org/markup-compatibility/2006";
13
14pub fn local_name(name: &[u8]) -> &[u8] {
16 match name.iter().position(|&byte| byte == b':') {
17 Some(pos) => &name[pos + 1..],
18 None => name,
19 }
20}
21
22pub fn matches_local_name(name: &[u8], expected: &[u8]) -> bool {
24 local_name(name) == expected
25}
26
27pub fn get_attr(element: &BytesStart<'_>, name: &[u8]) -> Option<String> {
29 element
30 .attributes()
31 .flatten()
32 .find(|attr| matches_local_name(attr.key.as_ref(), name))
33 .and_then(|attr| std::str::from_utf8(&attr.value).ok().map(str::to_owned))
34}
35
36pub(crate) fn extra_namespace_declarations(
38 element: &BytesStart<'_>,
39) -> Result<Vec<(String, String)>> {
40 let mut declarations = Vec::new();
41 for attribute in element.attributes() {
42 let attribute = attribute?;
43 let key = attribute.key.as_ref();
44 if key.starts_with(b"xmlns:") && key != b"xmlns:vt" {
45 let name = std::str::from_utf8(key)?.to_owned();
46 let value = attribute
47 .decoded_and_normalized_value(XmlVersion::Implicit1_0, element.decoder())?
48 .into_owned();
49 declarations.push((name, value));
50 }
51 }
52 Ok(declarations)
53}
54
55#[cfg(test)]
56mod tests {
57 use quick_xml::Reader;
58 use quick_xml::events::Event;
59
60 use super::*;
61
62 #[test]
63 fn local_names_match_with_or_without_a_prefix() {
64 assert_eq!(local_name(b"w:document"), b"document");
65 assert_eq!(local_name(b"document"), b"document");
66 assert!(matches_local_name(b"p:sld", b"sld"));
67 assert!(!matches_local_name(b"p:sld", b"slide"));
68 }
69
70 #[test]
71 fn attributes_match_with_or_without_a_prefix() {
72 let mut reader = Reader::from_str(r#"<item r:id="rId7" plain="value"/>"#);
73 let mut buf = Vec::new();
74 let Event::Empty(element) = reader.read_event_into(&mut buf).unwrap() else {
75 panic!("expected empty element");
76 };
77
78 assert_eq!(get_attr(&element, b"id").as_deref(), Some("rId7"));
79 assert_eq!(get_attr(&element, b"plain").as_deref(), Some("value"));
80 assert_eq!(get_attr(&element, b"missing"), None);
81 }
82}