as3_parser/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: MxmlName,
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<MxmlName>,
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 MxmlName {
57    pub location: Location,
58    /// The unresolved prefix of the name.
59    pub prefix: Option<String>,
60    pub name: String,
61}
62
63impl MxmlName {
64    pub fn resolve_prefix(&self, namespace: &Rc<MxmlNamespace>) -> Result<String, MxmlNameError> {
65        let Some(p) = self.prefix.as_ref() else {
66            return if let Some(v) = namespace.get(MxmlNamespace::DEFAULT_NAMESPACE) {
67                Ok(v)
68            } else {
69                Err(MxmlNameError::PrefixNotDefined(MxmlNamespace::DEFAULT_NAMESPACE.into()))
70            };
71        };
72        if let Some(v) = namespace.get(p) {
73            Ok(v)
74        } else {
75            Err(MxmlNameError::PrefixNotDefined(p.clone()))
76        }
77    }
78
79    pub fn resolve_name(&self, namespace: &Rc<MxmlNamespace>) -> Result<(String, String), MxmlNameError> {
80        let p = self.resolve_prefix(namespace)?;
81        Ok((p, self.name.clone()))
82    }
83
84    pub fn equals_name(&self, other: &Self, namespace: &Rc<MxmlNamespace>) -> Result<bool, MxmlNameError> {
85        if self.name != other.name {
86            return Ok(false);
87        }
88        let p1 = self.resolve_prefix(namespace)?;
89        let p2 = other.resolve_prefix(namespace)?;
90        Ok(&p1 == &p2)
91    }
92
93    pub fn to_string(&self, namespace: &Rc<MxmlNamespace>) -> String {
94        self.resolve_name(namespace).map(|(uri, localname)| {
95            if uri.is_empty() {
96                return localname;
97            }
98            format!("{uri}:{localname}")
99        }).unwrap_or("[error]".into())
100    }
101}
102
103#[derive(Clone)]
104pub enum MxmlNameError {
105    PrefixNotDefined(String),
106}
107
108#[derive(Clone, Serialize, Deserialize)]
109pub enum MxmlContent {
110    Characters((String, Location)),
111    /// A CDATA construct, including the first `<![CDATA[` characters
112    /// and the last `]]>` characters.
113    CData((String, Location)),
114    /// A comment construct, including the first `<!--` characters
115    /// and the last `-->` characters.
116    Comment((String, Location)),
117    ProcessingInstruction {
118        location: Location,
119        name: String,
120        data: Option<String>,
121    },
122    Element(Rc<MxmlElement>),
123}
124
125impl MxmlContent {
126    pub fn location(&self) -> Location {
127        match self {
128            Self::Characters((_, l)) => l.clone(),
129            Self::CData((_, l)) => l.clone(),
130            Self::Comment((_, l)) => l.clone(),
131            Self::ProcessingInstruction { location: l, .. } => l.clone(),
132            Self::Element(e) => e.location.clone(),
133        }
134    }
135
136    pub fn inner_text(&self) -> String {
137        match self {
138            Self::Characters((data, _)) => data.clone(),
139            Self::CData((data, _)) => data["<![CDATA[".len()..(data.len() - 3)].to_owned(),
140            Self::Comment(_) => String::new(),
141            Self::ProcessingInstruction { .. } => String::new(),
142            Self::Element(e) => e.inner_text(),
143        }
144    }
145}
146
147/// Mapping of namespace prefixes.
148#[derive(Clone, PartialEq)]
149pub struct MxmlNamespace {
150    parent: Option<Rc<MxmlNamespace>>,
151    mappings: RefCell<BTreeMap<String, String>>,
152}
153
154impl Default for MxmlNamespace {
155    fn default() -> Self {
156        Self::new(None)
157    }
158}
159
160impl MxmlNamespace {
161    /// Returns the prefix used for the default XML namespace.
162    pub const DEFAULT_NAMESPACE: &'static str = "";
163
164    /// Constructs an empty set of namespace mappings.
165    pub fn new(parent: Option<&Rc<MxmlNamespace>>) -> Self {
166        let mut ns = Self {
167            parent: parent.map(|p| p.clone()),
168            mappings: RefCell::new(BTreeMap::new()),
169        };
170        if ns.parent.is_none() {
171            ns.mappings.get_mut().insert(Self::DEFAULT_NAMESPACE.into(), "".into());
172            ns.mappings.get_mut().insert("xmlns".into(), "http://www.w3.org/xml/xmlns".into());
173        }
174        ns
175    }
176
177    pub fn includes(&self, prefix: &str) -> bool {
178        self.mappings.borrow().contains_key(prefix) || match &self.parent {
179            Some(p) => p.includes(prefix),
180            None => false,
181        }
182    }
183
184    /// Retrieves the value of a prefix either in the actual
185    /// set of mappings or in the parent set of mappings.
186    pub fn get(&self, prefix: &str) -> Option<String> {
187        if let Some(value) = self.mappings.borrow().get(prefix) {
188            return Some(value.clone());
189        }
190        self.parent.as_ref().and_then(|p| p.get(prefix))
191    }
192
193    pub fn set(&self, prefix: &str, value: &str) {
194        self.mappings.borrow_mut().insert(prefix.to_owned(), value.to_owned());
195    }
196
197    pub fn delete(&self, prefix: &str) -> bool {
198        self.mappings.borrow_mut().remove(prefix).is_some()
199    }
200
201    pub fn clear(&self) {
202        self.mappings.borrow_mut().clear();
203    }
204
205    /// Returns the actual set of prefix mappings.
206    pub fn listing(&self) -> BTreeMap<String, String> {
207        self.mappings.borrow().clone()
208    }
209
210    /// Returns a concatenation of the parent set of prefix mappings
211    /// and the actual set of prefix mappings.
212    pub fn full_listing(&self) -> BTreeMap<String, String> {
213        let mut listing = self.parent.as_ref().map_or(BTreeMap::new(), |p| p.full_listing());
214        listing.extend(self.listing());
215        listing
216    }
217}