xml/
element.rs

1// RustyXML
2// Copyright 2013-2016 RustyXML developers
3//
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7// option. This file may not be copied, modified, or distributed
8// except according to those terms.
9
10use crate::element_builder::{BuilderError, ElementBuilder};
11use crate::parser::Parser;
12use crate::{escape, Xml};
13
14use std::collections::HashMap;
15use std::fmt;
16use std::iter::IntoIterator;
17use std::slice;
18use std::str::FromStr;
19
20#[derive(Clone, PartialEq, Debug)]
21/// A struct representing an XML element
22pub struct Element {
23    /// The element's name
24    pub name: String,
25    /// The element's namespace
26    pub ns: Option<String>,
27    /// The element's attributes
28    pub attributes: HashMap<(String, Option<String>), String>,
29    /// The element's child `Xml` nodes
30    pub children: Vec<Xml>,
31    /// The prefixes set for known namespaces
32    pub(crate) prefixes: HashMap<String, String>,
33    /// The element's default namespace
34    pub(crate) default_ns: Option<String>,
35}
36
37fn fmt_elem(
38    elem: &Element,
39    parent: Option<&Element>,
40    all_prefixes: &HashMap<String, String>,
41    f: &mut fmt::Formatter,
42) -> fmt::Result {
43    let mut all_prefixes = all_prefixes.clone();
44    all_prefixes.extend(elem.prefixes.clone().into_iter());
45
46    // Do we need a prefix?
47    if elem.ns != elem.default_ns {
48        let prefix = all_prefixes
49            .get(elem.ns.as_ref().map_or("", |x| &x[..]))
50            .expect("No namespace prefix bound");
51        write!(f, "<{}:{}", *prefix, elem.name)?;
52    } else {
53        write!(f, "<{}", elem.name)?;
54    }
55
56    // Do we need to set the default namespace ?
57    if !elem
58        .attributes
59        .iter()
60        .any(|(&(ref name, _), _)| name == "xmlns")
61    {
62        match (parent, &elem.default_ns) {
63            // No parent, namespace is not empty
64            (None, &Some(ref ns)) => write!(f, " xmlns='{}'", *ns)?,
65            // Parent and child namespace differ
66            (Some(parent), ns) if parent.default_ns != *ns => {
67                write!(f, " xmlns='{}'", ns.as_ref().map_or("", |x| &x[..]))?
68            }
69            _ => (),
70        }
71    }
72
73    for (&(ref name, ref ns), value) in &elem.attributes {
74        match *ns {
75            Some(ref ns) => {
76                let prefix = all_prefixes.get(ns).expect("No namespace prefix bound");
77                write!(f, " {}:{}='{}'", *prefix, name, escape(&value))?
78            }
79            None => write!(f, " {}='{}'", name, escape(&value))?,
80        }
81    }
82
83    if elem.children.is_empty() {
84        write!(f, "/>")?;
85    } else {
86        write!(f, ">")?;
87        for child in &elem.children {
88            match *child {
89                Xml::ElementNode(ref child) => fmt_elem(child, Some(elem), &all_prefixes, f)?,
90                ref o => fmt::Display::fmt(o, f)?,
91            }
92        }
93        if elem.ns != elem.default_ns {
94            let prefix = all_prefixes
95                .get(elem.ns.as_ref().unwrap())
96                .expect("No namespace prefix bound");
97            write!(f, "</{}:{}>", *prefix, elem.name)?;
98        } else {
99            write!(f, "</{}>", elem.name)?;
100        }
101    }
102
103    Ok(())
104}
105
106impl fmt::Display for Element {
107    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
108        fmt_elem(self, None, &HashMap::new(), f)
109    }
110}
111
112/// An iterator returning filtered child `Element`s of another `Element`
113pub struct ChildElements<'a, 'b> {
114    elems: slice::Iter<'a, Xml>,
115    name: &'b str,
116    ns: Option<&'b str>,
117}
118
119impl<'a, 'b> Iterator for ChildElements<'a, 'b> {
120    type Item = &'a Element;
121
122    fn next(&mut self) -> Option<&'a Element> {
123        let (name, ns) = (self.name, self.ns);
124        self.elems
125            .by_ref()
126            .filter_map(|child| {
127                if let Xml::ElementNode(ref elem) = *child {
128                    if name == elem.name && ns == elem.ns.as_ref().map(|x| &x[..]) {
129                        return Some(elem);
130                    }
131                }
132                None
133            })
134            .next()
135    }
136}
137
138impl Element {
139    /// Create a new `Element`, with specified name and namespace.
140    /// Attributes are specified as a `Vec` of `(name, namespace, value)` tuples.
141    pub fn new<A>(name: String, ns: Option<String>, attrs: A) -> Element
142    where
143        A: IntoIterator<Item = (String, Option<String>, String)>,
144    {
145        let mut prefixes = HashMap::with_capacity(2);
146        prefixes.insert(
147            "http://www.w3.org/XML/1998/namespace".to_owned(),
148            "xml".to_owned(),
149        );
150        prefixes.insert(
151            "http://www.w3.org/2000/xmlns/".to_owned(),
152            "xmlns".to_owned(),
153        );
154
155        let attributes: HashMap<_, _> = attrs
156            .into_iter()
157            .map(|(name, ns, value)| ((name, ns), value))
158            .collect();
159
160        Element {
161            name,
162            ns: ns.clone(),
163            default_ns: ns,
164            prefixes,
165            attributes,
166            children: Vec::new(),
167        }
168    }
169
170    /// Returns the character and CDATA contained in the element.
171    pub fn content_str(&self) -> String {
172        let mut res = String::new();
173        for child in &self.children {
174            match *child {
175                Xml::ElementNode(ref elem) => res.push_str(&elem.content_str()),
176                Xml::CharacterNode(ref data) | Xml::CDATANode(ref data) => res.push_str(&data),
177                _ => (),
178            }
179        }
180        res
181    }
182
183    /// Gets an attribute with the specified name and namespace. When an attribute with the
184    /// specified name does not exist `None` is returned.
185    pub fn get_attribute<'a>(&'a self, name: &str, ns: Option<&str>) -> Option<&'a str> {
186        self.attributes
187            .get(&(name.to_owned(), ns.map(|x| x.to_owned())))
188            .map(|x| &x[..])
189    }
190
191    /// Sets the attribute with the specified name and namespace.
192    /// Returns the original value.
193    pub fn set_attribute(
194        &mut self,
195        name: String,
196        ns: Option<String>,
197        value: String,
198    ) -> Option<String> {
199        self.attributes.insert((name, ns), value)
200    }
201
202    /// Remove the attribute with the specified name and namespace.
203    /// Returns the original value.
204    pub fn remove_attribute(&mut self, name: &str, ns: Option<&str>) -> Option<String> {
205        self.attributes
206            .remove(&(name.to_owned(), ns.map(|x| x.to_owned())))
207    }
208
209    /// Gets the first child `Element` with the specified name and namespace. When no child
210    /// with the specified name exists `None` is returned.
211    pub fn get_child<'a>(&'a self, name: &str, ns: Option<&str>) -> Option<&'a Element> {
212        self.get_children(name, ns).next()
213    }
214
215    /// Get all children `Element` with the specified name and namespace. When no child
216    /// with the specified name exists an empty vetor is returned.
217    pub fn get_children<'a, 'b>(
218        &'a self,
219        name: &'b str,
220        ns: Option<&'b str>,
221    ) -> ChildElements<'a, 'b> {
222        ChildElements {
223            elems: self.children.iter(),
224            name,
225            ns,
226        }
227    }
228
229    /// Appends a child element. Returns a reference to the added element.
230    pub fn tag(&mut self, child: Element) -> &mut Element {
231        self.children.push(Xml::ElementNode(child));
232        let error = "Internal error: Could not get reference to new element!";
233        match *self.children.last_mut().expect(error) {
234            Xml::ElementNode(ref mut elem) => elem,
235            _ => panic!(error),
236        }
237    }
238
239    /// Appends a child element. Returns a mutable reference to self.
240    pub fn tag_stay(&mut self, child: Element) -> &mut Element {
241        self.children.push(Xml::ElementNode(child));
242        self
243    }
244
245    /// Appends characters. Returns a mutable reference to self.
246    pub fn text(&mut self, text: String) -> &mut Element {
247        self.children.push(Xml::CharacterNode(text));
248        self
249    }
250
251    /// Appends CDATA. Returns a mutable reference to self.
252    pub fn cdata(&mut self, text: String) -> &mut Element {
253        self.children.push(Xml::CDATANode(text));
254        self
255    }
256
257    /// Appends a comment. Returns a mutable reference to self.
258    pub fn comment(&mut self, text: String) -> &mut Element {
259        self.children.push(Xml::CommentNode(text));
260        self
261    }
262
263    /// Appends processing information. Returns a mutable reference to self.
264    pub fn pi(&mut self, text: String) -> &mut Element {
265        self.children.push(Xml::PINode(text));
266        self
267    }
268}
269
270impl FromStr for Element {
271    type Err = BuilderError;
272    #[inline]
273    fn from_str(data: &str) -> Result<Element, BuilderError> {
274        let mut p = Parser::new();
275        let mut e = ElementBuilder::new();
276
277        p.feed_str(data);
278        p.filter_map(|x| e.handle_event(x))
279            .next()
280            .unwrap_or(Err(BuilderError::NoElement))
281    }
282}
283
284#[cfg(test)]
285mod tests {
286    use super::Element;
287
288    #[test]
289    fn test_get_children() {
290        let elem: Element = "<a><b/><c/><b/></a>".parse().unwrap();
291        assert_eq!(
292            elem.get_children("b", None).collect::<Vec<_>>(),
293            vec![
294                &Element::new("b".to_owned(), None, vec![]),
295                &Element::new("b".to_owned(), None, vec![])
296            ],
297        );
298    }
299
300    #[test]
301    fn test_get_child() {
302        let elem: Element = "<a><b/><c/><b/></a>".parse().unwrap();
303        assert_eq!(
304            elem.get_child("b", None),
305            Some(&Element::new("b".to_owned(), None, vec![])),
306        );
307    }
308}