diff --git a/parsers/src/util/macro_tests.rs b/parsers/src/util/macro_tests.rs index 986e9e6e..ca480d65 100644 --- a/parsers/src/util/macro_tests.rs +++ b/parsers/src/util/macro_tests.rs @@ -398,6 +398,17 @@ fn text_string_roundtrip() { roundtrip_full::("hello world!"); } +#[test] +fn text_string_positive_preserves_whitespace() { + #[allow(unused_imports)] + use std::{ + option::Option::{None, Some}, + result::Result::{Err, Ok}, + }; + let el = parse_str::(" \t\n").unwrap(); + assert_eq!(el.text, " \t\n"); +} + #[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] #[xml(namespace = NS1, name = "text")] struct TextNonString { @@ -414,3 +425,42 @@ fn text_non_string_roundtrip() { }; roundtrip_full::("123456"); } + +#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[xml(namespace = NS1, name = "elem")] +struct IgnoresWhitespaceWithoutTextConsumer; + +#[test] +fn ignores_whitespace_without_text_consumer_positive() { + #[allow(unused_imports)] + use std::{ + option::Option::{None, Some}, + result::Result::{Err, Ok}, + }; + let _ = parse_str::( + " \t\r\n", + ) + .unwrap(); +} + +#[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] +#[xml(namespace = NS1, name = "elem")] +struct FailsTextWithoutTextConsumer; + +#[test] +fn fails_text_without_text_consumer_positive() { + #[allow(unused_imports)] + use std::{ + option::Option::{None, Some}, + result::Result::{Err, Ok}, + }; + match parse_str::(" quak ") + { + Err(::xso::error::FromElementError::Invalid(::xso::error::Error::Other(e))) + if e.contains("Unexpected text") => + { + () + } + other => panic!("unexpected result: {:?}", other), + } +} diff --git a/xso-proc/src/compound.rs b/xso-proc/src/compound.rs index b823a4d4..dc92900c 100644 --- a/xso-proc/src/compound.rs +++ b/xso-proc/src/compound.rs @@ -132,7 +132,15 @@ impl Compound { let text_handler = match text_handler { Some(v) => v, None => quote! { - ::core::result::Result::Err(::xso::error::Error::Other("Unexpected text content".into())) + // note: u8::is_ascii_whitespace includes U+000C, which is not + // part of XML's white space definition.' + if #text.as_bytes().iter().any(|b| *b != b' ' && *b != b'\t' && *b != b'\r' && *b != b'\n') { + ::core::result::Result::Err(::xso::error::Error::Other("Unexpected text content".into())) + } else { + ::core::result::Result::Ok(::std::ops::ControlFlow::Break( + Self::#default_state_ident { #builder_data_ident } + )) + } }, };