minidom: Rework Prefixes internal structure
Change the mapping in Prefixes to Prefix -> Namespace instead of Namespace -> Prefix. This allows us to not have duplicate prefixes anymore, but requires us to store the prefix on Element. This prefix is only taken as a hint anyway and used only when coming from the reader. This commits also partially removes the possibility to add prefixes when creating an Element via `Element::new`, `Element::builder` or `Element::bare`. Proper errors should be added in the following commits. Signed-off-by: Maxime “pep” Buquet <pep@bouah.net>
This commit is contained in:
parent
429949102d
commit
1f2d7aa99d
4 changed files with 106 additions and 93 deletions
|
|
@ -15,7 +15,7 @@
|
||||||
use crate::convert::IntoAttributeValue;
|
use crate::convert::IntoAttributeValue;
|
||||||
use crate::error::{Error, Result};
|
use crate::error::{Error, Result};
|
||||||
use crate::namespaces::NSChoice;
|
use crate::namespaces::NSChoice;
|
||||||
use crate::prefixes::Prefixes;
|
use crate::prefixes::{Prefix, Namespace, Prefixes};
|
||||||
use crate::node::Node;
|
use crate::node::Node;
|
||||||
|
|
||||||
use std::collections::{btree_map, BTreeMap};
|
use std::collections::{btree_map, BTreeMap};
|
||||||
|
|
@ -85,6 +85,9 @@ pub fn escape(raw: &[u8]) -> Cow<[u8]> {
|
||||||
pub struct Element {
|
pub struct Element {
|
||||||
name: String,
|
name: String,
|
||||||
namespace: String,
|
namespace: String,
|
||||||
|
/// This is only used when deserializing. If you have to use a custom prefix use
|
||||||
|
/// `ElementBuilder::prefix`.
|
||||||
|
prefix: Option<Prefix>,
|
||||||
prefixes: Prefixes,
|
prefixes: Prefixes,
|
||||||
attributes: BTreeMap<String, String>,
|
attributes: BTreeMap<String, String>,
|
||||||
children: Vec<Node>,
|
children: Vec<Node>,
|
||||||
|
|
@ -124,24 +127,18 @@ impl Element {
|
||||||
fn new<P: Into<Prefixes>>(
|
fn new<P: Into<Prefixes>>(
|
||||||
name: String,
|
name: String,
|
||||||
namespace: String,
|
namespace: String,
|
||||||
|
prefix: Option<Prefix>,
|
||||||
prefixes: P,
|
prefixes: P,
|
||||||
attributes: BTreeMap<String, String>,
|
attributes: BTreeMap<String, String>,
|
||||||
children: Vec<Node>,
|
children: Vec<Node>,
|
||||||
) -> Element {
|
) -> Element {
|
||||||
let (prefix, name) = split_element_name(name).unwrap();
|
// TODO: Check that "name" doesn't contain ":". We've stopped accepting the "prefix:local"
|
||||||
let namespace: String = namespace.into();
|
// format.
|
||||||
let prefixes: Prefixes = match prefix {
|
|
||||||
None => prefixes.into(),
|
|
||||||
Some(_) => {
|
|
||||||
let mut p = prefixes.into();
|
|
||||||
p.insert(namespace.clone(), prefix);
|
|
||||||
p
|
|
||||||
},
|
|
||||||
};
|
|
||||||
Element {
|
Element {
|
||||||
name,
|
name,
|
||||||
namespace,
|
namespace,
|
||||||
prefixes: Rc::new(prefixes.into()),
|
prefix,
|
||||||
|
prefixes: prefixes.into(),
|
||||||
attributes,
|
attributes,
|
||||||
children,
|
children,
|
||||||
}
|
}
|
||||||
|
|
@ -166,19 +163,15 @@ impl Element {
|
||||||
/// assert_eq!(elem.text(), "inner");
|
/// assert_eq!(elem.text(), "inner");
|
||||||
/// ```
|
/// ```
|
||||||
pub fn builder<S: AsRef<str>, NS: Into<String>>(name: S, namespace: NS) -> ElementBuilder {
|
pub fn builder<S: AsRef<str>, NS: Into<String>>(name: S, namespace: NS) -> ElementBuilder {
|
||||||
let (prefix, name) = split_element_name(name).unwrap();
|
|
||||||
let namespace: String = namespace.into();
|
|
||||||
let prefixes: BTreeMap<String, Option<String>> = match prefix {
|
|
||||||
None => Default::default(),
|
|
||||||
Some(_) => {
|
|
||||||
let mut prefixes: BTreeMap<String, Option<String>> = BTreeMap::new();
|
|
||||||
prefixes.insert(namespace.clone(), prefix);
|
|
||||||
prefixes
|
|
||||||
},
|
|
||||||
};
|
|
||||||
ElementBuilder {
|
ElementBuilder {
|
||||||
root: Element::new(name, namespace, None, BTreeMap::new(), Vec::new()),
|
root: Element::new(
|
||||||
prefixes,
|
name.as_ref().to_string(),
|
||||||
|
namespace.into(),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
BTreeMap::new(),
|
||||||
|
Vec::new()
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -200,6 +193,7 @@ impl Element {
|
||||||
Element::new(
|
Element::new(
|
||||||
name.into(),
|
name.into(),
|
||||||
namespace.into(),
|
namespace.into(),
|
||||||
|
None,
|
||||||
BTreeMap::new(),
|
BTreeMap::new(),
|
||||||
BTreeMap::new(),
|
BTreeMap::new(),
|
||||||
Vec::new(),
|
Vec::new(),
|
||||||
|
|
@ -359,34 +353,47 @@ impl Element {
|
||||||
if stack.len() <= 1 {
|
if stack.len() <= 1 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
prefix_stack.pop().unwrap();
|
let prefixes = prefix_stack.pop().unwrap();
|
||||||
let elem = stack.pop().unwrap();
|
let elem = stack.pop().unwrap();
|
||||||
if let Some(to) = stack.last_mut() {
|
if let Some(to) = stack.last_mut() {
|
||||||
// TODO: check whether this is correct, we are comparing &[u8]s, not &strs
|
// TODO: check whether this is correct, we are comparing &[u8]s, not &strs
|
||||||
let elem_name = e.name();
|
let elem_name = e.name();
|
||||||
let mut split_iter = elem_name.splitn(2, |u| *u == 0x3A);
|
let mut split_iter = elem_name.splitn(2, |u| *u == 0x3A);
|
||||||
let possible_prefix = split_iter.next().unwrap(); // Can't be empty.
|
let possible_prefix = split_iter.next().unwrap(); // Can't be empty.
|
||||||
match split_iter.next() {
|
let opening_prefix = {
|
||||||
Some(name) => {
|
let mut tmp: Option<Option<String>> = None;
|
||||||
match elem.prefixes.get(&elem.namespace) {
|
for (prefix, ns) in prefixes {
|
||||||
Some(Some(prefix)) => {
|
if ns == elem.namespace {
|
||||||
if possible_prefix != prefix.as_bytes() {
|
tmp = Some(prefix.clone());
|
||||||
return Err(Error::InvalidElementClosed);
|
break;
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(Error::InvalidElementClosed);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
match tmp {
|
||||||
|
Some(prefix) => prefix,
|
||||||
|
None => return Err(Error::InvalidPrefix),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match split_iter.next() {
|
||||||
|
// There is a prefix on the closing tag
|
||||||
|
Some(name) => {
|
||||||
|
// Does the closing prefix match the opening prefix?
|
||||||
|
match opening_prefix {
|
||||||
|
Some(prefix) if possible_prefix == prefix.as_bytes() => (),
|
||||||
|
_ => return Err(Error::InvalidElementClosed),
|
||||||
|
}
|
||||||
|
// Does the closing tag name match the opening tag name?
|
||||||
if name != elem.name().as_bytes() {
|
if name != elem.name().as_bytes() {
|
||||||
return Err(Error::InvalidElementClosed);
|
return Err(Error::InvalidElementClosed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// There was no prefix on the closing tag
|
||||||
None => {
|
None => {
|
||||||
match elem.prefixes.get(&elem.namespace) {
|
// Is there a prefix on the opening tag?
|
||||||
Some(Some(_)) => return Err(Error::InvalidElementClosed),
|
match opening_prefix {
|
||||||
|
Some(_) => return Err(Error::InvalidElementClosed),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
// Does the opening tag name match the closing one?
|
||||||
if possible_prefix != elem.name().as_bytes() {
|
if possible_prefix != elem.name().as_bytes() {
|
||||||
return Err(Error::InvalidElementClosed);
|
return Err(Error::InvalidElementClosed);
|
||||||
}
|
}
|
||||||
|
|
@ -441,24 +448,20 @@ impl Element {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Like `write_to()` but without the `<?xml?>` prelude
|
/// Like `write_to()` but without the `<?xml?>` prelude
|
||||||
pub fn write_to_inner<W: Write>(&self, writer: &mut EventWriter<W>, all_prefixes: &mut BTreeMap<Option<String>, String>) -> Result<()> {
|
pub fn write_to_inner<W: Write>(&self, writer: &mut EventWriter<W>, all_prefixes: &mut BTreeMap<Prefix, Namespace>) -> Result<()> {
|
||||||
let local_prefixes = self.prefixes.declared_prefixes();
|
let local_prefixes: &BTreeMap<Option<String>, String> = self.prefixes.declared_prefixes();
|
||||||
|
|
||||||
// Element namespace
|
// Element namespace
|
||||||
// If the element prefix hasn't been set yet via a custom prefix, add it.
|
// If the element prefix hasn't been set yet via a custom prefix, add it.
|
||||||
let mut existing_self_prefix: Option<Option<String>> = None;
|
let mut existing_self_prefix: Option<Option<String>> = None;
|
||||||
if let Some(prefix) = local_prefixes.get(&self.namespace) {
|
for (prefix, ns) in local_prefixes.iter().chain(all_prefixes.iter()) {
|
||||||
existing_self_prefix = Some(prefix.clone());
|
if ns == &self.namespace {
|
||||||
} else {
|
existing_self_prefix = Some(prefix.clone());
|
||||||
for (prefix, ns) in all_prefixes.iter() {
|
|
||||||
if ns == &self.namespace {
|
|
||||||
existing_self_prefix = Some(prefix.clone());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut all_keys = all_prefixes.keys().cloned();
|
let mut all_keys = all_prefixes.keys().cloned();
|
||||||
let mut local_keys = local_prefixes.values().cloned();
|
let mut local_keys = local_prefixes.keys().cloned();
|
||||||
let self_prefix: (Option<String>, bool) = match existing_self_prefix {
|
let self_prefix: (Option<String>, bool) = match existing_self_prefix {
|
||||||
// No prefix exists already for our namespace
|
// No prefix exists already for our namespace
|
||||||
None => {
|
None => {
|
||||||
|
|
@ -503,7 +506,7 @@ impl Element {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Custom prefixes/namespace sets
|
// Custom prefixes/namespace sets
|
||||||
for (ns, prefix) in local_prefixes {
|
for (prefix, ns) in local_prefixes {
|
||||||
match all_prefixes.get(prefix) {
|
match all_prefixes.get(prefix) {
|
||||||
p @ Some(_) if p == prefix.as_ref() => (),
|
p @ Some(_) if p == prefix.as_ref() => (),
|
||||||
_ => {
|
_ => {
|
||||||
|
|
@ -823,7 +826,7 @@ fn split_element_name<S: AsRef<str>>(s: S) -> Result<(Option<String>, String)> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_element<R: BufRead>(reader: &EventReader<R>, event: &BytesStart, prefixes: &mut BTreeMap<String, Option<String>>) -> Result<Element> {
|
fn build_element<R: BufRead>(reader: &EventReader<R>, event: &BytesStart, prefixes: &mut BTreeMap<Prefix, Namespace>) -> Result<Element> {
|
||||||
let (prefix, name) = split_element_name(str::from_utf8(event.name())?)?;
|
let (prefix, name) = split_element_name(str::from_utf8(event.name())?)?;
|
||||||
let mut local_prefixes = BTreeMap::new();
|
let mut local_prefixes = BTreeMap::new();
|
||||||
|
|
||||||
|
|
@ -837,33 +840,39 @@ fn build_element<R: BufRead>(reader: &EventReader<R>, event: &BytesStart, prefix
|
||||||
})
|
})
|
||||||
.filter(|o| match *o {
|
.filter(|o| match *o {
|
||||||
Ok((ref key, ref value)) if key == "xmlns" => {
|
Ok((ref key, ref value)) if key == "xmlns" => {
|
||||||
local_prefixes.insert(value.clone(), None);
|
local_prefixes.insert(None, value.clone());
|
||||||
prefixes.insert(value.clone(), None);
|
prefixes.insert(None, value.clone());
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
Ok((ref key, ref value)) if key.starts_with("xmlns:") => {
|
Ok((ref key, ref value)) if key.starts_with("xmlns:") => {
|
||||||
local_prefixes.insert(value.to_owned(), Some(key[6..].to_owned()));
|
local_prefixes.insert(Some(key[6..].to_owned()), value.to_owned());
|
||||||
prefixes.insert(value.to_owned(), Some(key[6..].to_owned()));
|
prefixes.insert(Some(key[6..].to_owned()), value.to_owned());
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
_ => true,
|
_ => true,
|
||||||
})
|
})
|
||||||
.collect::<Result<BTreeMap<String, String>>>()?;
|
.collect::<Result<BTreeMap<String, String>>>()?;
|
||||||
|
|
||||||
let namespace: String = {
|
let namespace: &String = {
|
||||||
let mut tmp: Option<String> = None;
|
if let Some(namespace) = local_prefixes.get(&prefix) {
|
||||||
|
namespace
|
||||||
for (k, v) in local_prefixes.iter().chain(prefixes.iter()) {
|
} else if let Some(namespace) = prefixes.get(&prefix) {
|
||||||
if v == &prefix {
|
namespace
|
||||||
tmp = Some(k.clone());
|
} else {
|
||||||
break;
|
return Err(Error::MissingNamespace);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp.ok_or(Error::MissingNamespace)?
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let element = Element::new(name, namespace, local_prefixes, attributes, Vec::new());
|
let element = Element::new(
|
||||||
|
name,
|
||||||
|
namespace.clone(),
|
||||||
|
// Note that this will always be Some(_) as we can't distinguish between the None case and
|
||||||
|
// Some(None). At least we make sure the prefix has a namespace associated.
|
||||||
|
Some(prefix),
|
||||||
|
local_prefixes,
|
||||||
|
attributes,
|
||||||
|
Vec::new()
|
||||||
|
);
|
||||||
Ok(element)
|
Ok(element)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -974,13 +983,13 @@ impl<'a> Iterator for AttrsMut<'a> {
|
||||||
/// A builder for `Element`s.
|
/// A builder for `Element`s.
|
||||||
pub struct ElementBuilder {
|
pub struct ElementBuilder {
|
||||||
root: Element,
|
root: Element,
|
||||||
prefixes: BTreeMap<String, Option<String>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ElementBuilder {
|
impl ElementBuilder {
|
||||||
/// Sets a custom prefix.
|
/// Sets a custom prefix. It is not possible to set the same prefix twice.
|
||||||
pub fn prefix<S: Into<String>>(mut self, prefix: Option<String>, namespace: S) -> ElementBuilder {
|
pub fn prefix<S: Into<Namespace>>(mut self, prefix: Prefix, namespace: S) -> ElementBuilder {
|
||||||
self.prefixes.insert(namespace.into(), prefix);
|
// TODO: Make this actually send back an error when a duplicate prefix is added.
|
||||||
|
self.root.prefixes.insert(prefix, namespace.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1013,10 +1022,7 @@ impl ElementBuilder {
|
||||||
|
|
||||||
/// Builds the `Element`.
|
/// Builds the `Element`.
|
||||||
pub fn build(self) -> Element {
|
pub fn build(self) -> Element {
|
||||||
let mut element = self.root;
|
self.root
|
||||||
// Set namespaces
|
|
||||||
element.prefixes = Rc::new(Prefixes::from(self.prefixes));
|
|
||||||
element
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1031,6 +1037,7 @@ mod tests {
|
||||||
let elem = Element::new(
|
let elem = Element::new(
|
||||||
"name".to_owned(),
|
"name".to_owned(),
|
||||||
"namespace".to_owned(),
|
"namespace".to_owned(),
|
||||||
|
None,
|
||||||
(None, "namespace".to_owned()),
|
(None, "namespace".to_owned()),
|
||||||
BTreeMap::from_iter(vec![("name".to_string(), "value".to_string())].into_iter()),
|
BTreeMap::from_iter(vec![("name".to_string(), "value".to_string())].into_iter()),
|
||||||
Vec::new(),
|
Vec::new(),
|
||||||
|
|
@ -1071,7 +1078,7 @@ mod tests {
|
||||||
let mut reader = EventReader::from_str(xml);
|
let mut reader = EventReader::from_str(xml);
|
||||||
let elem = Element::from_reader(&mut reader);
|
let elem = Element::from_reader(&mut reader);
|
||||||
|
|
||||||
let nested = Element::builder("prefix:bar", "ns1").attr("baz", "qxx").build();
|
let nested = Element::builder("bar", "ns1").attr("baz", "qxx").build();
|
||||||
let elem2 = Element::builder("foo", "ns1").append(nested).build();
|
let elem2 = Element::builder("foo", "ns1").append(nested).build();
|
||||||
|
|
||||||
assert_eq!(elem.unwrap(), elem2);
|
assert_eq!(elem.unwrap(), elem2);
|
||||||
|
|
@ -1086,7 +1093,7 @@ mod tests {
|
||||||
assert_eq!(elem.name(), String::from("bar"));
|
assert_eq!(elem.name(), String::from("bar"));
|
||||||
assert_eq!(elem.ns(), String::from("ns1"));
|
assert_eq!(elem.ns(), String::from("ns1"));
|
||||||
// Ensure the prefix is properly added to the store
|
// Ensure the prefix is properly added to the store
|
||||||
assert_eq!(elem.prefixes.get(&String::from("ns1")), Some(Some(String::from("foo"))));
|
assert_eq!(elem.prefixes.get(Some(String::from("foo"))), Some(&String::from("ns1")));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,10 @@ pub enum Error {
|
||||||
/// An error which is returned when an elemet's name contains more than one colon
|
/// An error which is returned when an elemet's name contains more than one colon
|
||||||
InvalidElement,
|
InvalidElement,
|
||||||
|
|
||||||
|
/// An error which is returned when an element being serialized doesn't contain a prefix
|
||||||
|
/// (be it None or Some(_)).
|
||||||
|
InvalidPrefix,
|
||||||
|
|
||||||
/// An error which is returned when an element doesn't contain a namespace
|
/// An error which is returned when an element doesn't contain a namespace
|
||||||
MissingNamespace,
|
MissingNamespace,
|
||||||
|
|
||||||
|
|
@ -51,6 +55,7 @@ impl StdError for Error {
|
||||||
Error::EndOfDocument => None,
|
Error::EndOfDocument => None,
|
||||||
Error::InvalidElementClosed => None,
|
Error::InvalidElementClosed => None,
|
||||||
Error::InvalidElement => None,
|
Error::InvalidElement => None,
|
||||||
|
Error::InvalidPrefix => None,
|
||||||
Error::MissingNamespace => None,
|
Error::MissingNamespace => None,
|
||||||
Error::NoComments => None,
|
Error::NoComments => None,
|
||||||
}
|
}
|
||||||
|
|
@ -70,6 +75,7 @@ impl std::fmt::Display for Error {
|
||||||
write!(fmt, "the XML is invalid, an element was wrongly closed")
|
write!(fmt, "the XML is invalid, an element was wrongly closed")
|
||||||
}
|
}
|
||||||
Error::InvalidElement => write!(fmt, "the XML element is invalid"),
|
Error::InvalidElement => write!(fmt, "the XML element is invalid"),
|
||||||
|
Error::InvalidPrefix => write!(fmt, "the prefix is invalid"),
|
||||||
Error::MissingNamespace => write!(
|
Error::MissingNamespace => write!(
|
||||||
fmt,
|
fmt,
|
||||||
"the XML element is missing a namespace",
|
"the XML element is missing a namespace",
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,12 @@
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
pub type Prefix = Option<String>;
|
||||||
|
pub type Namespace = String;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
pub struct Prefixes {
|
pub struct Prefixes {
|
||||||
prefixes: BTreeMap<String, Option<String>>,
|
prefixes: BTreeMap<Prefix, Namespace>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Prefixes {
|
impl Default for Prefixes {
|
||||||
|
|
@ -26,7 +29,7 @@ impl Default for Prefixes {
|
||||||
impl fmt::Debug for Prefixes {
|
impl fmt::Debug for Prefixes {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "Prefixes(")?;
|
write!(f, "Prefixes(")?;
|
||||||
for (namespace, prefix) in &self.prefixes {
|
for (prefix, namespace) in &self.prefixes {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"xmlns{}={:?} ",
|
"xmlns{}={:?} ",
|
||||||
|
|
@ -42,24 +45,21 @@ impl fmt::Debug for Prefixes {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Prefixes {
|
impl Prefixes {
|
||||||
pub fn declared_prefixes(&self) -> &BTreeMap<String, Option<String>> {
|
pub fn declared_prefixes(&self) -> &BTreeMap<Prefix, Namespace> {
|
||||||
&self.prefixes
|
&self.prefixes
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, namespace: &String) -> Option<Option<String>> {
|
pub fn get(&self, prefix: Prefix) -> Option<&Namespace> {
|
||||||
match self.prefixes.get(namespace) {
|
self.prefixes.get(&prefix)
|
||||||
Some(ns) => Some(ns.clone()),
|
|
||||||
None => None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn insert<S: Into<String>>(&mut self, namespace: S, prefix: Option<String>) {
|
pub(crate) fn insert<S: Into<Namespace>>(&mut self, prefix: Prefix, namespace: S) {
|
||||||
self.prefixes.insert(namespace.into(), prefix);
|
self.prefixes.insert(prefix, namespace.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<BTreeMap<String, Option<String>>> for Prefixes {
|
impl From<BTreeMap<Prefix, Namespace>> for Prefixes {
|
||||||
fn from(prefixes: BTreeMap<String, Option<String>>) -> Self {
|
fn from(prefixes: BTreeMap<Prefix, Namespace>) -> Self {
|
||||||
Prefixes { prefixes }
|
Prefixes { prefixes }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -73,20 +73,20 @@ impl From<Option<String>> for Prefixes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<String> for Prefixes {
|
impl From<Namespace> for Prefixes {
|
||||||
fn from(namespace: String) -> Self {
|
fn from(namespace: Namespace) -> Self {
|
||||||
let mut prefixes = BTreeMap::new();
|
let mut prefixes = BTreeMap::new();
|
||||||
prefixes.insert(namespace, None);
|
prefixes.insert(None, namespace);
|
||||||
|
|
||||||
Prefixes { prefixes }
|
Prefixes { prefixes }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<(Option<String>, String)> for Prefixes {
|
impl From<(Prefix, Namespace)> for Prefixes {
|
||||||
fn from(prefix_namespace: (Option<String>, String)) -> Self {
|
fn from(prefix_namespace: (Prefix, Namespace)) -> Self {
|
||||||
let (prefix, namespace) = prefix_namespace;
|
let (prefix, namespace) = prefix_namespace;
|
||||||
let mut prefixes = BTreeMap::new();
|
let mut prefixes = BTreeMap::new();
|
||||||
prefixes.insert(namespace, prefix);
|
prefixes.insert(prefix, namespace);
|
||||||
|
|
||||||
Prefixes { prefixes }
|
Prefixes { prefixes }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ fn writer_with_prefix() {
|
||||||
.prefix(None, "ns2")
|
.prefix(None, "ns2")
|
||||||
.build();
|
.build();
|
||||||
assert_eq!(String::from(&root),
|
assert_eq!(String::from(&root),
|
||||||
r#"<p1:root xmlns:p1="ns1" xmlns="ns2"/>"#,
|
r#"<p1:root xmlns="ns2" xmlns:p1="ns1"/>"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -198,7 +198,7 @@ fn writer_with_prefix_deduplicate() {
|
||||||
.append(child)
|
.append(child)
|
||||||
.build();
|
.build();
|
||||||
assert_eq!(String::from(&root),
|
assert_eq!(String::from(&root),
|
||||||
r#"<p1:root xmlns:p1="ns1" xmlns="ns2"><p1:child/></p1:root>"#,
|
r#"<p1:root xmlns="ns2" xmlns:p1="ns1"><p1:child/></p1:root>"#,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Ensure descendants don't just reuse ancestors' prefixes that have been shadowed in between
|
// Ensure descendants don't just reuse ancestors' prefixes that have been shadowed in between
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue