Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion xsd-parser-types/src/xml/element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use quick_xml::{
name::QName,
};

use crate::misc::format_utf8_slice;
use crate::misc::{format_utf8_slice, Namespace, NamespacePrefix};

#[cfg(feature = "quick-xml")]
use crate::quick_xml::{
Expand Down Expand Up @@ -93,6 +93,29 @@ impl<'a> Element<'a> {

self
}

/// Add a namespace to the namespace context of this element.
///
/// This will not add a namespace attribute to the element itself. It only
/// tells the serializer that this namespace must be valid in the context of
/// this element. If the namespace is not already declared in a parent element,
/// a suitable `xmlns` attribute will be added automatically.
///
/// If you want to add a namespace declaration attribute to the element in
/// any case, use the [`Element::attribute`] method instead.
#[must_use]
pub fn namespace<P, N>(mut self, prefix: P, namespace: N) -> Self
where
P: Into<Cow<'a, [u8]>>,
N: Into<Cow<'a, [u8]>>,
{
let mut namespaces = self.namespaces.into_owned();
namespaces.insert(prefix.into().into(), namespace.into().into());

self.namespaces = namespaces.into_shared();

self
}
}

impl Debug for Element<'_> {
Expand Down Expand Up @@ -172,6 +195,7 @@ impl<'ser, 'el> ElementSerializer<'ser, 'el> {
Self::Start { name, element }
}

#[allow(clippy::too_many_lines)]
fn next_item(&mut self, helper: &mut SerializeHelper) -> Result<Option<Event<'ser>>, Error> {
loop {
match replace(self, Self::Done) {
Expand All @@ -183,9 +207,19 @@ impl<'ser, 'el> ElementSerializer<'ser, 'el> {
});

let mut start = BytesStart::new(element_name);

helper.begin_ns_scope();
for (prefix, ns) in &**element.namespaces {
let prefix = NamespacePrefix::new(prefix.0.clone().into_owned());
let ns = Namespace::new(ns.0.clone().into_owned());
helper.write_xmlns(&mut start, Some(&prefix), &ns);
}

start.extend_attributes(attributes);

let event = if element.values.is_empty() {
helper.end_ns_scope();

Event::Empty(start)
} else {
let values = element.values.iter();
Expand All @@ -206,6 +240,8 @@ impl<'ser, 'el> ElementSerializer<'ser, 'el> {
let end = BytesEnd::new(element_name);
let event = Event::End(end);

helper.end_ns_scope();

return Ok(Some(event));
}
Self::NextValue {
Expand Down
32 changes: 31 additions & 1 deletion xsd-parser-types/src/xml/namespaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,18 @@ use crate::misc::format_utf8_slice;
#[derive(Default, Debug, Clone, Eq, PartialEq)]
pub struct Namespaces<'a>(pub HashMap<Key<'a>, Value<'a>>);

impl Namespaces<'_> {
impl<'a> Namespaces<'a> {
/// Create a new [`Namespaces`] instance.
#[must_use]
pub fn new() -> Self {
Self::default()
}

/// Convert this list into a shared version ([`NamespacesShared`]).
#[must_use]
pub fn into_shared(self) -> NamespacesShared<'a> {
NamespacesShared::new(self)
}
}

impl<'a> Deref for Namespaces<'a> {
Expand Down Expand Up @@ -81,6 +87,12 @@ impl<'a> From<&'a [u8]> for Key<'a> {
}
}

impl<'a> From<Cow<'a, [u8]>> for Key<'a> {
fn from(value: Cow<'a, [u8]>) -> Self {
Self(value)
}
}

impl Deref for Key<'_> {
type Target = [u8];

Expand Down Expand Up @@ -146,6 +158,24 @@ impl Borrow<[u8]> for Value<'_> {
}
}

impl From<Vec<u8>> for Value<'static> {
fn from(value: Vec<u8>) -> Self {
Self(Cow::Owned(value))
}
}

impl<'a> From<&'a [u8]> for Value<'a> {
fn from(value: &'a [u8]) -> Self {
Self(Cow::Borrowed(value))
}
}

impl<'a> From<Cow<'a, [u8]>> for Value<'a> {
fn from(value: Cow<'a, [u8]>) -> Self {
Self(value)
}
}

/// Represents a shared list of namespaces.
///
/// This is useful to not store the same map again and again. Is uses an [`Arc`]
Expand Down
2 changes: 1 addition & 1 deletion xsd-parser/tests/feature/any/example/default.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<tns:Name>def</tns:Name>
</tns:Choice>
<tns:Choice>
<AnyElement2 />
<AnyElement2 xmlns:anyNs="http://example.com/anyNs" />
</tns:Choice>
<tns:Choice>
<AnotherElement2 />
Expand Down
7 changes: 6 additions & 1 deletion xsd-parser/tests/feature/any/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,12 @@ macro_rules! test_obj {
},
ChoiceType {
any_attribute: AnyAttributes::default(),
content: ChoiceTypeContent::Any(Element::default().name(b"AnyElement2")),
content: ChoiceTypeContent::Any(
Element::default()
.name(b"AnyElement2")
.namespace(b"tns", b"http://example.com")
.namespace(b"anyNs", b"http://example.com/anyNs"),
),
},
ChoiceType {
any_attribute: AnyAttributes::default(),
Expand Down