/rust/registry/src/index.crates.io-6f17d22bba15001f/quick-xml-0.29.0/src/name.rs
Line | Count | Source (jump to first uncovered line) |
1 | | //! Module for handling names according to the W3C [Namespaces in XML 1.1 (Second Edition)][spec] |
2 | | //! specification |
3 | | //! |
4 | | //! [spec]: https://www.w3.org/TR/xml-names11 |
5 | | |
6 | | use crate::errors::{Error, Result}; |
7 | | use crate::events::attributes::Attribute; |
8 | | use crate::events::BytesStart; |
9 | | use crate::utils::write_byte_string; |
10 | | use memchr::memchr; |
11 | | use std::convert::TryFrom; |
12 | | use std::fmt::{self, Debug, Formatter}; |
13 | | |
14 | | /// A [qualified name] of an element or an attribute, including an optional |
15 | | /// namespace [prefix](Prefix) and a [local name](LocalName). |
16 | | /// |
17 | | /// [qualified name]: https://www.w3.org/TR/xml-names11/#dt-qualname |
18 | | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
19 | | #[cfg_attr(feature = "serde-types", derive(serde::Deserialize, serde::Serialize))] |
20 | | pub struct QName<'a>(pub &'a [u8]); |
21 | | impl<'a> QName<'a> { |
22 | | /// Converts this name to an internal slice representation. |
23 | | #[inline(always)] |
24 | 28.6M | pub fn into_inner(self) -> &'a [u8] { |
25 | 28.6M | self.0 |
26 | 28.6M | } |
27 | | |
28 | | /// Returns local part of this qualified name. |
29 | | /// |
30 | | /// All content up to and including the first `:` character is removed from |
31 | | /// the tag name. |
32 | | /// |
33 | | /// # Examples |
34 | | /// |
35 | | /// ``` |
36 | | /// # use quick_xml::name::QName; |
37 | | /// let simple = QName(b"simple-name"); |
38 | | /// assert_eq!(simple.local_name().as_ref(), b"simple-name"); |
39 | | /// |
40 | | /// let qname = QName(b"namespace:simple-name"); |
41 | | /// assert_eq!(qname.local_name().as_ref(), b"simple-name"); |
42 | | /// ``` |
43 | 0 | pub fn local_name(&self) -> LocalName<'a> { |
44 | 0 | LocalName(self.index().map_or(self.0, |i| &self.0[i + 1..])) |
45 | 0 | } |
46 | | |
47 | | /// Returns namespace part of this qualified name or `None` if namespace part |
48 | | /// is not defined (symbol `':'` not found). |
49 | | /// |
50 | | /// # Examples |
51 | | /// |
52 | | /// ``` |
53 | | /// # use std::convert::AsRef; |
54 | | /// # use quick_xml::name::QName; |
55 | | /// let simple = QName(b"simple-name"); |
56 | | /// assert_eq!(simple.prefix(), None); |
57 | | /// |
58 | | /// let qname = QName(b"prefix:simple-name"); |
59 | | /// assert_eq!(qname.prefix().as_ref().map(|n| n.as_ref()), Some(b"prefix".as_ref())); |
60 | | /// ``` |
61 | 0 | pub fn prefix(&self) -> Option<Prefix<'a>> { |
62 | 0 | self.index().map(|i| Prefix(&self.0[..i])) |
63 | 0 | } |
64 | | |
65 | | /// The same as `(qname.local_name(), qname.prefix())`, but does only one |
66 | | /// lookup for a `':'` symbol. |
67 | 0 | pub fn decompose(&self) -> (LocalName<'a>, Option<Prefix<'a>>) { |
68 | 0 | match self.index() { |
69 | 0 | None => (LocalName(self.0), None), |
70 | 0 | Some(i) => (LocalName(&self.0[i + 1..]), Some(Prefix(&self.0[..i]))), |
71 | | } |
72 | 0 | } |
73 | | |
74 | | /// If that `QName` represents `"xmlns"` series of names, returns `Some`, |
75 | | /// otherwise `None` is returned. |
76 | | /// |
77 | | /// # Examples |
78 | | /// |
79 | | /// ``` |
80 | | /// # use quick_xml::name::{QName, PrefixDeclaration}; |
81 | | /// let qname = QName(b"xmlns"); |
82 | | /// assert_eq!(qname.as_namespace_binding(), Some(PrefixDeclaration::Default)); |
83 | | /// |
84 | | /// let qname = QName(b"xmlns:prefix"); |
85 | | /// assert_eq!(qname.as_namespace_binding(), Some(PrefixDeclaration::Named(b"prefix"))); |
86 | | /// |
87 | | /// // Be aware that this method does not check the validity of the prefix - it can be empty! |
88 | | /// let qname = QName(b"xmlns:"); |
89 | | /// assert_eq!(qname.as_namespace_binding(), Some(PrefixDeclaration::Named(b""))); |
90 | | /// |
91 | | /// let qname = QName(b"other-name"); |
92 | | /// assert_eq!(qname.as_namespace_binding(), None); |
93 | | /// |
94 | | /// // https://www.w3.org/TR/xml-names11/#xmlReserved |
95 | | /// let qname = QName(b"xmlns-reserved-name"); |
96 | | /// assert_eq!(qname.as_namespace_binding(), None); |
97 | | /// ``` |
98 | 0 | pub fn as_namespace_binding(&self) -> Option<PrefixDeclaration<'a>> { |
99 | 0 | if self.0.starts_with(b"xmlns") { |
100 | 0 | return match self.0.get(5) { |
101 | 0 | None => Some(PrefixDeclaration::Default), |
102 | 0 | Some(&b':') => Some(PrefixDeclaration::Named(&self.0[6..])), |
103 | 0 | _ => None, |
104 | | }; |
105 | 0 | } |
106 | 0 | None |
107 | 0 | } |
108 | | |
109 | | /// Returns the index in the name where prefix ended |
110 | | #[inline(always)] |
111 | 0 | fn index(&self) -> Option<usize> { |
112 | 0 | memchr(b':', self.0) |
113 | 0 | } |
114 | | } |
115 | | impl<'a> Debug for QName<'a> { |
116 | 0 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { |
117 | 0 | write!(f, "QName(")?; |
118 | 0 | write_byte_string(f, self.0)?; |
119 | 0 | write!(f, ")") |
120 | 0 | } |
121 | | } |
122 | | impl<'a> AsRef<[u8]> for QName<'a> { |
123 | | #[inline] |
124 | 54.3M | fn as_ref(&self) -> &[u8] { |
125 | 54.3M | self.0 |
126 | 54.3M | } <quick_xml::name::QName as core::convert::AsRef<[u8]>>::as_ref Line | Count | Source | 124 | 47.5M | fn as_ref(&self) -> &[u8] { | 125 | 47.5M | self.0 | 126 | 47.5M | } |
<quick_xml::name::QName as core::convert::AsRef<[u8]>>::as_ref Line | Count | Source | 124 | 6.78M | fn as_ref(&self) -> &[u8] { | 125 | 6.78M | self.0 | 126 | 6.78M | } |
|
127 | | } |
128 | | |
129 | | //////////////////////////////////////////////////////////////////////////////////////////////////// |
130 | | |
131 | | /// A [local (unqualified) name] of an element or an attribute, i.e. a name |
132 | | /// without [prefix](Prefix). |
133 | | /// |
134 | | /// [local (unqualified) name]: https://www.w3.org/TR/xml-names11/#dt-localname |
135 | | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
136 | | #[cfg_attr(feature = "serde-types", derive(serde::Deserialize, serde::Serialize))] |
137 | | pub struct LocalName<'a>(&'a [u8]); |
138 | | impl<'a> LocalName<'a> { |
139 | | /// Converts this name to an internal slice representation. |
140 | | #[inline(always)] |
141 | 0 | pub fn into_inner(self) -> &'a [u8] { |
142 | 0 | self.0 |
143 | 0 | } |
144 | | } |
145 | | impl<'a> Debug for LocalName<'a> { |
146 | 0 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { |
147 | 0 | write!(f, "LocalName(")?; |
148 | 0 | write_byte_string(f, self.0)?; |
149 | 0 | write!(f, ")") |
150 | 0 | } |
151 | | } |
152 | | impl<'a> AsRef<[u8]> for LocalName<'a> { |
153 | | #[inline] |
154 | 0 | fn as_ref(&self) -> &[u8] { |
155 | 0 | self.0 |
156 | 0 | } |
157 | | } |
158 | | impl<'a> From<QName<'a>> for LocalName<'a> { |
159 | | /// Creates `LocalName` from a [`QName`] |
160 | | /// |
161 | | /// # Examples |
162 | | /// |
163 | | /// ``` |
164 | | /// # use quick_xml::name::{LocalName, QName}; |
165 | | /// |
166 | | /// let local: LocalName = QName(b"unprefixed").into(); |
167 | | /// assert_eq!(local.as_ref(), b"unprefixed"); |
168 | | /// |
169 | | /// let local: LocalName = QName(b"some:prefix").into(); |
170 | | /// assert_eq!(local.as_ref(), b"prefix"); |
171 | | /// ``` |
172 | | #[inline] |
173 | 0 | fn from(name: QName<'a>) -> Self { |
174 | 0 | Self(name.index().map_or(name.0, |i| &name.0[i + 1..])) |
175 | 0 | } |
176 | | } |
177 | | |
178 | | //////////////////////////////////////////////////////////////////////////////////////////////////// |
179 | | |
180 | | /// A [namespace prefix] part of the [qualified name](QName) of an element tag |
181 | | /// or an attribute: a `prefix` in `<prefix:local-element-name>` or |
182 | | /// `prefix:local-attribute-name="attribute value"`. |
183 | | /// |
184 | | /// [namespace prefix]: https://www.w3.org/TR/xml-names11/#dt-prefix |
185 | | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
186 | | #[cfg_attr(feature = "serde-types", derive(serde::Deserialize, serde::Serialize))] |
187 | | pub struct Prefix<'a>(&'a [u8]); |
188 | | impl<'a> Prefix<'a> { |
189 | | /// Extracts internal slice |
190 | | #[inline(always)] |
191 | 0 | pub fn into_inner(self) -> &'a [u8] { |
192 | 0 | self.0 |
193 | 0 | } |
194 | | } |
195 | | impl<'a> Debug for Prefix<'a> { |
196 | 0 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { |
197 | 0 | write!(f, "Prefix(")?; |
198 | 0 | write_byte_string(f, self.0)?; |
199 | 0 | write!(f, ")") |
200 | 0 | } |
201 | | } |
202 | | impl<'a> AsRef<[u8]> for Prefix<'a> { |
203 | | #[inline] |
204 | 0 | fn as_ref(&self) -> &[u8] { |
205 | 0 | self.0 |
206 | 0 | } |
207 | | } |
208 | | |
209 | | //////////////////////////////////////////////////////////////////////////////////////////////////// |
210 | | |
211 | | /// A namespace prefix declaration, `xmlns` or `xmlns:<name>`, as defined in |
212 | | /// [XML Schema specification](https://www.w3.org/TR/xml-names11/#ns-decl) |
213 | | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
214 | | pub enum PrefixDeclaration<'a> { |
215 | | /// XML attribute binds a default namespace. Corresponds to `xmlns` in `xmlns="..."` |
216 | | Default, |
217 | | /// XML attribute binds a specified prefix to a namespace. Corresponds to a |
218 | | /// `prefix` in `xmlns:prefix="..."`, which is stored as payload of this variant. |
219 | | Named(&'a [u8]), |
220 | | } |
221 | | |
222 | | //////////////////////////////////////////////////////////////////////////////////////////////////// |
223 | | |
224 | | /// A [namespace name] that is declared in a `xmlns[:prefix]="namespace name"`. |
225 | | /// |
226 | | /// [namespace name]: https://www.w3.org/TR/xml-names11/#dt-NSName |
227 | | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
228 | | #[cfg_attr(feature = "serde-types", derive(serde::Deserialize, serde::Serialize))] |
229 | | pub struct Namespace<'a>(pub &'a [u8]); |
230 | | impl<'a> Namespace<'a> { |
231 | | /// Converts this namespace to an internal slice representation. |
232 | | /// |
233 | | /// This is [non-normalized] attribute value, i.e. any entity references is |
234 | | /// not expanded and space characters are not removed. This means, that |
235 | | /// different byte slices, returned from this method, can represent the same |
236 | | /// namespace and would be treated by parser as identical. |
237 | | /// |
238 | | /// For example, if the entity **eacute** has been defined to be **é**, |
239 | | /// the empty tags below all contain namespace declarations binding the |
240 | | /// prefix `p` to the same [IRI reference], `http://example.org/rosé`. |
241 | | /// |
242 | | /// ```xml |
243 | | /// <p:foo xmlns:p="http://example.org/rosé" /> |
244 | | /// <p:foo xmlns:p="http://example.org/rosé" /> |
245 | | /// <p:foo xmlns:p="http://example.org/rosé" /> |
246 | | /// <p:foo xmlns:p="http://example.org/rosé" /> |
247 | | /// <p:foo xmlns:p="http://example.org/rosé" /> |
248 | | /// ``` |
249 | | /// |
250 | | /// This is because XML entity references are expanded during attribute value |
251 | | /// normalization. |
252 | | /// |
253 | | /// [non-normalized]: https://www.w3.org/TR/xml11/#AVNormalize |
254 | | /// [IRI reference]: https://datatracker.ietf.org/doc/html/rfc3987 |
255 | | #[inline(always)] |
256 | 0 | pub fn into_inner(self) -> &'a [u8] { |
257 | 0 | self.0 |
258 | 0 | } |
259 | | //TODO: implement value normalization and use it when comparing namespaces |
260 | | } |
261 | | impl<'a> Debug for Namespace<'a> { |
262 | 0 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { |
263 | 0 | write!(f, "Namespace(")?; |
264 | 0 | write_byte_string(f, self.0)?; |
265 | 0 | write!(f, ")") |
266 | 0 | } |
267 | | } |
268 | | impl<'a> AsRef<[u8]> for Namespace<'a> { |
269 | | #[inline] |
270 | 0 | fn as_ref(&self) -> &[u8] { |
271 | 0 | self.0 |
272 | 0 | } |
273 | | } |
274 | | |
275 | | //////////////////////////////////////////////////////////////////////////////////////////////////// |
276 | | |
277 | | /// Result of [prefix] resolution which creates by [`NsReader::resolve_attribute`], |
278 | | /// [`NsReader::resolve_element`], [`NsReader::read_resolved_event`] and |
279 | | /// [`NsReader::read_resolved_event_into`] methods. |
280 | | /// |
281 | | /// [prefix]: Prefix |
282 | | /// [`NsReader::resolve_attribute`]: crate::reader::NsReader::resolve_attribute |
283 | | /// [`NsReader::resolve_element`]: crate::reader::NsReader::resolve_element |
284 | | /// [`NsReader::read_resolved_event`]: crate::reader::NsReader::read_resolved_event |
285 | | /// [`NsReader::read_resolved_event_into`]: crate::reader::NsReader::read_resolved_event_into |
286 | | #[derive(Clone, PartialEq, Eq, Hash)] |
287 | | pub enum ResolveResult<'ns> { |
288 | | /// Qualified name does not contain prefix, and resolver does not define |
289 | | /// default namespace, so name is not bound to any namespace |
290 | | Unbound, |
291 | | /// [`Prefix`] resolved to the specified namespace |
292 | | Bound(Namespace<'ns>), |
293 | | /// Specified prefix was not found in scope |
294 | | Unknown(Vec<u8>), |
295 | | } |
296 | | impl<'ns> Debug for ResolveResult<'ns> { |
297 | 0 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { |
298 | 0 | match self { |
299 | 0 | Self::Unbound => write!(f, "Unbound"), |
300 | 0 | Self::Bound(ns) => write!(f, "Bound({:?})", ns), |
301 | 0 | Self::Unknown(p) => { |
302 | 0 | write!(f, "Unknown(")?; |
303 | 0 | write_byte_string(f, p)?; |
304 | 0 | write!(f, ")") |
305 | | } |
306 | | } |
307 | 0 | } |
308 | | } |
309 | | |
310 | | impl<'ns> TryFrom<ResolveResult<'ns>> for Option<Namespace<'ns>> { |
311 | | type Error = Error; |
312 | | |
313 | | /// Try to convert this result to an optional namespace and returns |
314 | | /// [`Error::UnknownPrefix`] if this result represents unknown prefix |
315 | 0 | fn try_from(result: ResolveResult<'ns>) -> Result<Self> { |
316 | | use ResolveResult::*; |
317 | | |
318 | 0 | match result { |
319 | 0 | Unbound => Ok(None), |
320 | 0 | Bound(ns) => Ok(Some(ns)), |
321 | 0 | Unknown(p) => Err(Error::UnknownPrefix(p)), |
322 | | } |
323 | 0 | } |
324 | | } |
325 | | |
326 | | //////////////////////////////////////////////////////////////////////////////////////////////////// |
327 | | |
328 | | /// An entry that contains index into the buffer with namespace bindings. |
329 | | /// |
330 | | /// Defines a mapping from *[namespace prefix]* to *[namespace name]*. |
331 | | /// If prefix is empty, defines a *default namespace* binding that applies to |
332 | | /// unprefixed element names (unprefixed attribute names do not bind to any |
333 | | /// namespace and they processing is dependent on the element in which their |
334 | | /// defined). |
335 | | /// |
336 | | /// [namespace prefix]: https://www.w3.org/TR/xml-names11/#dt-prefix |
337 | | /// [namespace name]: https://www.w3.org/TR/xml-names11/#dt-NSName |
338 | | #[derive(Debug, Clone)] |
339 | | struct NamespaceEntry { |
340 | | /// Index of the namespace in the buffer |
341 | | start: usize, |
342 | | /// Length of the prefix |
343 | | /// * if greater than zero, then binds this namespace to the slice |
344 | | /// `[start..start + prefix_len]` in the buffer. |
345 | | /// * else defines the current default namespace. |
346 | | prefix_len: usize, |
347 | | /// The length of a namespace name (the URI) of this namespace declaration. |
348 | | /// Name started just after prefix and extend for `value_len` bytes. |
349 | | /// |
350 | | /// The XML standard [specifies] that an empty namespace value 'removes' a namespace declaration |
351 | | /// for the extent of its scope. For prefix declarations that's not very interesting, but it is |
352 | | /// vital for default namespace declarations. With `xmlns=""` you can revert back to the default |
353 | | /// behaviour of leaving unqualified element names unqualified. |
354 | | /// |
355 | | /// [specifies]: https://www.w3.org/TR/xml-names11/#scoping |
356 | | value_len: usize, |
357 | | /// Level of nesting at which this namespace was declared. The declaring element is included, |
358 | | /// i.e., a declaration on the document root has `level = 1`. |
359 | | /// This is used to pop the namespace when the element gets closed. |
360 | | level: i32, |
361 | | } |
362 | | |
363 | | impl NamespaceEntry { |
364 | | /// Get the namespace prefix, bound to this namespace declaration, or `None`, |
365 | | /// if this declaration is for default namespace (`xmlns="..."`). |
366 | | #[inline] |
367 | 0 | fn prefix<'b>(&self, ns_buffer: &'b [u8]) -> Option<Prefix<'b>> { |
368 | 0 | if self.prefix_len == 0 { |
369 | 0 | None |
370 | | } else { |
371 | 0 | Some(Prefix(&ns_buffer[self.start..self.start + self.prefix_len])) |
372 | | } |
373 | 0 | } |
374 | | |
375 | | /// Gets the namespace name (the URI) slice out of namespace buffer |
376 | | /// |
377 | | /// Returns `None` if namespace for this prefix was explicitly removed from |
378 | | /// scope, using `xmlns[:prefix]=""` |
379 | | #[inline] |
380 | 0 | fn namespace<'ns>(&self, buffer: &'ns [u8]) -> ResolveResult<'ns> { |
381 | 0 | if self.value_len == 0 { |
382 | 0 | ResolveResult::Unbound |
383 | | } else { |
384 | 0 | let start = self.start + self.prefix_len; |
385 | 0 | ResolveResult::Bound(Namespace(&buffer[start..start + self.value_len])) |
386 | | } |
387 | 0 | } |
388 | | } |
389 | | |
390 | | /// A namespace management buffer. |
391 | | /// |
392 | | /// Holds all internal logic to push/pop namespaces with their levels. |
393 | | #[derive(Debug, Default, Clone)] |
394 | | pub(crate) struct NamespaceResolver { |
395 | | /// A stack of namespace bindings to prefixes that currently in scope |
396 | | bindings: Vec<NamespaceEntry>, |
397 | | /// The number of open tags at the moment. We need to keep track of this to know which namespace |
398 | | /// declarations to remove when we encounter an `End` event. |
399 | | nesting_level: i32, |
400 | | } |
401 | | |
402 | | impl NamespaceResolver { |
403 | | /// Begins a new scope and add to it all [namespace bindings] that found in |
404 | | /// the specified start element. |
405 | | /// |
406 | | /// [namespace binding]: https://www.w3.org/TR/xml-names11/#dt-NSDecl |
407 | 0 | pub fn push(&mut self, start: &BytesStart, buffer: &mut Vec<u8>) { |
408 | 0 | self.nesting_level += 1; |
409 | 0 | let level = self.nesting_level; |
410 | | // adds new namespaces for attributes starting with 'xmlns:' and for the 'xmlns' |
411 | | // (default namespace) attribute. |
412 | 0 | for a in start.attributes().with_checks(false) { |
413 | 0 | if let Ok(Attribute { key: k, value: v }) = a { |
414 | 0 | match k.as_namespace_binding() { |
415 | 0 | Some(PrefixDeclaration::Default) => { |
416 | 0 | let start = buffer.len(); |
417 | 0 | buffer.extend_from_slice(&v); |
418 | 0 | self.bindings.push(NamespaceEntry { |
419 | 0 | start, |
420 | 0 | prefix_len: 0, |
421 | 0 | value_len: v.len(), |
422 | 0 | level, |
423 | 0 | }); |
424 | 0 | } |
425 | 0 | Some(PrefixDeclaration::Named(prefix)) => { |
426 | 0 | let start = buffer.len(); |
427 | 0 | buffer.extend_from_slice(prefix); |
428 | 0 | buffer.extend_from_slice(&v); |
429 | 0 | self.bindings.push(NamespaceEntry { |
430 | 0 | start, |
431 | 0 | prefix_len: prefix.len(), |
432 | 0 | value_len: v.len(), |
433 | 0 | level, |
434 | 0 | }); |
435 | 0 | } |
436 | 0 | None => {} |
437 | | } |
438 | | } else { |
439 | 0 | break; |
440 | | } |
441 | | } |
442 | 0 | } |
443 | | |
444 | | /// Ends a top-most scope by popping all [namespace binding], that was added by |
445 | | /// last call to [`Self::push()`]. |
446 | | /// |
447 | | /// [namespace binding]: https://www.w3.org/TR/xml-names11/#dt-NSDecl |
448 | 0 | pub fn pop(&mut self, buffer: &mut Vec<u8>) { |
449 | 0 | self.nesting_level -= 1; |
450 | 0 | let current_level = self.nesting_level; |
451 | 0 | // from the back (most deeply nested scope), look for the first scope that is still valid |
452 | 0 | match self.bindings.iter().rposition(|n| n.level <= current_level) { |
453 | | // none of the namespaces are valid, remove all of them |
454 | 0 | None => { |
455 | 0 | buffer.clear(); |
456 | 0 | self.bindings.clear(); |
457 | 0 | } |
458 | | // drop all namespaces past the last valid namespace |
459 | 0 | Some(last_valid_pos) => { |
460 | 0 | if let Some(len) = self.bindings.get(last_valid_pos + 1).map(|n| n.start) { |
461 | 0 | buffer.truncate(len); |
462 | 0 | self.bindings.truncate(last_valid_pos + 1); |
463 | 0 | } |
464 | | } |
465 | | } |
466 | 0 | } |
467 | | |
468 | | /// Resolves a potentially qualified **element name** or **attribute name** |
469 | | /// into (namespace name, local name). |
470 | | /// |
471 | | /// *Qualified* names have the form `prefix:local-name` where the `prefix` is |
472 | | /// defined on any containing XML element via `xmlns:prefix="the:namespace:uri"`. |
473 | | /// The namespace prefix can be defined on the same element as the element or |
474 | | /// attribute in question. |
475 | | /// |
476 | | /// *Unqualified* attribute names do *not* inherit the current *default namespace*. |
477 | | /// |
478 | | /// # Lifetimes |
479 | | /// |
480 | | /// - `'n`: lifetime of an attribute or an element name |
481 | | /// - `'ns`: lifetime of a namespaces buffer, where all found namespaces are stored |
482 | | #[inline] |
483 | 0 | pub fn resolve<'n, 'ns>( |
484 | 0 | &self, |
485 | 0 | name: QName<'n>, |
486 | 0 | buffer: &'ns [u8], |
487 | 0 | use_default: bool, |
488 | 0 | ) -> (ResolveResult<'ns>, LocalName<'n>) { |
489 | 0 | let (local_name, prefix) = name.decompose(); |
490 | 0 | (self.resolve_prefix(prefix, buffer, use_default), local_name) |
491 | 0 | } |
492 | | |
493 | | /// Finds a [namespace name] for a given qualified **element name**, borrow |
494 | | /// it from the specified buffer. |
495 | | /// |
496 | | /// Returns `None`, if: |
497 | | /// - name is unqualified |
498 | | /// - prefix not found in the current scope |
499 | | /// - prefix was [unbound] using `xmlns:prefix=""` |
500 | | /// |
501 | | /// # Lifetimes |
502 | | /// |
503 | | /// - `'ns`: lifetime of a namespaces buffer, where all found namespaces are stored |
504 | | /// |
505 | | /// [namespace name]: https://www.w3.org/TR/xml-names11/#dt-NSName |
506 | | /// [unbound]: https://www.w3.org/TR/xml-names11/#scoping |
507 | | #[inline] |
508 | 0 | pub fn find<'ns>(&self, element_name: QName, buffer: &'ns [u8]) -> ResolveResult<'ns> { |
509 | 0 | self.resolve_prefix(element_name.prefix(), buffer, true) |
510 | 0 | } |
511 | | |
512 | 0 | fn resolve_prefix<'ns>( |
513 | 0 | &self, |
514 | 0 | prefix: Option<Prefix>, |
515 | 0 | buffer: &'ns [u8], |
516 | 0 | use_default: bool, |
517 | 0 | ) -> ResolveResult<'ns> { |
518 | 0 | self.bindings |
519 | 0 | .iter() |
520 | 0 | // Find the last defined binding that corresponds to the given prefix |
521 | 0 | .rev() |
522 | 0 | .find_map(|n| match (n.prefix(buffer), prefix) { |
523 | | // This is default namespace definition and name has no explicit prefix |
524 | 0 | (None, None) if use_default => Some(n.namespace(buffer)), |
525 | 0 | (None, None) => Some(ResolveResult::Unbound), |
526 | | |
527 | | // One part has prefix but other is not -> skip |
528 | 0 | (None, Some(_)) => None, |
529 | 0 | (Some(_), None) => None, |
530 | | |
531 | | // Prefixes does not match -> skip |
532 | 0 | (Some(definition), Some(usage)) if definition != usage => None, |
533 | | |
534 | | // Prefixes the same, entry defines binding reset (corresponds to `xmlns:p=""`) |
535 | 0 | _ if n.value_len == 0 => Some(Self::maybe_unknown(prefix)), |
536 | | // Prefixes the same, returns corresponding namespace |
537 | 0 | _ => Some(n.namespace(buffer)), |
538 | 0 | }) |
539 | 0 | .unwrap_or_else(|| Self::maybe_unknown(prefix)) |
540 | 0 | } |
541 | | |
542 | | #[inline] |
543 | 0 | fn maybe_unknown(prefix: Option<Prefix>) -> ResolveResult<'static> { |
544 | 0 | match prefix { |
545 | 0 | Some(p) => ResolveResult::Unknown(p.into_inner().to_vec()), |
546 | 0 | None => ResolveResult::Unbound, |
547 | | } |
548 | 0 | } |
549 | | } |
550 | | |
551 | | #[cfg(test)] |
552 | | mod namespaces { |
553 | | use super::*; |
554 | | use pretty_assertions::assert_eq; |
555 | | use ResolveResult::*; |
556 | | |
557 | | /// Unprefixed attribute names (resolved with `false` flag) never have a namespace |
558 | | /// according to <https://www.w3.org/TR/xml-names11/#defaulting>: |
559 | | /// |
560 | | /// > A default namespace declaration applies to all unprefixed element names |
561 | | /// > within its scope. Default namespace declarations do not apply directly |
562 | | /// > to attribute names; the interpretation of unprefixed attributes is |
563 | | /// > determined by the element on which they appear. |
564 | | mod unprefixed { |
565 | | use super::*; |
566 | | use pretty_assertions::assert_eq; |
567 | | |
568 | | /// Basic tests that checks that basic resolver functionality is working |
569 | | #[test] |
570 | | fn basic() { |
571 | | let name = QName(b"simple"); |
572 | | let ns = Namespace(b"default"); |
573 | | |
574 | | let mut resolver = NamespaceResolver::default(); |
575 | | let mut buffer = Vec::new(); |
576 | | |
577 | | resolver.push( |
578 | | &BytesStart::from_content(" xmlns='default'", 0), |
579 | | &mut buffer, |
580 | | ); |
581 | | assert_eq!(buffer, b"default"); |
582 | | |
583 | | // Check that tags without namespaces does not change result |
584 | | resolver.push(&BytesStart::from_content("", 0), &mut buffer); |
585 | | assert_eq!(buffer, b"default"); |
586 | | resolver.pop(&mut buffer); |
587 | | |
588 | | assert_eq!(buffer, b"default"); |
589 | | assert_eq!( |
590 | | resolver.resolve(name, &buffer, true), |
591 | | (Bound(ns), LocalName(b"simple")) |
592 | | ); |
593 | | assert_eq!( |
594 | | resolver.resolve(name, &buffer, false), |
595 | | (Unbound, LocalName(b"simple")) |
596 | | ); |
597 | | assert_eq!(resolver.find(name, &buffer), Bound(ns)); |
598 | | } |
599 | | |
600 | | /// Test adding a second level of namespaces, which replaces the previous binding |
601 | | #[test] |
602 | | fn override_namespace() { |
603 | | let name = QName(b"simple"); |
604 | | let old_ns = Namespace(b"old"); |
605 | | let new_ns = Namespace(b"new"); |
606 | | |
607 | | let mut resolver = NamespaceResolver::default(); |
608 | | let mut buffer = Vec::new(); |
609 | | |
610 | | resolver.push(&BytesStart::from_content(" xmlns='old'", 0), &mut buffer); |
611 | | resolver.push(&BytesStart::from_content(" xmlns='new'", 0), &mut buffer); |
612 | | |
613 | | assert_eq!(buffer, b"oldnew"); |
614 | | assert_eq!( |
615 | | resolver.resolve(name, &buffer, true), |
616 | | (Bound(new_ns), LocalName(b"simple")) |
617 | | ); |
618 | | assert_eq!( |
619 | | resolver.resolve(name, &buffer, false), |
620 | | (Unbound, LocalName(b"simple")) |
621 | | ); |
622 | | assert_eq!(resolver.find(name, &buffer), Bound(new_ns)); |
623 | | |
624 | | resolver.pop(&mut buffer); |
625 | | assert_eq!(buffer, b"old"); |
626 | | assert_eq!( |
627 | | resolver.resolve(name, &buffer, true), |
628 | | (Bound(old_ns), LocalName(b"simple")) |
629 | | ); |
630 | | assert_eq!( |
631 | | resolver.resolve(name, &buffer, false), |
632 | | (Unbound, LocalName(b"simple")) |
633 | | ); |
634 | | assert_eq!(resolver.find(name, &buffer), Bound(old_ns)); |
635 | | } |
636 | | |
637 | | /// Test adding a second level of namespaces, which reset the previous binding |
638 | | /// to not bound state by specifying an empty namespace name. |
639 | | /// |
640 | | /// See <https://www.w3.org/TR/xml-names11/#scoping> |
641 | | #[test] |
642 | | fn reset() { |
643 | | let name = QName(b"simple"); |
644 | | let old_ns = Namespace(b"old"); |
645 | | |
646 | | let mut resolver = NamespaceResolver::default(); |
647 | | let mut buffer = Vec::new(); |
648 | | |
649 | | resolver.push(&BytesStart::from_content(" xmlns='old'", 0), &mut buffer); |
650 | | resolver.push(&BytesStart::from_content(" xmlns=''", 0), &mut buffer); |
651 | | |
652 | | assert_eq!(buffer, b"old"); |
653 | | assert_eq!( |
654 | | resolver.resolve(name, &buffer, true), |
655 | | (Unbound, LocalName(b"simple")) |
656 | | ); |
657 | | assert_eq!( |
658 | | resolver.resolve(name, &buffer, false), |
659 | | (Unbound, LocalName(b"simple")) |
660 | | ); |
661 | | assert_eq!(resolver.find(name, &buffer), Unbound); |
662 | | |
663 | | resolver.pop(&mut buffer); |
664 | | assert_eq!(buffer, b"old"); |
665 | | assert_eq!( |
666 | | resolver.resolve(name, &buffer, true), |
667 | | (Bound(old_ns), LocalName(b"simple")) |
668 | | ); |
669 | | assert_eq!( |
670 | | resolver.resolve(name, &buffer, false), |
671 | | (Unbound, LocalName(b"simple")) |
672 | | ); |
673 | | assert_eq!(resolver.find(name, &buffer), Bound(old_ns)); |
674 | | } |
675 | | } |
676 | | |
677 | | mod declared_prefix { |
678 | | use super::*; |
679 | | use pretty_assertions::assert_eq; |
680 | | |
681 | | /// Basic tests that checks that basic resolver functionality is working |
682 | | #[test] |
683 | | fn basic() { |
684 | | let name = QName(b"p:with-declared-prefix"); |
685 | | let ns = Namespace(b"default"); |
686 | | |
687 | | let mut resolver = NamespaceResolver::default(); |
688 | | let mut buffer = Vec::new(); |
689 | | |
690 | | resolver.push( |
691 | | &BytesStart::from_content(" xmlns:p='default'", 0), |
692 | | &mut buffer, |
693 | | ); |
694 | | assert_eq!(buffer, b"pdefault"); |
695 | | |
696 | | // Check that tags without namespaces does not change result |
697 | | resolver.push(&BytesStart::from_content("", 0), &mut buffer); |
698 | | assert_eq!(buffer, b"pdefault"); |
699 | | resolver.pop(&mut buffer); |
700 | | |
701 | | assert_eq!(buffer, b"pdefault"); |
702 | | assert_eq!( |
703 | | resolver.resolve(name, &buffer, true), |
704 | | (Bound(ns), LocalName(b"with-declared-prefix")) |
705 | | ); |
706 | | assert_eq!( |
707 | | resolver.resolve(name, &buffer, false), |
708 | | (Bound(ns), LocalName(b"with-declared-prefix")) |
709 | | ); |
710 | | assert_eq!(resolver.find(name, &buffer), Bound(ns)); |
711 | | } |
712 | | |
713 | | /// Test adding a second level of namespaces, which replaces the previous binding |
714 | | #[test] |
715 | | fn override_namespace() { |
716 | | let name = QName(b"p:with-declared-prefix"); |
717 | | let old_ns = Namespace(b"old"); |
718 | | let new_ns = Namespace(b"new"); |
719 | | |
720 | | let mut resolver = NamespaceResolver::default(); |
721 | | let mut buffer = Vec::new(); |
722 | | |
723 | | resolver.push(&BytesStart::from_content(" xmlns:p='old'", 0), &mut buffer); |
724 | | resolver.push(&BytesStart::from_content(" xmlns:p='new'", 0), &mut buffer); |
725 | | |
726 | | assert_eq!(buffer, b"poldpnew"); |
727 | | assert_eq!( |
728 | | resolver.resolve(name, &buffer, true), |
729 | | (Bound(new_ns), LocalName(b"with-declared-prefix")) |
730 | | ); |
731 | | assert_eq!( |
732 | | resolver.resolve(name, &buffer, false), |
733 | | (Bound(new_ns), LocalName(b"with-declared-prefix")) |
734 | | ); |
735 | | assert_eq!(resolver.find(name, &buffer), Bound(new_ns)); |
736 | | |
737 | | resolver.pop(&mut buffer); |
738 | | assert_eq!(buffer, b"pold"); |
739 | | assert_eq!( |
740 | | resolver.resolve(name, &buffer, true), |
741 | | (Bound(old_ns), LocalName(b"with-declared-prefix")) |
742 | | ); |
743 | | assert_eq!( |
744 | | resolver.resolve(name, &buffer, false), |
745 | | (Bound(old_ns), LocalName(b"with-declared-prefix")) |
746 | | ); |
747 | | assert_eq!(resolver.find(name, &buffer), Bound(old_ns)); |
748 | | } |
749 | | |
750 | | /// Test adding a second level of namespaces, which reset the previous binding |
751 | | /// to not bound state by specifying an empty namespace name. |
752 | | /// |
753 | | /// See <https://www.w3.org/TR/xml-names11/#scoping> |
754 | | #[test] |
755 | | fn reset() { |
756 | | let name = QName(b"p:with-declared-prefix"); |
757 | | let old_ns = Namespace(b"old"); |
758 | | |
759 | | let mut resolver = NamespaceResolver::default(); |
760 | | let mut buffer = Vec::new(); |
761 | | |
762 | | resolver.push(&BytesStart::from_content(" xmlns:p='old'", 0), &mut buffer); |
763 | | resolver.push(&BytesStart::from_content(" xmlns:p=''", 0), &mut buffer); |
764 | | |
765 | | assert_eq!(buffer, b"poldp"); |
766 | | assert_eq!( |
767 | | resolver.resolve(name, &buffer, true), |
768 | | (Unknown(b"p".to_vec()), LocalName(b"with-declared-prefix")) |
769 | | ); |
770 | | assert_eq!( |
771 | | resolver.resolve(name, &buffer, false), |
772 | | (Unknown(b"p".to_vec()), LocalName(b"with-declared-prefix")) |
773 | | ); |
774 | | assert_eq!(resolver.find(name, &buffer), Unknown(b"p".to_vec())); |
775 | | |
776 | | resolver.pop(&mut buffer); |
777 | | assert_eq!(buffer, b"pold"); |
778 | | assert_eq!( |
779 | | resolver.resolve(name, &buffer, true), |
780 | | (Bound(old_ns), LocalName(b"with-declared-prefix")) |
781 | | ); |
782 | | assert_eq!( |
783 | | resolver.resolve(name, &buffer, false), |
784 | | (Bound(old_ns), LocalName(b"with-declared-prefix")) |
785 | | ); |
786 | | assert_eq!(resolver.find(name, &buffer), Bound(old_ns)); |
787 | | } |
788 | | } |
789 | | |
790 | | #[test] |
791 | | fn undeclared_prefix() { |
792 | | let name = QName(b"unknown:prefix"); |
793 | | |
794 | | let resolver = NamespaceResolver::default(); |
795 | | let buffer = Vec::new(); |
796 | | |
797 | | assert_eq!(buffer, b""); |
798 | | assert_eq!( |
799 | | resolver.resolve(name, &buffer, true), |
800 | | (Unknown(b"unknown".to_vec()), LocalName(b"prefix")) |
801 | | ); |
802 | | assert_eq!( |
803 | | resolver.resolve(name, &buffer, false), |
804 | | (Unknown(b"unknown".to_vec()), LocalName(b"prefix")) |
805 | | ); |
806 | | assert_eq!(resolver.find(name, &buffer), Unknown(b"unknown".to_vec())); |
807 | | } |
808 | | |
809 | | /// Checks how the QName is decomposed to a prefix and a local name |
810 | | #[test] |
811 | | fn prefix_and_local_name() { |
812 | | let name = QName(b"foo:bus"); |
813 | | assert_eq!(name.prefix(), Some(Prefix(b"foo"))); |
814 | | assert_eq!(name.local_name(), LocalName(b"bus")); |
815 | | assert_eq!(name.decompose(), (LocalName(b"bus"), Some(Prefix(b"foo")))); |
816 | | |
817 | | let name = QName(b"foo:"); |
818 | | assert_eq!(name.prefix(), Some(Prefix(b"foo"))); |
819 | | assert_eq!(name.local_name(), LocalName(b"")); |
820 | | assert_eq!(name.decompose(), (LocalName(b""), Some(Prefix(b"foo")))); |
821 | | |
822 | | let name = QName(b":foo"); |
823 | | assert_eq!(name.prefix(), Some(Prefix(b""))); |
824 | | assert_eq!(name.local_name(), LocalName(b"foo")); |
825 | | assert_eq!(name.decompose(), (LocalName(b"foo"), Some(Prefix(b"")))); |
826 | | |
827 | | let name = QName(b"foo:bus:baz"); |
828 | | assert_eq!(name.prefix(), Some(Prefix(b"foo"))); |
829 | | assert_eq!(name.local_name(), LocalName(b"bus:baz")); |
830 | | assert_eq!( |
831 | | name.decompose(), |
832 | | (LocalName(b"bus:baz"), Some(Prefix(b"foo"))) |
833 | | ); |
834 | | } |
835 | | } |