diff --git a/parsers/src/data_forms_validate.rs b/parsers/src/data_forms_validate.rs
index 2fc18ce9..8f50fbb0 100644
--- a/parsers/src/data_forms_validate.rs
+++ b/parsers/src/data_forms_validate.rs
@@ -4,19 +4,18 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+use std::borrow::Cow;
use std::fmt::{Display, Formatter};
use std::str::FromStr;
-use minidom::{Element, IntoAttributeValue};
-use xso::{
- error::{Error, FromElementError},
- AsXml, FromXml,
-};
+use minidom::IntoAttributeValue;
+use xso::{error::Error, AsXml, AsXmlText, FromXml, FromXmlText};
-use crate::ns::{self, XDATA_VALIDATE};
+use crate::ns;
/// Validation Method
-#[derive(Debug, Clone, PartialEq)]
+#[derive(FromXml, AsXml, Debug, Clone, PartialEq)]
+#[xml(namespace = ns::XDATA_VALIDATE)]
pub enum Method {
/// … to indicate that the value(s) should simply match the field type and datatype constraints,
/// the `` element shall contain a `` child element. Using `` validation,
@@ -24,6 +23,7 @@ pub enum Method {
/// the field type.
///
///
+ #[xml(name = "basic")]
Basic,
/// For "list-single" or "list-multi", to indicate that the user may enter a custom value
@@ -34,6 +34,7 @@ pub enum Method {
/// "list-multi", with no options and all values automatically selected.
///
///
+ #[xml(name = "open")]
Open,
/// To indicate that the value should fall within a certain range, the `` element shall
@@ -51,10 +52,14 @@ pub enum Method {
/// constraints.
///
///
+ #[xml(name = "range")]
Range {
/// The 'min' attribute specifies the minimum allowable value.
+ #[xml(attribute(default))]
min: Option,
+
/// The 'max' attribute specifies the maximum allowable value.
+ #[xml(attribute(default))]
max: Option,
},
@@ -65,7 +70,8 @@ pub enum Method {
/// character data only.
///
///
- Regex(String),
+ #[xml(name = "regex")]
+ Regex(#[xml(text)] String),
}
/// Selection Ranges in "list-multi"
@@ -75,6 +81,7 @@ pub struct ListRange {
/// The 'min' attribute specifies the minimum allowable number of selected/entered values.
#[xml(attribute(default))]
pub min: Option,
+
/// The 'max' attribute specifies the maximum allowable number of selected/entered values.
#[xml(attribute(default))]
pub max: Option,
@@ -181,7 +188,8 @@ pub enum Datatype {
}
/// Validation rules for a DataForms Field.
-#[derive(Debug, Clone, PartialEq)]
+#[derive(FromXml, AsXml, Debug, Clone, PartialEq)]
+#[xml(namespace = ns::XDATA_VALIDATE, name = "validate")]
pub struct Validate {
/// The 'datatype' attribute specifies the datatype. This attribute is OPTIONAL, and defaults
/// to "xs:string". It MUST meet one of the following conditions:
@@ -191,6 +199,7 @@ pub struct Validate {
/// - Start with "x:", and specify a user-defined datatype.
///
/// Note that while "x:" allows for ad-hoc definitions, its use is NOT RECOMMENDED.
+ #[xml(attribute(default))]
pub datatype: Option,
/// The validation method. If no validation method is specified, form processors MUST
@@ -202,6 +211,7 @@ pub struct Validate {
/// defined by that method.
///
///
+ #[xml(child(default))]
pub method: Option,
/// For "list-multi", validation can indicate (via the `` element) that a minimum
@@ -215,108 +225,10 @@ pub struct Validate {
/// selection constraints.
///
///
+ #[xml(child(default))]
pub list_range: Option,
}
-impl TryFrom for Validate {
- type Error = FromElementError;
-
- fn try_from(elem: Element) -> Result {
- check_self!(elem, "validate", XDATA_VALIDATE);
- check_no_unknown_attributes!(elem, "item", ["datatype"]);
-
- let mut validate = Validate {
- datatype: elem
- .attr("datatype")
- .map(Datatype::from_str)
- .transpose()
- .map_err(|err| FromElementError::Invalid(Error::TextParseError(err.into())))?,
- method: None,
- list_range: None,
- };
-
- for child in elem.children() {
- match child {
- _ if child.is("list-range", XDATA_VALIDATE) => {
- let list_range = ListRange::try_from(child.clone())?;
- if validate.list_range.is_some() {
- return Err(Error::Other(
- "Encountered unsupported number (n > 1) of list-range in validate element.",
- ).into());
- }
- validate.list_range = Some(list_range);
- }
- _ => {
- let method = Method::try_from(child.clone())?;
- if validate.method.is_some() {
- return Err(Error::Other(
- "Encountered unsupported number (n > 1) of validation methods in validate element.",
- ).into());
- }
- validate.method = Some(method);
- }
- }
- }
-
- Ok(validate)
- }
-}
-
-impl From for Element {
- fn from(value: Validate) -> Self {
- Element::builder("validate", XDATA_VALIDATE)
- .attr("datatype", value.datatype)
- .append_all(value.method)
- .append_all(value.list_range)
- .build()
- }
-}
-
-impl TryFrom for Method {
- type Error = Error;
-
- fn try_from(elem: Element) -> Result {
- let method = match elem {
- _ if elem.is("basic", XDATA_VALIDATE) => {
- check_no_attributes!(elem, "basic");
- Method::Basic
- }
- _ if elem.is("open", XDATA_VALIDATE) => {
- check_no_attributes!(elem, "open");
- Method::Open
- }
- _ if elem.is("range", XDATA_VALIDATE) => {
- check_no_unknown_attributes!(elem, "range", ["min", "max"]);
- Method::Range {
- min: elem.attr("min").map(ToString::to_string),
- max: elem.attr("max").map(ToString::to_string),
- }
- }
- _ if elem.is("regex", XDATA_VALIDATE) => {
- check_no_attributes!(elem, "regex");
- check_no_children!(elem, "regex");
- Method::Regex(elem.text())
- }
- _ => return Err(Error::Other("Encountered invalid validation method.")),
- };
- Ok(method)
- }
-}
-
-impl From for Element {
- fn from(value: Method) -> Self {
- match value {
- Method::Basic => Element::builder("basic", XDATA_VALIDATE),
- Method::Open => Element::builder("open", XDATA_VALIDATE),
- Method::Range { min, max } => Element::builder("range", XDATA_VALIDATE)
- .attr("min", min)
- .attr("max", max),
- Method::Regex(regex) => Element::builder("regex", XDATA_VALIDATE).append(regex),
- }
- .build()
- }
-}
-
impl FromStr for Datatype {
type Err = DatatypeError;
@@ -404,9 +316,22 @@ impl IntoAttributeValue for Datatype {
}
}
+impl FromXmlText for Datatype {
+ fn from_xml_text(s: String) -> Result {
+ s.parse().map_err(Error::text_parse_error)
+ }
+}
+
+impl AsXmlText for Datatype {
+ fn as_xml_text(&self) -> Result, Error> {
+ Ok(Cow::Owned(self.to_string()))
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
+ use minidom::Element;
#[test]
fn test_parse_datatype() -> Result<(), DatatypeError> {