Coverage Report

Created: 2025-05-08 06:13

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