xso: add support for ignoring unknown stuff in extracts

This commit is contained in:
Jonas Schäfer 2024-10-03 12:56:04 +02:00 committed by Link Mauve
parent 66233b0150
commit 7d8ffe45a7
4 changed files with 70 additions and 1 deletions

View file

@ -1863,3 +1863,39 @@ fn ignore_unknown_children_negative_unexpected_attribute() {
other => panic!("unexpected result: {:?}", other),
}
}
#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
#[xml(namespace = NS1, name = "parent")]
struct ExtractIgnoreUnknownStuff {
#[xml(extract(namespace = NS1, name = "child", on_unknown_attribute = Discard, on_unknown_child = Discard, fields(
extract(namespace = NS1, name = "grandchild", fields(text))
)))]
contents: String,
}
#[test]
fn extract_ignore_unknown_stuff_positive() {
#[allow(unused_imports)]
use std::{
option::Option::{None, Some},
result::Result::{Err, Ok},
};
match parse_str::<ExtractIgnoreUnknownStuff>(
"<parent xmlns='urn:example:ns1'><child foo='bar'><quak/><grandchild>hello world</grandchild></child></parent>",
) {
Ok(ExtractIgnoreUnknownStuff { contents }) => {
assert_eq!(contents, "hello world");
}
other => panic!("unexpected result: {:?}", other),
}
}
#[test]
fn extract_ignore_unknown_stuff_roundtrip() {
#[allow(unused_imports)]
use std::{
option::Option::{None, Some},
result::Result::{Err, Ok},
};
roundtrip_full::<ExtractIgnoreUnknownStuff>("<parent xmlns='urn:example:ns1'><child><grandchild>hello world</grandchild></child></parent>")
}

View file

@ -319,6 +319,8 @@ fn new_field(
qname: QNameRef { namespace, name },
amount,
fields,
on_unknown_attribute,
on_unknown_child,
} => {
let xml_namespace = namespace.unwrap_or_else(|| container_namespace.clone());
let xml_name = default_name(span, name, field_ident)?;
@ -366,7 +368,8 @@ fn new_field(
&xml_namespace,
));
}
let parts = Compound::from_field_defs(field_defs, None, None)?;
let parts =
Compound::from_field_defs(field_defs, on_unknown_attribute, on_unknown_child)?;
Ok(Box::new(ChildField {
default_,

View file

@ -737,6 +737,12 @@ pub(crate) enum XmlFieldMeta {
/// The `fields` nested meta.
fields: Vec<XmlFieldMeta>,
/// The `on_unknown_attribute` value.
on_unknown_attribute: Option<Ident>,
/// The `on_unknown_child` value.
on_unknown_child: Option<Ident>,
},
/// `#[xml(element)]`
@ -925,6 +931,8 @@ impl XmlFieldMeta {
let mut qname = QNameRef::default();
let mut fields = None;
let mut amount = None;
let mut on_unknown_attribute = None;
let mut on_unknown_child = None;
let mut default_ = Flag::Absent;
meta.parse_nested_meta(|meta| {
if meta.path.is_ident("default") {
@ -952,6 +960,24 @@ impl XmlFieldMeta {
}
amount = Some(meta.value()?.parse()?);
Ok(())
} else if meta.path.is_ident("on_unknown_attribute") {
if on_unknown_attribute.is_some() {
return Err(Error::new_spanned(
meta.path,
"duplicate `on_unknown_attribute` key",
));
}
on_unknown_attribute = Some(meta.value()?.parse()?);
Ok(())
} else if meta.path.is_ident("on_unknown_child") {
if on_unknown_child.is_some() {
return Err(Error::new_spanned(
meta.path,
"duplicate `on_unknown_child` key",
));
}
on_unknown_child = Some(meta.value()?.parse()?);
Ok(())
} else {
match qname.parse_incremental_from_meta(meta)? {
None => Ok(()),
@ -966,6 +992,8 @@ impl XmlFieldMeta {
qname,
fields,
amount,
on_unknown_attribute,
on_unknown_child,
})
}

View file

@ -474,6 +474,8 @@ The following keys can be used inside the `#[xml(extract(..))]` meta:
| `default` | flag | If present, an absent child will substitute the default value instead of raising an error. |
| `n` | `1` or `..` | If `1`, a single element is parsed. If `..`, a collection is parsed. Defaults to `1`. |
| `fields` | *nested* | A list of [field meta](#field-meta) which describe the contents of the child element. |
| `on_unknown_attribute` | *identifier* | Name of an [`UnknownAttributePolicy`] member, controlling how unknown attributes are handled. |
| `on_unknown_child` | *identifier* | Name of an [`UnknownChildPolicy`] member, controlling how unknown children are handled. |
If the `name` key contains a namespace prefix, it must be one of the prefixes
defined as built-in in the XML specifications. That prefix will then be