Skip to content

Commit 65982bc

Browse files
committed
Add reserved namespace bindings.
This adds xml and xmlns namespace bindings. These are defined at https://www.w3.org/TR/xml-names11/#xmlReserved. This also updates the MSRV to 1.56.
1 parent f957002 commit 65982bc

File tree

3 files changed

+64
-2
lines changed

3 files changed

+64
-2
lines changed

Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ repository = "https://github.com/tafia/quick-xml"
1010
keywords = ["xml", "serde", "parser", "writer", "html"]
1111
categories = ["asynchronous", "encoding", "parsing", "parser-implementations"]
1212
license = "MIT"
13-
rust-version = "1.52"
13+
rust-version = "1.56"
1414
include = ["src/*", "LICENSE-MIT.md", "README.md"]
1515

1616
[dependencies]
@@ -20,6 +20,7 @@ serde = { version = "1.0.100", optional = true }
2020
tokio = { version = "1.10", optional = true, default-features = false, features = ["io-util"] }
2121
memchr = "2.1"
2222
arbitrary = { version = "1.2.3", features = ["derive"], optional = true }
23+
once_cell = ">=0.17.2"
2324

2425
[dev-dependencies]
2526
criterion = "0.4"

Changelog.md

+4
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,14 @@
1212

1313
### New Features
1414

15+
- [#545]: resolve well-known namespaces to their approrpriate URIs
16+
1517
### Bug Fixes
1618

1719
### Misc Changes
1820

21+
- [#545]: bump MSRV to 1.56
22+
1923

2024
## 0.30.0 -- 2023-07-23
2125

src/name.rs

+58-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ use crate::events::attributes::Attribute;
88
use crate::events::BytesStart;
99
use crate::utils::write_byte_string;
1010
use memchr::memchr;
11+
use once_cell::sync::Lazy;
12+
use std::collections::HashMap;
1113
use std::convert::TryFrom;
1214
use std::fmt::{self, Debug, Formatter};
1315

@@ -399,6 +401,32 @@ pub(crate) struct NamespaceResolver {
399401
nesting_level: i32,
400402
}
401403

404+
/// These constants define the reserved namespaces for the xml standard.
405+
///
406+
/// The prefix `xml` is by definition bound to the namespace name
407+
/// `http://www.w3.org/XML/1998/namespace`. It may, but need not, be declared, and must not be
408+
/// undeclared or bound to any other namespace name. Other prefixes must not be bound to this
409+
/// namespace name, and it must not be declared as the default namespace.
410+
///
411+
/// The prefix `xmlns` is used only to declare namespace bindings and is by definition bound
412+
/// to the namespace name http://www.w3.org/2000/xmlns/. It must not be declared or
413+
/// undeclared. Other prefixes must not be bound to this namespace name, and it must not be
414+
/// declared as the default namespace. Element names must not have the prefix xmlns.
415+
///
416+
/// [reserved namespaces]: https://www.w3.org/TR/xml-names11/#xmlReserved
417+
static WELL_KNOWN_NAMESPACES: Lazy<HashMap<Prefix, Namespace>> = Lazy::new(|| {
418+
let mut m = HashMap::new();
419+
m.insert(
420+
Prefix(b"xml"),
421+
Namespace(b"http://www.w3.org/XML/1998/namespace"),
422+
);
423+
m.insert(
424+
Prefix(b"xmlns"),
425+
Namespace(b"http://www.w3.org/2000/xmlns/"),
426+
);
427+
m
428+
});
429+
402430
impl NamespaceResolver {
403431
/// Begins a new scope and add to it all [namespace bindings] that found in
404432
/// the specified start element.
@@ -542,7 +570,10 @@ impl NamespaceResolver {
542570
#[inline]
543571
fn maybe_unknown(prefix: Option<Prefix>) -> ResolveResult<'static> {
544572
match prefix {
545-
Some(p) => ResolveResult::Unknown(p.into_inner().to_vec()),
573+
Some(p) => WELL_KNOWN_NAMESPACES.get(&p).map_or_else(
574+
|| ResolveResult::Unknown(p.into_inner().to_vec()),
575+
|p| ResolveResult::Bound(*p),
576+
),
546577
None => ResolveResult::Unbound,
547578
}
548579
}
@@ -787,6 +818,32 @@ mod namespaces {
787818
}
788819
}
789820

821+
mod builtin_prefixes {
822+
use super::*;
823+
use pretty_assertions::assert_eq;
824+
825+
#[test]
826+
fn undeclared_reserved_prefixes() {
827+
let resolver = NamespaceResolver::default();
828+
let tag = b"random";
829+
830+
for (prefix, namespace) in WELL_KNOWN_NAMESPACES.iter() {
831+
let name_buf = [prefix.into_inner(), tag].join(&b":"[..]);
832+
let name = QName(&name_buf);
833+
834+
assert_eq!(
835+
resolver.resolve(name, b"", true),
836+
(Bound(*namespace), LocalName(tag))
837+
);
838+
assert_eq!(
839+
resolver.resolve(name.clone(), b"", false),
840+
(Bound(*namespace), LocalName(tag))
841+
);
842+
assert_eq!(resolver.find(name.clone(), b""), Bound(*namespace));
843+
}
844+
}
845+
}
846+
790847
#[test]
791848
fn undeclared_prefix() {
792849
let name = QName(b"unknown:prefix");

0 commit comments

Comments
 (0)