xso: add support for ignoring unknown stuff in extracts
This commit is contained in:
parent
66233b0150
commit
7d8ffe45a7
4 changed files with 70 additions and 1 deletions
|
|
@ -1863,3 +1863,39 @@ fn ignore_unknown_children_negative_unexpected_attribute() {
|
||||||
other => panic!("unexpected result: {:?}", other),
|
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>")
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -319,6 +319,8 @@ fn new_field(
|
||||||
qname: QNameRef { namespace, name },
|
qname: QNameRef { namespace, name },
|
||||||
amount,
|
amount,
|
||||||
fields,
|
fields,
|
||||||
|
on_unknown_attribute,
|
||||||
|
on_unknown_child,
|
||||||
} => {
|
} => {
|
||||||
let xml_namespace = namespace.unwrap_or_else(|| container_namespace.clone());
|
let xml_namespace = namespace.unwrap_or_else(|| container_namespace.clone());
|
||||||
let xml_name = default_name(span, name, field_ident)?;
|
let xml_name = default_name(span, name, field_ident)?;
|
||||||
|
|
@ -366,7 +368,8 @@ fn new_field(
|
||||||
&xml_namespace,
|
&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 {
|
Ok(Box::new(ChildField {
|
||||||
default_,
|
default_,
|
||||||
|
|
|
||||||
|
|
@ -737,6 +737,12 @@ pub(crate) enum XmlFieldMeta {
|
||||||
|
|
||||||
/// The `fields` nested meta.
|
/// The `fields` nested meta.
|
||||||
fields: Vec<XmlFieldMeta>,
|
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)]`
|
/// `#[xml(element)]`
|
||||||
|
|
@ -925,6 +931,8 @@ impl XmlFieldMeta {
|
||||||
let mut qname = QNameRef::default();
|
let mut qname = QNameRef::default();
|
||||||
let mut fields = None;
|
let mut fields = None;
|
||||||
let mut amount = None;
|
let mut amount = None;
|
||||||
|
let mut on_unknown_attribute = None;
|
||||||
|
let mut on_unknown_child = None;
|
||||||
let mut default_ = Flag::Absent;
|
let mut default_ = Flag::Absent;
|
||||||
meta.parse_nested_meta(|meta| {
|
meta.parse_nested_meta(|meta| {
|
||||||
if meta.path.is_ident("default") {
|
if meta.path.is_ident("default") {
|
||||||
|
|
@ -952,6 +960,24 @@ impl XmlFieldMeta {
|
||||||
}
|
}
|
||||||
amount = Some(meta.value()?.parse()?);
|
amount = Some(meta.value()?.parse()?);
|
||||||
Ok(())
|
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 {
|
} else {
|
||||||
match qname.parse_incremental_from_meta(meta)? {
|
match qname.parse_incremental_from_meta(meta)? {
|
||||||
None => Ok(()),
|
None => Ok(()),
|
||||||
|
|
@ -966,6 +992,8 @@ impl XmlFieldMeta {
|
||||||
qname,
|
qname,
|
||||||
fields,
|
fields,
|
||||||
amount,
|
amount,
|
||||||
|
on_unknown_attribute,
|
||||||
|
on_unknown_child,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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. |
|
| `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`. |
|
| `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. |
|
| `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
|
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
|
defined as built-in in the XML specifications. That prefix will then be
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue