mxmlextrema_as3parser/tree/
mxml.rs

1use std::collections::BTreeMap;
2
3use crate::ns::*;
4use serde::{Serialize, Deserialize};
5
6#[derive(Clone, Serialize, Deserialize)]
7pub struct Mxml {
8    pub location: Location,
9    pub version: XmlVersion,
10    pub encoding: String,
11    pub content: Vec<Rc<MxmlContent>>,
12}
13
14#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
15pub enum XmlVersion {
16    /// XML version 1.0.
17    Version10,
18}
19
20#[derive(Clone, Serialize, Deserialize)]
21pub struct MxmlElement {
22    pub location: Location,
23    pub name: MxmlTagName,
24    /// Attribute list, including `xmlns` and `xmlns:` namespace prefixes.
25    pub attributes: Vec<Rc<MxmlAttribute>>,
26    /// The namespace mapping relative to the XML element.
27    #[serde(skip)]
28    pub namespace: Rc<MxmlNamespace>,
29    pub content: Option<Vec<Rc<MxmlContent>>>,
30    pub closing_name: Option<MxmlTagName>,
31}
32
33impl MxmlElement {
34    pub fn inner_text(&self) -> String {
35        let mut j = String::new();
36        if let Some(c) = self.content.as_ref() {
37            for c1 in c.iter() {
38                j.push_str(&c1.inner_text());
39            }
40        }
41        j
42    }
43}
44
45#[derive(Clone, Serialize, Deserialize)]
46pub struct MxmlAttribute {
47    pub location: Location,
48    /// Indicates whether the attribute is a `xmlns` or `xmlns:` attribute.
49    pub xmlns: bool,
50    pub name: MxmlName,
51    /// Attribute value. The location data includes the quotes.
52    pub value: (String, Location),
53}
54
55#[derive(Clone, Serialize, Deserialize)]
56pub struct MxmlTagName {
57    pub location: Location,
58    /// The unresolved prefix of the name.
59    pub prefix: Option<String>,
60    pub name: String,
61}
62
63#[derive(Clone, Serialize, Deserialize)]
64pub struct MxmlName {
65    pub location: Location,
66    /// The unresolved prefix of the name.
67    pub prefix: Option<String>,
68    pub name: String,
69}
70
71impl MxmlTagName {
72    pub fn resolve_prefix(&self, namespace: &Rc<MxmlNamespace>) -> Result<String, MxmlNameError> {
73        let Some(p) = self.prefix.as_ref() else {
74            return if let Some(v) = namespace.get(MxmlNamespace::DEFAULT_NAMESPACE) {
75                Ok(v)
76            } else {
77                Err(MxmlNameError::PrefixNotDefined(MxmlNamespace::DEFAULT_NAMESPACE.into()))
78            };
79        };
80        if let Some(v) = namespace.get(p) {
81            Ok(v)
82        } else {
83            Err(MxmlNameError::PrefixNotDefined(p.clone()))
84        }
85    }
86
87    pub fn resolve_name(&self, namespace: &Rc<MxmlNamespace>) -> Result<(String, String), MxmlNameError> {
88        let p = self.resolve_prefix(namespace)?;
89        Ok((p, self.name.clone()))
90    }
91
92    pub fn equals_name(&self, other: &Self, namespace: &Rc<MxmlNamespace>) -> Result<bool, MxmlNameError> {
93        if self.name != other.name {
94            return Ok(false);
95        }
96        let p1 = self.resolve_prefix(namespace)?;
97        let p2 = other.resolve_prefix(namespace)?;
98        Ok(&p1 == &p2)
99    }
100
101    pub fn to_string(&self, namespace: &Rc<MxmlNamespace>) -> String {
102        self.resolve_name(namespace).map(|(uri, localname)| {
103            if uri.is_empty() {
104                return localname;
105            }
106            format!("{uri}:{localname}")
107        }).unwrap_or("[error]".into())
108    }
109}
110
111impl MxmlName {
112    pub fn resolve_prefix(&self, namespace: &Rc<MxmlNamespace>) -> Result<String, MxmlNameError> {
113        let Some(p) = self.prefix.as_ref() else {
114            return Ok(MxmlNamespace::DEFAULT_NAMESPACE.to_owned());
115        };
116        if let Some(v) = namespace.get(p) {
117            Ok(v)
118        } else {
119            Err(MxmlNameError::PrefixNotDefined(p.clone()))
120        }
121    }
122
123    pub fn resolve_name(&self, namespace: &Rc<MxmlNamespace>) -> Result<(String, String), MxmlNameError> {
124        let p = self.resolve_prefix(namespace)?;
125        Ok((p, self.name.clone()))
126    }
127
128    pub fn equals_name(&self, other: &Self, namespace: &Rc<MxmlNamespace>) -> Result<bool, MxmlNameError> {
129        if self.name != other.name {
130            return Ok(false);
131        }
132        let p1 = self.resolve_prefix(namespace)?;
133        let p2 = other.resolve_prefix(namespace)?;
134        Ok(&p1 == &p2)
135    }
136
137    pub fn to_string(&self, namespace: &Rc<MxmlNamespace>) -> String {
138        self.resolve_name(namespace).map(|(uri, localname)| {
139            if uri.is_empty() {
140                return localname;
141            }
142            format!("{uri}:{localname}")
143        }).unwrap_or("[error]".into())
144    }
145}
146
147#[derive(Clone)]
148pub enum MxmlNameError {
149    PrefixNotDefined(String),
150}
151
152#[derive(Clone, Serialize, Deserialize)]
153pub enum MxmlContent {
154    Characters((String, Location)),
155    /// A CDATA construct, including the first `<![CDATA[` characters
156    /// and the last `]]>` characters.
157    CData((String, Location)),
158    /// A comment construct, including the first `<!--` characters
159    /// and the last `-->` characters.
160    Comment((String, Location)),
161    ProcessingInstruction {
162        location: Location,
163        name: String,
164        data: Option<String>,
165    },
166    Element(Rc<MxmlElement>),
167}
168
169impl MxmlContent {
170    pub fn location(&self) -> Location {
171        match self {
172            Self::Characters((_, l)) => l.clone(),
173            Self::CData((_, l)) => l.clone(),
174            Self::Comment((_, l)) => l.clone(),
175            Self::ProcessingInstruction { location: l, .. } => l.clone(),
176            Self::Element(e) => e.location.clone(),
177        }
178    }
179
180    pub fn inner_text(&self) -> String {
181        match self {
182            Self::Characters((data, _)) => data.clone(),
183            Self::CData((data, _)) => data["<![CDATA[".len()..(data.len() - 3)].to_owned(),
184            Self::Comment(_) => String::new(),
185            Self::ProcessingInstruction { .. } => String::new(),
186            Self::Element(e) => e.inner_text(),
187        }
188    }
189}
190
191/// Mapping of namespace prefixes.
192#[derive(Clone, PartialEq)]
193pub struct MxmlNamespace {
194    parent: Option<Rc<MxmlNamespace>>,
195    mappings: RefCell<BTreeMap<String, String>>,
196}
197
198impl Default for MxmlNamespace {
199    fn default() -> Self {
200        Self::new(None)
201    }
202}
203
204impl MxmlNamespace {
205    /// Returns the prefix used for the default XML namespace.
206    pub const DEFAULT_NAMESPACE: &'static str = "";
207
208    /// Constructs an empty set of namespace mappings.
209    pub fn new(parent: Option<&Rc<MxmlNamespace>>) -> Self {
210        let mut ns = Self {
211            parent: parent.map(|p| p.clone()),
212            mappings: RefCell::new(BTreeMap::new()),
213        };
214        if ns.parent.is_none() {
215            ns.mappings.get_mut().insert(Self::DEFAULT_NAMESPACE.into(), "".into());
216            ns.mappings.get_mut().insert("xmlns".into(), "http://www.w3.org/xml/xmlns".into());
217        }
218        ns
219    }
220
221    pub fn includes(&self, prefix: &str) -> bool {
222        self.mappings.borrow().contains_key(prefix) || match &self.parent {
223            Some(p) => p.includes(prefix),
224            None => false,
225        }
226    }
227
228    /// Retrieves the value of a prefix either in the actual
229    /// set of mappings or in the parent set of mappings.
230    pub fn get(&self, prefix: &str) -> Option<String> {
231        if let Some(value) = self.mappings.borrow().get(prefix) {
232            return Some(value.clone());
233        }
234        self.parent.as_ref().and_then(|p| p.get(prefix))
235    }
236
237    pub fn set(&self, prefix: &str, value: &str) {
238        self.mappings.borrow_mut().insert(prefix.to_owned(), value.to_owned());
239    }
240
241    pub fn delete(&self, prefix: &str) -> bool {
242        self.mappings.borrow_mut().remove(prefix).is_some()
243    }
244
245    pub fn clear(&self) {
246        self.mappings.borrow_mut().clear();
247    }
248
249    /// Returns the actual set of prefix mappings.
250    pub fn listing(&self) -> BTreeMap<String, String> {
251        self.mappings.borrow().clone()
252    }
253
254    /// Returns a concatenation of the parent set of prefix mappings
255    /// and the actual set of prefix mappings.
256    pub fn full_listing(&self) -> BTreeMap<String, String> {
257        let mut listing = self.parent.as_ref().map_or(BTreeMap::new(), |p| p.full_listing());
258        listing.extend(self.listing());
259        listing
260    }
261}