rsvg/
href.rs

1//! Handling of `xlink:href` and `href` attributes
2//!
3//! In SVG1.1, links to elements are done with the `xlink:href` attribute.  However, SVG2
4//! reduced this to just plain `href` with no namespace:
5//! <https://svgwg.org/svg2-draft/linking.html#XLinkRefAttrs>
6//!
7//! If an element has both `xlink:href` and `href` attributes, the `href` overrides the
8//! other.  We implement that logic in this module.
9
10use markup5ever::{ExpandedName, expanded_name, local_name, ns};
11
12/// Returns whether the attribute is either of `xlink:href` or `href`.
13///
14/// # Example
15///
16/// Use with an `if` pattern inside a `match`:
17///
18/// ```
19/// # use markup5ever::{expanded_name, local_name, ns, QualName, Prefix, Namespace, LocalName, ExpandedName};
20/// # use rsvg::doctest_only::{is_href,set_href};
21///
22/// let qual_name = QualName::new(
23///     Some(Prefix::from("xlink")),
24///     Namespace::from("http://www.w3.org/1999/xlink"),
25///     LocalName::from("href"),
26/// );
27///
28/// let value = "some_url";
29/// let mut my_field: Option<String> = None;
30///
31/// match qual_name.expanded() {
32///     ref name if is_href(name) => set_href(name, &mut my_field, Some(value.to_string())),
33///     _ => unreachable!(),
34/// }
35/// ```
36pub fn is_href(name: &ExpandedName<'_>) -> bool {
37    matches!(
38        *name,
39        expanded_name!(xlink "href") | expanded_name!("", "href")
40    )
41}
42
43/// Sets an `href` attribute in preference over an `xlink:href` one.
44///
45/// See [`is_href`] for example usage.
46pub fn set_href<T>(name: &ExpandedName<'_>, dest: &mut Option<T>, href: Option<T>) {
47    if dest.is_none() || *name != expanded_name!(xlink "href") {
48        *dest = href;
49    }
50}