Detailed changes
@@ -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>")
+}
@@ -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_,
@@ -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,
})
}
@@ -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