Coverage Report

Created: 2025-02-21 07:11

/rust/registry/src/index.crates.io-6f17d22bba15001f/markup5ever-0.12.1/interface/mod.rs
Line
Count
Source (jump to first uncovered line)
1
// Copyright 2014-2017 The html5ever Project Developers. See the
2
// COPYRIGHT file at the top-level directory of this distribution.
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
//! Types for tag and attribute names, and tree-builder functionality.
10
11
use std::fmt;
12
use tendril::StrTendril;
13
14
pub use self::tree_builder::{create_element, AppendNode, AppendText, ElementFlags, NodeOrText};
15
pub use self::tree_builder::{LimitedQuirks, NoQuirks, Quirks, QuirksMode};
16
pub use self::tree_builder::{NextParserState, Tracer, TreeSink};
17
use super::{LocalName, Namespace, Prefix};
18
19
/// An [expanded name], containing the tag and the namespace.
20
///
21
/// [expanded name]: https://www.w3.org/TR/REC-xml-names/#dt-expname
22
#[derive(Copy, Clone, Eq, Hash)]
23
pub struct ExpandedName<'a> {
24
    pub ns: &'a Namespace,
25
    pub local: &'a LocalName,
26
}
27
28
impl<'a, 'b> PartialEq<ExpandedName<'a>> for ExpandedName<'b> {
29
0
    fn eq(&self, other: &ExpandedName<'a>) -> bool {
30
0
        self.ns == other.ns && self.local == other.local
31
0
    }
32
}
33
34
impl<'a> fmt::Debug for ExpandedName<'a> {
35
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
36
0
        if self.ns.is_empty() {
37
0
            write!(f, "{}", self.local)
38
        } else {
39
0
            write!(f, "{{{}}}:{}", self.ns, self.local)
40
        }
41
0
    }
42
}
43
44
/// Helper to quickly create an expanded name.
45
///
46
/// Can be used with no namespace as `expanded_name!("", "some_name")`
47
/// or with a namespace as `expanded_name!(ns "some_name")`.  In the
48
/// latter case, `ns` is one of the symbols which the [`ns!`][ns]
49
/// macro accepts; note the lack of a comma between the `ns` and
50
/// `"some_name"`.
51
///
52
/// [ns]: macro.ns.html
53
///
54
/// # Examples
55
///
56
/// ```
57
/// # #[macro_use] extern crate markup5ever;
58
///
59
/// # fn main() {
60
/// use markup5ever::ExpandedName;
61
///
62
/// assert_eq!(
63
///     expanded_name!("", "div"),
64
///     ExpandedName {
65
///         ns: &ns!(),
66
///         local: &local_name!("div")
67
///     }
68
/// );
69
///
70
/// assert_eq!(
71
///     expanded_name!(html "div"),
72
///     ExpandedName {
73
///         ns: &ns!(html),
74
///         local: &local_name!("div")
75
///     }
76
/// );
77
/// # }
78
#[macro_export]
79
macro_rules! expanded_name {
80
    ("", $local: tt) => {
81
        $crate::interface::ExpandedName {
82
            ns: &ns!(),
83
            local: &local_name!($local),
84
        }
85
    };
86
    ($ns: ident $local: tt) => {
87
        $crate::interface::ExpandedName {
88
            ns: &ns!($ns),
89
            local: &local_name!($local),
90
        }
91
    };
92
}
93
94
pub mod tree_builder;
95
96
/// A fully qualified name (with a namespace), used to depict names of tags and attributes.
97
///
98
/// Namespaces can be used to differentiate between similar XML fragments. For example:
99
///
100
/// ```text
101
/// // HTML
102
/// <table>
103
///   <tr>
104
///     <td>Apples</td>
105
///     <td>Bananas</td>
106
///   </tr>
107
/// </table>
108
///
109
/// // Furniture XML
110
/// <table>
111
///   <name>African Coffee Table</name>
112
///   <width>80</width>
113
///   <length>120</length>
114
/// </table>
115
/// ```
116
///
117
/// Without XML namespaces, we can't use those two fragments in the same document
118
/// at the same time. However if we declare a namespace we could instead say:
119
///
120
/// ```text
121
///
122
/// // Furniture XML
123
/// <furn:table xmlns:furn="https://furniture.rs">
124
///   <furn:name>African Coffee Table</furn:name>
125
///   <furn:width>80</furn:width>
126
///   <furn:length>120</furn:length>
127
/// </furn:table>
128
/// ```
129
///
130
/// and bind the prefix `furn` to a different namespace.
131
///
132
/// For this reason we parse names that contain a colon in the following way:
133
///
134
/// ```text
135
/// <furn:table>
136
///    |    |
137
///    |    +- local name
138
///    |
139
///  prefix (when resolved gives namespace_url `https://furniture.rs`)
140
/// ```
141
///
142
/// NOTE: `Prefix`, `LocalName` and `Prefix` are all derivative of
143
/// `string_cache::atom::Atom` and `Atom` implements `Deref<str>`.
144
///
145
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone)]
146
#[cfg_attr(feature = "heap_size", derive(HeapSizeOf))]
147
pub struct QualName {
148
    /// The prefix of qualified (e.g. `furn` in `<furn:table>` above).
149
    /// Optional (since some namespaces can be empty or inferred), and
150
    /// only useful for namespace resolution (since different prefix
151
    /// can still resolve to same namespace)
152
    ///
153
    /// ```
154
    ///
155
    /// # fn main() {
156
    /// use markup5ever::{QualName, Namespace, LocalName, Prefix};
157
    ///
158
    /// let qual = QualName::new(
159
    ///     Some(Prefix::from("furn")),
160
    ///     Namespace::from("https://furniture.rs"),
161
    ///     LocalName::from("table"),
162
    /// );
163
    ///
164
    /// assert_eq!("furn", &qual.prefix.unwrap());
165
    ///
166
    /// # }
167
    /// ```
168
    pub prefix: Option<Prefix>,
169
    /// The namespace after resolution (e.g. `https://furniture.rs` in example above).
170
    ///
171
    /// ```
172
    /// # use markup5ever::{QualName, Namespace, LocalName, Prefix};
173
    ///
174
    /// # fn main() {
175
    /// # let qual = QualName::new(
176
    /// #    Some(Prefix::from("furn")),
177
    /// #    Namespace::from("https://furniture.rs"),
178
    /// #    LocalName::from("table"),
179
    /// # );
180
    ///
181
    /// assert_eq!("https://furniture.rs", &qual.ns);
182
    /// # }
183
    /// ```
184
    ///
185
    /// When matching namespaces used by HTML we can use `ns!` macro.
186
    /// Although keep in mind that ns! macro only works with namespaces
187
    /// that are present in HTML spec (like `html`, `xmlns`, `svg`, etc.).
188
    ///
189
    /// ```
190
    /// #[macro_use] extern crate markup5ever;
191
    ///
192
    /// # use markup5ever::{QualName, Namespace, LocalName, Prefix};
193
    ///
194
    /// let html_table = QualName::new(
195
    ///    None,
196
    ///    ns!(html),
197
    ///    LocalName::from("table"),
198
    /// );
199
    ///
200
    /// assert!(
201
    ///   match html_table.ns {
202
    ///     ns!(html) => true,
203
    ///     _ => false,
204
    ///   }
205
    /// );
206
    ///
207
    /// ```
208
    pub ns: Namespace,
209
    /// The local name (e.g. `table` in `<furn:table>` above).
210
    ///
211
    /// ```
212
    /// # use markup5ever::{QualName, Namespace, LocalName, Prefix};
213
    ///
214
    /// # fn main() {
215
    /// # let qual = QualName::new(
216
    /// #    Some(Prefix::from("furn")),
217
    /// #    Namespace::from("https://furniture.rs"),
218
    /// #    LocalName::from("table"),
219
    /// # );
220
    ///
221
    /// assert_eq!("table", &qual.local);
222
    /// # }
223
    /// ```
224
    /// When matching local name we can also use the `local_name!` macro:
225
    ///
226
    /// ```
227
    /// #[macro_use] extern crate markup5ever;
228
    ///
229
    /// # use markup5ever::{QualName, Namespace, LocalName, Prefix};
230
    ///
231
    /// # let qual = QualName::new(
232
    /// #    Some(Prefix::from("furn")),
233
    /// #    Namespace::from("https://furniture.rs"),
234
    /// #    LocalName::from("table"),
235
    /// # );
236
    ///
237
    /// // Initialize qual to furniture example
238
    ///
239
    /// assert!(
240
    ///   match qual.local {
241
    ///     local_name!("table") => true,
242
    ///     _ => false,
243
    ///   }
244
    /// );
245
    ///
246
    /// ```
247
    pub local: LocalName,
248
}
249
250
impl QualName {
251
    /// Basic constructor function.
252
    ///
253
    /// First let's try it for the following example where `QualName`
254
    /// is defined as:
255
    /// ```text
256
    /// <furn:table> <!-- namespace url is https://furniture.rs -->
257
    /// ```
258
    ///
259
    /// Given this definition, we can define `QualName` using strings.
260
    ///
261
    /// ```
262
    /// use markup5ever::{QualName, Namespace, LocalName, Prefix};
263
    ///
264
    /// # fn main() {
265
    /// let qual_name = QualName::new(
266
    ///     Some(Prefix::from("furn")),
267
    ///     Namespace::from("https://furniture.rs"),
268
    ///     LocalName::from("table"),
269
    /// );
270
    /// # }
271
    /// ```
272
    ///
273
    /// If we were instead to construct this element instead:
274
    ///
275
    /// ```text
276
    ///
277
    /// <table>
278
    ///  ^^^^^---- no prefix and thus default html namespace
279
    ///
280
    /// ```
281
    ///
282
    /// Or could define it using macros, like so:
283
    ///
284
    /// ```
285
    /// #[macro_use] extern crate markup5ever;
286
    /// use markup5ever::{QualName, Namespace, LocalName, Prefix};
287
    ///
288
    /// # fn main() {
289
    /// let qual_name = QualName::new(
290
    ///     None,
291
    ///     ns!(html),
292
    ///     local_name!("table")
293
    /// );
294
    /// # }
295
    /// ```
296
    ///
297
    /// Let's analyse the above example.
298
    /// Since we have no prefix its value is None. Second we have html namespace.
299
    /// In html5ever html namespaces are supported out of the box,
300
    /// we can write `ns!(html)` instead of typing `Namespace::from("http://www.w3.org/1999/xhtml")`.
301
    /// Local name is also one of the HTML elements local names, so can
302
    /// use `local_name!("table")` macro.
303
    ///
304
    #[inline]
305
0
    pub fn new(prefix: Option<Prefix>, ns: Namespace, local: LocalName) -> QualName {
306
0
        QualName { prefix, ns, local }
307
0
    }
Unexecuted instantiation: <markup5ever::interface::QualName>::new
Unexecuted instantiation: <markup5ever::interface::QualName>::new
308
309
    /// Take a reference of `self` as an `ExpandedName`, dropping the unresolved prefix.
310
    ///
311
    /// In XML and HTML prefixes are only used to extract the relevant namespace URI.
312
    /// Expanded name only contains resolved namespace and tag name, which are only
313
    /// relevant parts of an XML or HTML tag and attribute name respectively.
314
    ///
315
    /// In lieu of our XML Namespace example
316
    ///
317
    /// ```text
318
    /// <furn:table> <!-- namespace url is https://furniture.rs -->
319
    /// ```
320
    /// For it the expanded name would become roughly equivalent to:
321
    ///
322
    /// ```text
323
    /// ExpandedName {
324
    ///    ns: "https://furniture.rs",
325
    ///    local: "table",
326
    /// }
327
    /// ```
328
    ///
329
    #[inline]
330
0
    pub fn expanded(&self) -> ExpandedName {
331
0
        ExpandedName {
332
0
            ns: &self.ns,
333
0
            local: &self.local,
334
0
        }
335
0
    }
Unexecuted instantiation: <markup5ever::interface::QualName>::expanded
Unexecuted instantiation: <markup5ever::interface::QualName>::expanded
336
}
337
338
/// A tag attribute, e.g. `class="test"` in `<div class="test" ...>`.
339
///
340
/// The namespace on the attribute name is almost always ns!("").
341
/// The tokenizer creates all attributes this way, but the tree
342
/// builder will adjust certain attribute names inside foreign
343
/// content (MathML, SVG).
344
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)]
345
pub struct Attribute {
346
    /// The name of the attribute (e.g. the `class` in `<div class="test">`)
347
    pub name: QualName,
348
    /// The value of the attribute (e.g. the `"test"` in `<div class="test">`)
349
    pub value: StrTendril,
350
}
351
352
#[cfg(test)]
353
mod tests {
354
    use super::Namespace;
355
356
    #[test]
357
    fn ns_macro() {
358
        assert_eq!(ns!(), Namespace::from(""));
359
360
        assert_eq!(ns!(html), Namespace::from("http://www.w3.org/1999/xhtml"));
361
        assert_eq!(
362
            ns!(xml),
363
            Namespace::from("http://www.w3.org/XML/1998/namespace")
364
        );
365
        assert_eq!(ns!(xmlns), Namespace::from("http://www.w3.org/2000/xmlns/"));
366
        assert_eq!(ns!(xlink), Namespace::from("http://www.w3.org/1999/xlink"));
367
        assert_eq!(ns!(svg), Namespace::from("http://www.w3.org/2000/svg"));
368
        assert_eq!(
369
            ns!(mathml),
370
            Namespace::from("http://www.w3.org/1998/Math/MathML")
371
        );
372
    }
373
}