1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
use std::collections::BTreeMap;

use crate::ns::*;
use serde::{Serialize, Deserialize};

#[derive(Clone, Serialize, Deserialize)]
pub struct MxmlDocument {
    pub version: XmlVersion,
    pub encoding: String,
    pub content: Vec<Rc<MxmlContent>>,
}

#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum XmlVersion {
    /// XML version 1.0.
    Version10,
}

#[derive(Clone, Serialize, Deserialize)]
pub struct MxmlElement {
    pub location: Location,
    pub name: MxmlName,
    /// Attribute list, including `xmlns` and `xmlns:` namespace prefixes.
    pub attributes: Vec<Rc<MxmlAttribute>>,
    /// The namespace mapping relative to the XML element.
    #[serde(skip)]
    pub namespace: Rc<MxmlNamespace>,
    pub content: Option<Vec<Rc<MxmlContent>>>,
    pub closing_name: Option<MxmlName>,
}

#[derive(Clone, Serialize, Deserialize)]
pub struct MxmlAttribute {
    pub location: Location,
    pub name: MxmlName,
    pub value: (String, Location),
}

#[derive(Clone, Serialize, Deserialize)]
pub struct MxmlName {
    pub location: Location,
    pub prefix: Option<Rc<String>>,
    pub name: String,
}

#[derive(Clone, Serialize, Deserialize)]
pub enum MxmlContent {
    Characters((String, Location)),
    Whitespace((String, Location)),
    /// A CDATA construct, including the first `<![CDATA[` characters
    /// and the last `]]>` characters.
    CData((String, Location)),
    /// A comment construct, including the first `<!--` characters
    /// and the last `-->` characters.
    Comment((String, Location)),
    ProcessingInstruction {
        location: Location,
        name: String,
        data: Option<String>,
    },
    Element(Rc<MxmlElement>),
}

impl MxmlContent {
    pub fn location(&self) -> Location {
        match self {
            Self::Characters((_, l)) => l.clone(),
            Self::Whitespace((_, l)) => l.clone(),
            Self::CData((_, l)) => l.clone(),
            Self::Comment((_, l)) => l.clone(),
            Self::ProcessingInstruction { location: l, .. } => l.clone(),
            Self::Element(e) => e.location.clone(),
        }
    }
}

/// Mapping of namespace prefixes.
#[derive(Clone, PartialEq)]
pub struct MxmlNamespace {
    parent: Option<Rc<MxmlNamespace>>,
    mappings: RefCell<BTreeMap<String, String>>,
}

impl Default for MxmlNamespace {
    fn default() -> Self {
        Self::new(None)
    }
}

impl MxmlNamespace {
    /// Returns the prefix used for the default XML namespace.
    pub const DEFAULT_NAMESPACE: &'static str = "";

    /// Constructs an empty set of namespace mappings.
    pub fn new(parent: Option<&Rc<MxmlNamespace>>) -> Self {
        Self {
            parent: parent.map(|p| p.clone()),
            mappings: RefCell::new(BTreeMap::new()),
        }
    }

    pub fn includes(&self, prefix: &str) -> bool {
        self.mappings.borrow().contains_key(prefix) || match &self.parent {
            Some(p) => p.includes(prefix),
            None => false,
        }
    }

    /// Retrieves the value of a prefix either in the actual
    /// set of mappings or in the parent set of mappings.
    pub fn get(&self, prefix: &str) -> Option<String> {
        if let Some(value) = self.mappings.borrow().get(prefix) {
            return Some(value.clone());
        }
        self.parent.as_ref().and_then(|p| p.get(prefix))
    }

    pub fn set(&mut self, prefix: &str, value: &str) {
        self.mappings.get_mut().insert(prefix.to_owned(), value.to_owned());
    }

    pub fn delete(&mut self, prefix: &str) -> bool {
        self.mappings.get_mut().remove(prefix).is_some()
    }

    pub fn clear(&mut self) {
        self.mappings.get_mut().clear();
    }

    /// Returns the actual set of prefix mappings.
    pub fn listing(&self) -> BTreeMap<String, String> {
        self.mappings.borrow().clone()
    }

    /// Returns a concatenation of the parent set of prefix mappings
    /// and the actual set of prefix mappings.
    pub fn full_listing(&self) -> BTreeMap<String, String> {
        let mut listing = self.parent.as_ref().map_or(BTreeMap::new(), |p| p.full_listing());
        listing.extend(self.listing());
        listing
    }
}