Repository: tafia/quick-xml
Pull request #395 (2022-06-05 17:15:29)

Add support for XML Schema `xs:list` type
This PR allows deserializing `Vec` and other sequences from space-separated lists, as [defined](https://www.w3.org/TR/xmlschema11-2/#atomic-vs-list) by XML Schema specification. So now this is possible:
Deserialize
```rust
struct AnyName {
  // Will contain vec!["first", "second", "third"]
  attribute: Vec<String>,
}
```
from
```xml
<any-tag attribute="first second third">
```

codecov-commenter: # [Codecov](https://codecov.io/gh/tafia/quick-xml/pull/395?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) Report
> Merging [#395](https://codecov.io/gh/tafia/quick-xml/pull/395?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) (328b4f6) into [master](https://codecov.io/gh/tafia/quick-xml/commit/0a4298798de2cebc639f4fafa71467d3abe83949?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) (0a42987) will **increase** coverage by `1.71%`.
> The diff coverage is `86.05%`.

```diff
@@            Coverage Diff             @@
##           master     #395      +/-   ##
==========================================
+ Coverage   60.79%   62.50%   +1.71%     
==========================================
  Files          19       20       +1     
  Lines        9843    10664     +821     
==========================================
+ Hits         5984     6666     +682     
- Misses       3859     3998     +139     
```

| Flag | Coverage Δ | |
|---|---|---|
| unittests | `62.50% <86.05%> (+1.71%)` | :arrow_up: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/tafia/quick-xml/pull/395?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) | Coverage Δ | |
|---|---|---|
| [src/errors.rs](https://codecov.io/gh/tafia/quick-xml/pull/395/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c3JjL2Vycm9ycy5ycw==) | `12.50% <0.00%> (-0.41%)` | :arrow_down: |
| [src/events/mod.rs](https://codecov.io/gh/tafia/quick-xml/pull/395/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c3JjL2V2ZW50cy9tb2QucnM=) | `73.87% <ø> (ø)` | |
| [src/de/map.rs](https://codecov.io/gh/tafia/quick-xml/pull/395/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c3JjL2RlL21hcC5ycw==) | `72.85% <51.16%> (-15.90%)` | :arrow_down: |
| [src/de/simple\_type.rs](https://codecov.io/gh/tafia/quick-xml/pull/395/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c3JjL2RlL3NpbXBsZV90eXBlLnJz) | `90.13% <90.13%> (ø)` | |
| [src/de/mod.rs](https://codecov.io/gh/tafia/quick-xml/pull/395/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c3JjL2RlL21vZC5ycw==) | `78.07% <100.00%> (+1.99%)` | :arrow_up: |
| [src/reader.rs](https://codecov.io/gh/tafia/quick-xml/pull/395/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c3JjL3JlYWRlci5ycw==) | `88.10% <100.00%> (-0.12%)` | :arrow_down: |
| [src/de/escape.rs](https://codecov.io/gh/tafia/quick-xml/pull/395/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c3JjL2RlL2VzY2FwZS5ycw==) | `23.35% <0.00%> (-43.07%)` | :arrow_down: |
| ... and [1 more](https://codecov.io/gh/tafia/quick-xml/pull/395/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/tafia/quick-xml/pull/395?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/tafia/quick-xml/pull/395?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None). Last update [0a42987...328b4f6](https://codecov.io/gh/tafia/quick-xml/pull/395?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None).

dralley: I tried to do a code review on this PR but since I don't use quick-xml via serde, am not familiar with Serde's parsing, etc. I realized I don't have time to do all of that research, plus dig through the XML spec, plus review the PR, and keep everything in my head long enough to get it done.

So I have just given this a brief look through.  You've done a great job with the testing
dralley: Feel free to merge this without a full approval

Patch:
diff --git a/Changelog.md b/Changelog.md
index 64bb395..6854dfc 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -22,6 +22,7 @@
   way to access decoding functionality is via this struct
 - [#191]: New event variant `StartText` emitted for bytes before the XML declaration
   or a start comment or a tag. For streams with BOM this event will contain a BOM
+- [#395]: Add support for XML Schema `xs:list`
 
 ### Bug Fixes
 
@@ -104,6 +105,7 @@
 [#387]: https://github.com/tafia/quick-xml/pull/387
 [#391]: https://github.com/tafia/quick-xml/pull/391
 [#393]: https://github.com/tafia/quick-xml/pull/393
+[#395]: https://github.com/tafia/quick-xml/pull/395
 
 ## 0.23.0 -- 2022-05-08
 
diff --git a/src/de/map.rs b/src/de/map.rs
index 2ee697d..efe98ab 100644
--- a/src/de/map.rs
+++ b/src/de/map.rs
@@ -3,6 +3,7 @@
 use crate::{
     de::escape::EscapedDeserializer,
     de::seq::{not_in, TagFilter},
+    de::simple_type::SimpleTypeDeserializer,
     de::{deserialize_bool, DeEvent, Deserializer, XmlRead, INNER_VALUE, UNFLATTEN_PREFIX},
     errors::serialize::DeError,
     events::attributes::IterState,
@@ -35,7 +36,10 @@ enum ValueSource {
     /// represented or by an ordinary text node, or by a CDATA node:
     ///
     /// ```xml
-    /// <...>text content for field value<...>
+    /// <any-tag>
+    ///     <key>text content</key>
+    /// <!--     ^^^^^^^^^^^^ - this will be used to deserialize map value -->
+    /// </any-tag>
     /// ```
     /// ```xml
     /// <any-tag>
@@ -200,8 +204,8 @@ where
     ) -> Result<Self, DeError> {
         Ok(MapAccess {
             de,
+            iter: IterState::new(start.name().as_ref().len(), false),
             start,
-            iter: IterState::new(0, false),
             source: ValueSource::Unknown,
             fields,
             has_value_field: fields.contains(&INNER_VALUE),
@@ -226,8 +230,8 @@ where
     ) -> Result<Option<K::Value>, Self::Error> {
         debug_assert_eq!(self.source, ValueSource::Unknown);
 
-        // FIXME: There error positions counted from end of tag name - need global position
-        let slice = self.start.attributes_raw();
+        // FIXME: There error positions counted from the start of tag name - need global position
+        let slice = &self.start.buf;
         let decoder = self.de.reader.decoder();
 
         if let Some(a) = self.iter.next(slice).transpose()? {
@@ -305,16 +309,12 @@ where
         seed: K,
     ) -> Result<K::Value, Self::Error> {
         match std::mem::replace(&mut self.source, ValueSource::Unknown) {
-            ValueSource::Attribute(value) => {
-                let slice = self.start.attributes_raw();
-                let decoder = self.de.reader.decoder();
-
-                seed.deserialize(EscapedDeserializer::new(
-                    Cow::Borrowed(&slice[value]),
-                    decoder,
-                    true,
-                ))
-            }
+            ValueSource::Attribute(value) => seed.deserialize(SimpleTypeDeserializer::from_part(
+                &self.start.buf,
+                value,
+                true,
+                self.de.reader.decoder(),
+            )),
             // This arm processes the following XML shape:
             // <any-tag>
             //   text value
@@ -323,10 +323,21 @@ where
             // is implicit and equals to the `INNER_VALUE` constant, and the value
             // is a `Text` or a `CData` event (the value deserializer will see one
             // of that events)
-            ValueSource::Text => seed.deserialize(MapValueDeserializer {
-                map: self,
-                allow_start: false,
-            }),
+            // This case are checked by "xml_schema_lists::element" tests in tests/serde-de.rs
+            ValueSource::Text => match self.de.next()? {
+                DeEvent::Text(e) => seed.deserialize(SimpleTypeDeserializer::from_cow(
+                    e.into_inner(),
+                    true,
+                    self.de.reader.decoder(),
+                )),
+                DeEvent::CData(e) => seed.deserialize(SimpleTypeDeserializer::from_cow(
+                    e.into_inner(),
+                    false,
+                    self.de.reader.decoder(),
+                )),
+                // SAFETY: We set `Text` only when we seen `Text` or `CData`
+                _ => unreachable!(),
+            },
             // This arm processes the following XML shape:
             // <any-tag>
             //   <any>...</any>
@@ -612,8 +623,140 @@ where
                 DeEvent::Eof => Err(DeError::UnexpectedEof),
 
                 // Start(tag), Text, CData
-                _ => seed.deserialize(&mut *self.map.de).map(Some),
+                _ => seed
+                    .deserialize(SeqValueDeserializer { map: self.map })
+                    .map(Some),
             };
         }
     }
 }
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/// A deserializer for a value of sequence.
+struct SeqValueDeserializer<'de, 'a, 'm, R>
+where
+    R: XmlRead<'de>,
+{
+    /// Access to the map that created this deserializer. Gives access to the
+    /// context, such as list of fields, that current map known about.
+    map: &'m mut MapAccess<'de, 'a, R>,
+}
+
+impl<'de, 'a, 'm, R> SeqValueDeserializer<'de, 'a, 'm, R>
+where
+    R: XmlRead<'de>,
+{
+    /// Returns a text event, used inside [`deserialize_primitives!()`]
+    #[inline]
+    fn next_text(&mut self, unescape: bool) -> Result<BytesCData<'de>, DeError> {
+        self.map.de.next_text_impl(unescape, true)
+    }
+
+    /// Returns a decoder, used inside [`deserialize_primitives!()`]
+    #[inline]
+    fn decoder(&self) -> Decoder {
+        self.map.de.reader.decoder()
+    }
+}
+
+impl<'de, 'a, 'm, R> de::Deserializer<'de> for SeqValueDeserializer<'de, 'a, 'm, R>
+where
+    R: XmlRead<'de>,
+{
+    type Error = DeError;
+
+    deserialize_primitives!(mut);
+
+    forward!(deserialize_option);
+    forward!(deserialize_unit);
+    forward!(deserialize_unit_struct(name: &'static str));
+    forward!(deserialize_newtype_struct(name: &'static str));
+
+    forward!(deserialize_map);
+    forward!(deserialize_struct(
+        name: &'static str,
+        fields: &'static [&'static str]
+    ));
+
+    forward!(deserialize_enum(
+        name: &'static str,
+        variants: &'static [&'static str]
+    ));
+
+    forward!(deserialize_any);
+    forward!(deserialize_ignored_any);
+
+    /// Representation of tuples the same as [sequences](#method.deserialize_seq).
+    fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, DeError>
+    where
+        V: Visitor<'de>,
+    {
+        self.deserialize_seq(visitor)
+    }
+
+    /// Representation of named tuples the same as [unnamed tuples](#method.deserialize_tuple).
+    fn deserialize_tuple_struct<V>(
+        self,
+        _name: &'static str,
+        len: usize,
+        visitor: V,
+    ) -> Result<V::Value, DeError>
+    where
+        V: Visitor<'de>,
+    {
+        self.deserialize_tuple(len, visitor)
+    }
+
+    fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+    where
+        V: Visitor<'de>,
+    {
+        match self.map.de.next()? {
+            DeEvent::Text(e) => SimpleTypeDeserializer::from_cow(
+                // Comment to prevent auto-formatting and keep Text and Cdata similar
+                e.into_inner(),
+                true,
+                self.map.de.reader.decoder(),
+            )
+            .deserialize_seq(visitor),
+            DeEvent::CData(e) => SimpleTypeDeserializer::from_cow(
+                e.into_inner(),
+                false,
+                self.map.de.reader.decoder(),
+            )
+            .deserialize_seq(visitor),
+            // This is a sequence element. We cannot treat it as another flatten
+            // sequence if type will require `deserialize_seq` We instead forward
+            // it to `xs:simpleType` implementation
+            DeEvent::Start(e) => {
+                let value = match self.map.de.next()? {
+                    DeEvent::Text(e) => SimpleTypeDeserializer::from_cow(
+                        e.into_inner(),
+                        true,
+                        self.map.de.reader.decoder(),
+                    )
+                    .deserialize_seq(visitor),
+                    DeEvent::CData(e) => SimpleTypeDeserializer::from_cow(
+                        e.into_inner(),
+                        false,
+                        self.map.de.reader.decoder(),
+                    )
+                    .deserialize_seq(visitor),
+                    e => Err(DeError::Custom(format!("Unsupported event {:?}", e))),
+                };
+                // TODO: May be assert that here we expect only matching closing tag?
+                self.map.de.read_to_end(e.name())?;
+                value
+            }
+            // SAFETY: we use that deserializer only when Start(element), Text,
+            // or CData event Start(tag), Text, CData was peeked already
+            _ => unreachable!(),
+        }
+    }
+
+    #[inline]
+    fn is_human_readable(&self) -> bool {
+        self.map.de.is_human_readable()
+    }
+}
diff --git a/src/de/mod.rs b/src/de/mod.rs
index e252ada..426c82f 100644
--- a/src/de/mod.rs
+++ b/src/de/mod.rs
@@ -215,6 +215,7 @@ macro_rules! deserialize_primitives {
 mod escape;
 mod map;
 mod seq;
+mod simple_type;
 mod var;
 
 pub use crate::errors::serialize::DeError;
@@ -331,6 +332,21 @@ where
 
 // TODO: According to the https://www.w3.org/TR/xmlschema-2/#boolean,
 // valid boolean representations are only "true", "false", "1", and "0"
+fn str2bool<'de, V>(value: &str, visitor: V) -> Result<V::Value, DeError>
+where
+    V: de::Visitor<'de>,
+{
+    match value {
+        "true" | "1" | "True" | "TRUE" | "t" | "Yes" | "YES" | "yes" | "y" => {
+            visitor.visit_bool(true)
+        }
+        "false" | "0" | "False" | "FALSE" | "f" | "No" | "NO" | "no" | "n" => {
+            visitor.visit_bool(false)
+        }
+        _ => Err(DeError::InvalidBoolean(value.into())),
+    }
+}
+
 fn deserialize_bool<'de, V>(value: &[u8], decoder: Decoder, visitor: V) -> Result<V::Value, DeError>
 where
     V: Visitor<'de>,
@@ -339,15 +355,7 @@ where
     {
         let value = decoder.decode(value)?;
         // No need to unescape because valid boolean representations cannot be escaped
-        match value.as_ref() {
-            "true" | "1" | "True" | "TRUE" | "t" | "Yes" | "YES" | "yes" | "y" => {
-                visitor.visit_bool(true)
-            }
-            "false" | "0" | "False" | "FALSE" | "f" | "No" | "NO" | "no" | "n" => {
-                visitor.visit_bool(false)
-            }
-            _ => Err(DeError::InvalidBoolean(value.into())),
-        }
+        str2bool(value.as_ref(), visitor)
     }
 
     #[cfg(not(feature = "encoding"))]
diff --git a/src/de/simple_type.rs b/src/de/simple_type.rs
new file mode 100644
index 0000000..b9a865b
--- /dev/null
+++ b/src/de/simple_type.rs
@@ -0,0 +1,1293 @@
+//! Contains Serde `Deserializer` for XML [simple types] [as defined] in the XML Schema.
+//!
+//! [simple types]: https://www.w3schools.com/xml/el_simpletype.asp
+//! [as defined]: https://www.w3.org/TR/xmlschema11-1/#Simple_Type_Definition
+
+use crate::de::{deserialize_bool, str2bool};
+use crate::errors::serialize::DeError;
+use crate::escape::unescape;
+use crate::reader::Decoder;
+use memchr::memchr;
+use serde::de::{DeserializeSeed, Deserializer, EnumAccess, SeqAccess, VariantAccess, Visitor};
+use serde::{self, serde_if_integer128};
+use std::borrow::Cow;
+use std::ops::{Deref, Range};
+
+macro_rules! deserialize_num {
+    ($method:ident, $visit:ident) => {
+        fn $method<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+        where
+            V: Visitor<'de>,
+        {
+            visitor.$visit(self.content.as_str().parse()?)
+        }
+    };
+    ($method:ident => $visit:ident) => {
+        fn $method<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+        where
+            V: Visitor<'de>,
+        {
+            let string = self.decode()?;
+            visitor.$visit(string.as_str().parse()?)
+        }
+    };
+}
+
+macro_rules! unsupported {
+    (
+        $deserialize:ident
+        $(
+            ($($type:ty),*)
+        )?
+        => $message:literal
+    ) => {
+        #[inline]
+        fn $deserialize<V: Visitor<'de>>(
+            self,
+            $($(_: $type,)*)?
+            _visitor: V
+        ) -> Result<V::Value, Self::Error> {
+            Err(DeError::Unsupported($message))
+        }
+    };
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/// A version of [`Cow`] that can borrow from two different buffers, one of them
+/// is a deserializer input, and conceptually contains only part of owned data.
+///
+/// # Lifetimes
+/// - `'de` -- lifetime of the data that deserializer borrow from the parsed input
+/// - `'a` -- lifetime of the data that owned by a deserializer
+enum Content<'de, 'a> {
+    /// An input borrowed from the parsed data
+    Input(&'de str),
+    /// An input borrowed from the buffer owned by another deserializer
+    Slice(&'a str),
+    /// An input taken from an external deserializer, owned by that deserializer.
+    /// Only part of this data, located after offset represented by `usize`, used
+    /// to deserialize data, the other is a garbage that can't be dropped because
+    /// we do not want to make reallocations if they will not required.
+    Owned(String, usize),
+}
+impl<'de, 'a> Content<'de, 'a> {
+    /// Returns string representation of the content
+    fn as_str(&self) -> &str {
+        match self {
+            Content::Input(s) => s,
+            Content::Slice(s) => s,
+            Content::Owned(s, offset) => s.split_at(*offset).1,
+        }
+    }
+
+    /// Supply to the visitor a borrowed string, a string slice, or an owned
+    /// string depending on the kind of input. Unlike [`Self::deserialize_item`],
+    /// the whole [`Self::Owned`] string will be passed to the visitor.
+    ///
+    /// Calls
+    /// - `visitor.visit_borrowed_str` if data borrowed from the input
+    /// - `visitor.visit_str` if data borrowed from another source
+    /// - `visitor.visit_string` if data owned by this type
+    #[inline]
+    fn deserialize_all<V>(self, visitor: V) -> Result<V::Value, DeError>
+    where
+        V: Visitor<'de>,
+    {
+        match self {
+            Content::Input(s) => visitor.visit_borrowed_str(s),
+            Content::Slice(s) => visitor.visit_str(s),
+            Content::Owned(s, _) => visitor.visit_string(s),
+        }
+    }
+
+    /// Supply to the visitor a borrowed string, a string slice, or an owned
+    /// string depending on the kind of input. Unlike [`Self::deserialize_all`],
+    /// only part of [`Self::Owned`] string will be passed to the visitor.
+    ///
+    /// Calls
+    /// - `visitor.visit_borrowed_str` if data borrowed from the input
+    /// - `visitor.visit_str` if data borrowed from another source
+    /// - `visitor.visit_string` if data owned by this type
+    #[inline]
+    fn deserialize_item<V>(self, visitor: V) -> Result<V::Value, DeError>
+    where
+        V: Visitor<'de>,
+    {
+        match self {
+            Content::Input(s) => visitor.visit_borrowed_str(s),
+            Content::Slice(s) => visitor.visit_str(s),
+            Content::Owned(s, 0) => visitor.visit_string(s),
+            Content::Owned(s, offset) => visitor.visit_str(s.split_at(offset).1),
+        }
+    }
+}
+
+/// A deserializer that handles ordinary [simple type definition][item] with
+/// `{variety} = atomic`, or an ordinary [simple type] definition with
+/// `{variety} = union` whose basic members are all atomic.
+///
+/// This deserializer can deserialize only primitive types:
+/// - numbers
+/// - booleans
+/// - strings
+/// - units
+/// - options
+/// - unit variants of enums
+///
+/// Identifiers represented as strings and deserialized accordingly.
+///
+/// Deserialization of all other types returns [`Unsupported`][DeError::Unsupported] error.
+///
+/// The `Owned` variant of the content acts as a storage for data, allocated by
+/// an external deserializer that pass it via [`ListIter`].
+///
+/// [item]: https://www.w3.org/TR/xmlschema11-1/#std-item_type_definition
+/// [simple type]: https://www.w3.org/TR/xmlschema11-1/#Simple_Type_Definition
+struct AtomicDeserializer<'de, 'a> {
+    /// Content of the attribute value, text content or CDATA content
+    content: Content<'de, 'a>,
+    /// If `true`, `content` in an escaped form and should be unescaped before use
+    escaped: bool,
+}
+
+impl<'de, 'a> Deserializer<'de> for AtomicDeserializer<'de, 'a> {
+    type Error = DeError;
+
+    /// Forwards deserialization to the [`Self::deserialize_str`]
+    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+    where
+        V: Visitor<'de>,
+    {
+        self.deserialize_str(visitor)
+    }
+
+    /// According to the <https://www.w3.org/TR/xmlschema-2/#boolean>,
+    /// valid boolean representations are only `"true"`, `"false"`, `"1"`,
+    /// and `"0"`. But this method also handles following:
+    ///
+    /// |`bool` |XML content
+    /// |-------|-------------------------------------------------------------
+    /// |`true` |`"True"`,  `"TRUE"`,  `"t"`, `"Yes"`, `"YES"`, `"yes"`, `"y"`
+    /// |`false`|`"False"`, `"FALSE"`, `"f"`, `"No"`,  `"NO"`,  `"no"`,  `"n"`
+    fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+    where
+        V: Visitor<'de>,
+    {
+        str2bool(self.content.as_str(), visitor)
+    }
+
+    deserialize_num!(deserialize_i8, visit_i8);
+    deserialize_num!(deserialize_i16, visit_i16);
+    deserialize_num!(deserialize_i32, visit_i32);
+    deserialize_num!(deserialize_i64, visit_i64);
+
+    deserialize_num!(deserialize_u8, visit_u8);
+    deserialize_num!(deserialize_u16, visit_u16);
+    deserialize_num!(deserialize_u32, visit_u32);
+    deserialize_num!(deserialize_u64, visit_u64);
+
+    serde_if_integer128! {
+        deserialize_num!(deserialize_i128, visit_i128);
+        deserialize_num!(deserialize_u128, visit_u128);
+    }
+
+    deserialize_num!(deserialize_f32, visit_f32);
+    deserialize_num!(deserialize_f64, visit_f64);
+
+    /// Forwards deserialization to the [`Self::deserialize_str`]
+    fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+    where
+        V: Visitor<'de>,
+    {
+        self.deserialize_str(visitor)
+    }
+
+    /// Supply to the visitor borrowed string, string slice, or owned string
+    /// depending on the kind of input and presence of the escaped data.
+    ///
+    /// If string requires unescaping, then calls [`Visitor::visit_string`] with
+    /// new allocated buffer with unescaped data.
+    ///
+    /// Otherwise calls
+    /// - [`Visitor::visit_borrowed_str`] if data borrowed from the input
+    /// - [`Visitor::visit_str`] if data borrowed from other deserializer
+    /// - [`Visitor::visit_string`] if data owned by this deserializer
+    fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+    where
+        V: Visitor<'de>,
+    {
+        if self.escaped {
+            match unescape(self.content.as_str().as_bytes())? {
+                Cow::Borrowed(_) => self.content.deserialize_item(visitor),
+                Cow::Owned(buf) => visitor.visit_string(String::from_utf8(buf)?),
+            }
+        } else {
+            self.content.deserialize_item(visitor)
+        }
+    }
+
+    fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+    where
+        V: Visitor<'de>,
+    {
+        self.deserialize_str(visitor)
+    }
+
+    /// If `content` is an empty string then calls [`Visitor::visit_none`],
+    /// otherwise calls [`Visitor::visit_some`] with itself
+    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+    where
+        V: Visitor<'de>,
+    {
+        if self.content.as_str().is_empty() {
+            visitor.visit_none()
+        } else {
+            visitor.visit_some(self)
+        }
+    }
+
+    fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+    where
+        V: Visitor<'de>,
+    {
+        visitor.visit_unit()
+    }
+
+    /// Forwards deserialization to the [`Self::deserialize_unit`]
+    fn deserialize_unit_struct<V>(
+        self,
+        _name: &'static str,
+        visitor: V,
+    ) -> Result<V::Value, Self::Error>
+    where
+        V: Visitor<'de>,
+    {
+        self.deserialize_unit(visitor)
+    }
+
+    fn deserialize_newtype_struct<V>(
+        self,
+        _name: &'static str,
+        visitor: V,
+    ) -> Result<V::Value, Self::Error>
+    where
+        V: Visitor<'de>,
+    {
+        visitor.visit_newtype_struct(self)
+    }
+
+    fn deserialize_enum<V>(
+        self,
+        _name: &'static str,
+        _variants: &'static [&'static str],
+        visitor: V,
+    ) -> Result<V::Value, Self::Error>
+    where
+        V: Visitor<'de>,
+    {
+        visitor.visit_enum(self)
+    }
+
+    /// Forwards deserialization to the [`Self::deserialize_str`]
+    fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+    where
+        V: Visitor<'de>,
+    {
+        self.deserialize_str(visitor)
+    }
+
+    fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+    where
+        V: Visitor<'de>,
+    {
+        visitor.visit_unit()
+    }
+
+    unsupported!(deserialize_bytes        => "byte arrays are not supported as `xs:list` items");
+    unsupported!(deserialize_byte_buf     => "byte arrays are not supported as `xs:list` items");
+    unsupported!(deserialize_seq          => "sequences are not supported as `xs:list` items");
+    unsupported!(deserialize_tuple(usize) => "tuples are not supported as `xs:list` items");
+    unsupported!(deserialize_tuple_struct(&'static str, usize) => "tuples are not supported as `xs:list` items");
+    unsupported!(deserialize_map          => "maps are not supported as `xs:list` items");
+    unsupported!(deserialize_struct(&'static str, &'static [&'static str]) => "structures are not supported as `xs:list` items");
+}
+
+impl<'de, 'a> EnumAccess<'de> for AtomicDeserializer<'de, 'a> {
+    type Error = DeError;
+    type Variant = AtomicUnitOnly;
+
+    fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), DeError>
+    where
+        V: DeserializeSeed<'de>,
+    {
+        let name = seed.deserialize(self)?;
+        Ok((name, AtomicUnitOnly))
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/// Deserializer of variant data, that supports only unit variants.
+/// Attempt to deserialize newtype, tuple or struct variant will return a
+/// [`DeError::Unsupported`] error.
+pub struct AtomicUnitOnly;
+impl<'de> VariantAccess<'de> for AtomicUnitOnly {
+    type Error = DeError;
+
+    #[inline]
+    fn unit_variant(self) -> Result<(), DeError> {
+        Ok(())
+    }
+
+    fn newtype_variant_seed<T>(self, _seed: T) -> Result<T::Value, DeError>
+    where
+        T: DeserializeSeed<'de>,
+    {
+        Err(DeError::Unsupported(
+            "enum newtype variants are not supported as `xs:list` items",
+        ))
+    }
+
+    fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value, DeError>
+    where
+        V: Visitor<'de>,
+    {
+        Err(DeError::Unsupported(
+            "enum tuple variants are not supported as `xs:list` items",
+        ))
+    }
+
+    fn struct_variant<V>(
+        self,
+        _fields: &'static [&'static str],
+        _visitor: V,
+    ) -> Result<V::Value, DeError>
+    where
+        V: Visitor<'de>,
+    {
+        Err(DeError::Unsupported(
+            "enum struct variants are not supported as `xs:list` items",
+        ))
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/// Iterator over string sub-slices delimited by one or several spaces.
+/// Contains decoded value of the `simpleType`.
+/// Iteration ends when list contains `None`.
+struct ListIter<'de, 'a> {
+    /// If `Some`, contains unconsumed data of the list
+    content: Option<Content<'de, 'a>>,
+    /// If `true`, `content` in escaped form and should be unescaped before use
+    escaped: bool,
+}
+impl<'de, 'a> SeqAccess<'de> for ListIter<'de, 'a> {
+    type Error = DeError;
+
+    fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, DeError>
+    where
+        T: DeserializeSeed<'de>,
+    {
+        if let Some(mut content) = self.content.take() {
+            const DELIMITER: u8 = b' ';
+
+            loop {
+                let string = content.as_str();
+                if string.is_empty() {
+                    return Ok(None);
+                }
+                return match memchr(DELIMITER, string.as_bytes()) {
+                    // No delimiters in the `content`, deserialize it as a whole atomic
+                    None => seed.deserialize(AtomicDeserializer {
+                        content,
+                        escaped: self.escaped,
+                    }),
+                    // `content` started with a space, skip them all
+                    Some(0) => {
+                        // Skip all spaces
+                        let start = string.as_bytes().iter().position(|ch| *ch != DELIMITER);
+                        content = match (start, content) {
+                            // We cannot find any non-space character, so string contains only spaces
+                            (None, _) => return Ok(None),
+                            // Borrow result from input or deserializer depending on the initial borrowing
+                            (Some(start), Content::Input(s)) => Content::Input(s.split_at(start).1),
+                            (Some(start), Content::Slice(s)) => Content::Slice(s.split_at(start).1),
+                            // Skip additional bytes if we own data
+                            (Some(start), Content::Owned(s, skip)) => {
+                                Content::Owned(s, skip + start)
+                            }
+                        };
+                        continue;
+                    }
+                    // `content` started from an atomic
+                    Some(end) => match content {
+                        // Borrow for the next iteration from input or deserializer depending on
+                        // the initial borrowing
+                        Content::Input(s) => {
+                            let (item, rest) = s.split_at(end);
+                            self.content = Some(Content::Input(rest));
+
+                            seed.deserialize(AtomicDeserializer {
+                                content: Content::Input(item),
+                                escaped: self.escaped,
+                            })
+                        }
+                        Content::Slice(s) => {
+                            let (item, rest) = s.split_at(end);
+                            self.content = Some(Content::Slice(rest));
+
+                            seed.deserialize(AtomicDeserializer {
+                                content: Content::Slice(item),
+                                escaped: self.escaped,
+                            })
+                        }
+                        // Skip additional bytes if we own data for next iteration, but deserialize from
+                        // the borrowed data from our buffer
+                        Content::Owned(s, skip) => {
+                            let item = s.split_at(skip + end).0;
+                            let result = seed.deserialize(AtomicDeserializer {
+                                content: Content::Slice(item),
+                                escaped: self.escaped,
+                            });
+
+                            self.content = Some(Content::Owned(s, skip + end));
+
+                            result
+                        }
+                    },
+                }
+                .map(Some);
+            }
+        }
+        Ok(None)
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/// A version of [`Cow`] that can borrow from two different buffers, one of them
+/// is a deserializer input.
+///
+/// # Lifetimes
+/// - `'de` -- lifetime of the data that deserializer borrow from the parsed input
+/// - `'a` -- lifetime of the data that owned by a deserializer
+enum CowRef<'de, 'a> {
+    /// An input borrowed from the parsed data
+    Input(&'de [u8]),
+    /// An input borrowed from the buffer owned by another deserializer
+    Slice(&'a [u8]),
+    /// An input taken from an external deserializer, owned by that deserializer
+    Owned(Vec<u8>),
+}
+impl<'de, 'a> Deref for CowRef<'de, 'a> {
+    type Target = [u8];
+
+    fn deref(&self) -> &[u8] {
+        match self {
+            Self::Input(slice) => slice,
+            Self::Slice(slice) => slice,
+            Self::Owned(ref v) => v,
+        }
+    }
+}
+
+/// A deserializer for an xml probably escaped and encoded value of XSD [simple types].
+/// This deserializer will borrow from the input as much as possible.
+///
+/// `deserialize_any()` returns the whole string that deserializer contains.
+///
+/// Escaping the value is actually not always necessary, for instance when
+/// converting to a float, we don't expect any escapable character anyway.
+/// In that cases deserializer skips unescaping step.
+///
+/// Used for deserialize values from:
+/// - attribute values (`<... ...="value" ...>`)
+/// - text content (`<...>text</...>`)
+/// - CDATA content (`<...><![CDATA[cdata]]></...>`)
+///
+/// [simple types]: https://www.w3.org/TR/xmlschema11-1/#Simple_Type_Definition
+pub struct SimpleTypeDeserializer<'de, 'a> {
+    /// - In case of attribute contains escaped attribute value
+    /// - In case of text contains escaped text value
+    /// - In case of CData contains unescaped cdata value
+    content: CowRef<'de, 'a>,
+    /// If `true`, `content` in escaped form and should be unescaped before use
+    escaped: bool,
+    /// Decoder used to deserialize string data, numeric and boolean data.
+    /// Not used for deserializing raw byte buffers
+    decoder: Decoder,
+}
+
+impl<'de, 'a> SimpleTypeDeserializer<'de, 'a> {
+    /// Creates a deserializer from a value, that possible borrowed from input
+    pub fn from_cow(value: Cow<'de, [u8]>, escaped: bool, decoder: Decoder) -> Self {
+        let content = match value {
+            Cow::Borrowed(slice) => CowRef::Input(slice),
+            Cow::Owned(content) => CowRef::Owned(content),
+        };
+        Self::new(content, escaped, decoder)
+    }
+
+    /// Creates a deserializer from a part of value at specified range
+    pub fn from_part(
+        value: &'a Cow<'de, [u8]>,
+        range: Range<usize>,
+        escaped: bool,
+        decoder: Decoder,
+    ) -> Self {
+        let content = match value {
+            Cow::Borrowed(slice) => CowRef::Input(&slice[range]),
+            Cow::Owned(slice) => CowRef::Slice(&slice[range]),
+        };
+        Self::new(content, escaped, decoder)
+    }
+
+    /// Constructor for tests
+    #[inline]
+    fn new(content: CowRef<'de, 'a>, escaped: bool, decoder: Decoder) -> Self {
+        Self {
+            content,
+            escaped,
+            decoder,
+        }
+    }
+
+    /// Decodes raw bytes using the encoding specified.
+    /// The method will borrow if has the UTF-8 compatible representation.
+    #[inline]
+    fn decode<'b>(&'b self) -> Result<Content<'de, 'b>, DeError> {
+        Ok(match self.content {
+            CowRef::Input(content) => match self.decoder.decode(content)? {
+                Cow::Borrowed(content) => Content::Input(content),
+                Cow::Owned(content) => Content::Owned(content, 0),
+            },
+            CowRef::Slice(content) => match self.decoder.decode(content)? {
+                Cow::Borrowed(content) => Content::Slice(content),
+                Cow::Owned(content) => Content::Owned(content, 0),
+            },
+            CowRef::Owned(ref content) => match self.decoder.decode(content)? {
+                Cow::Borrowed(content) => Content::Slice(content),
+                Cow::Owned(content) => Content::Owned(content, 0),
+            },
+        })
+    }
+}
+
+impl<'de, 'a> Deserializer<'de> for SimpleTypeDeserializer<'de, 'a> {
+    type Error = DeError;
+
+    /// Forwards deserialization to the [`Self::deserialize_str`]
+    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+    where
+        V: Visitor<'de>,
+    {
+        self.deserialize_str(visitor)
+    }
+
+    fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+    where
+        V: Visitor<'de>,
+    {
+        deserialize_bool(&self.content, self.decoder, visitor)
+    }
+
+    deserialize_num!(deserialize_i8  => visit_i8);
+    deserialize_num!(deserialize_i16 => visit_i16);
+    deserialize_num!(deserialize_i32 => visit_i32);
+    deserialize_num!(deserialize_i64 => visit_i64);
+
+    deserialize_num!(deserialize_u8  => visit_u8);
+    deserialize_num!(deserialize_u16 => visit_u16);
+    deserialize_num!(deserialize_u32 => visit_u32);
+    deserialize_num!(deserialize_u64 => visit_u64);
+
+    serde_if_integer128! {
+        deserialize_num!(deserialize_i128 => visit_i128);
+        deserialize_num!(deserialize_u128 => visit_u128);
+    }
+
+    deserialize_num!(deserialize_f32 => visit_f32);
+    deserialize_num!(deserialize_f64 => visit_f64);
+
+    /// Forwards deserialization to the [`Self::deserialize_str`]
+    fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+    where
+        V: Visitor<'de>,
+    {
+        self.deserialize_str(visitor)
+    }
+
+    fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+    where
+        V: Visitor<'de>,
+    {
+        let content = self.decode()?;
+        if self.escaped {
+            match unescape(content.as_str().as_bytes())? {
+                Cow::Borrowed(_) => content.deserialize_all(visitor),
+                Cow::Owned(buf) => visitor.visit_string(String::from_utf8(buf)?),
+            }
+        } else {
+            content.deserialize_all(visitor)
+        }
+    }
+
+    /// Forwards deserialization to the [`Self::deserialize_str`]
+    fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+    where
+        V: Visitor<'de>,
+    {
+        self.deserialize_str(visitor)
+    }
+
+    fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+    where
+        V: Visitor<'de>,
+    {
+        match self.content {
+            CowRef::Input(content) => visitor.visit_borrowed_bytes(content),
+            CowRef::Slice(content) => visitor.visit_bytes(content),
+            CowRef::Owned(content) => visitor.visit_byte_buf(content),
+        }
+    }
+
+    /// Forwards deserialization to the [`Self::deserialize_bytes`]
+    fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+    where
+        V: Visitor<'de>,
+    {
+        self.deserialize_bytes(visitor)
+    }
+
+    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+    where
+        V: Visitor<'de>,
+    {
+        if self.content.is_empty() {
+            visitor.visit_none()
+        } else {
+            visitor.visit_some(self)
+        }
+    }
+
+    fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+    where
+        V: Visitor<'de>,
+    {
+        visitor.visit_unit()
+    }
+
+    /// Forwards deserialization to the [`Self::deserialize_unit`]
+    fn deserialize_unit_struct<V>(
+        self,
+        _name: &'static str,
+        visitor: V,
+    ) -> Result<V::Value, Self::Error>
+    where
+        V: Visitor<'de>,
+    {
+        self.deserialize_unit(visitor)
+    }
+
+    fn deserialize_newtype_struct<V>(
+        self,
+        _name: &'static str,
+        visitor: V,
+    ) -> Result<V::Value, Self::Error>
+    where
+        V: Visitor<'de>,
+    {
+        visitor.visit_newtype_struct(self)
+    }
+
+    fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+    where
+        V: Visitor<'de>,
+    {
+        visitor.visit_seq(ListIter {
+            content: Some(self.decode()?),
+            escaped: self.escaped,
+        })
+    }
+
+    /// Representation of tuples the same as [sequences][Self::deserialize_seq].
+    fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
+    where
+        V: Visitor<'de>,
+    {
+        self.deserialize_seq(visitor)
+    }
+
+    /// Representation of named tuples the same as [unnamed tuples][Self::deserialize_tuple].
+    fn deserialize_tuple_struct<V>(
+        self,
+        _name: &'static str,
+        len: usize,
+        visitor: V,
+    ) -> Result<V::Value, DeError>
+    where
+        V: Visitor<'de>,
+    {
+        self.deserialize_tuple(len, visitor)
+    }
+
+    unsupported!(deserialize_map => "maps are not supported for XSD `simpleType`s");
+    unsupported!(deserialize_struct(&'static str, &'static [&'static str])
+                 => "structures are not supported for XSD `simpleType`s");
+
+    fn deserialize_enum<V>(
+        self,
+        _name: &'static str,
+        _variants: &'static [&'static str],
+        visitor: V,
+    ) -> Result<V::Value, Self::Error>
+    where
+        V: Visitor<'de>,
+    {
+        visitor.visit_enum(self)
+    }
+
+    /// Forwards deserialization to the [`Self::deserialize_str`]
+    fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+    where
+        V: Visitor<'de>,
+    {
+        self.deserialize_str(visitor)
+    }
+
+    fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+    where
+        V: Visitor<'de>,
+    {
+        visitor.visit_unit()
+    }
+}
+
+impl<'de, 'a> EnumAccess<'de> for SimpleTypeDeserializer<'de, 'a> {
+    type Error = DeError;
+    type Variant = SimpleTypeUnitOnly;
+
+    fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), DeError>
+    where
+        V: DeserializeSeed<'de>,
+    {
+        let name = seed.deserialize(self)?;
+        Ok((name, SimpleTypeUnitOnly))
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/// Deserializer of variant data, that supports only unit variants.
+/// Attempt to deserialize newtype, tuple or struct variant will return a
+/// [`DeError::Unsupported`] error.
+pub struct SimpleTypeUnitOnly;
+impl<'de> VariantAccess<'de> for SimpleTypeUnitOnly {
+    type Error = DeError;
+
+    #[inline]
+    fn unit_variant(self) -> Result<(), DeError> {
+        Ok(())
+    }
+
+    fn newtype_variant_seed<T>(self, _seed: T) -> Result<T::Value, DeError>
+    where
+        T: DeserializeSeed<'de>,
+    {
+        Err(DeError::Unsupported(
+            "enum newtype variants are not supported for XSD `simpleType`s",
+        ))
+    }
+
+    fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value, DeError>
+    where
+        V: Visitor<'de>,
+    {
+        Err(DeError::Unsupported(
+            "enum tuple variants are not supported for XSD `simpleType`s",
+        ))
+    }
+
+    fn struct_variant<V>(
+        self,
+        _fields: &'static [&'static str],
+        _visitor: V,
+    ) -> Result<V::Value, DeError>
+    where
+        V: Visitor<'de>,
+    {
+        Err(DeError::Unsupported(
+            "enum struct variants are not supported for XSD `simpleType`s",
+        ))
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::utils::{ByteBuf, Bytes};
+    use serde::de::IgnoredAny;
+    use serde::Deserialize;
+    use std::collections::HashMap;
+
+    macro_rules! simple {
+        ($encoding:ident, $name:ident: $type:ty = $xml:expr => $result:expr) => {
+            #[test]
+            fn $name() {
+                let decoder = Decoder::$encoding();
+                let xml = $xml;
+                let de = SimpleTypeDeserializer::new(CowRef::Input(xml.as_ref()), true, decoder);
+                let data: $type = Deserialize::deserialize(de).unwrap();
+
+                assert_eq!(data, $result);
+            }
+        };
+    }
+
+    macro_rules! err {
+        ($encoding:ident, $name:ident: $type:ty = $xml:expr => $kind:ident($reason:literal)) => {
+            #[test]
+            fn $name() {
+                let decoder = Decoder::$encoding();
+                let xml = $xml;
+                let de = SimpleTypeDeserializer::new(CowRef::Input(xml.as_ref()), true, decoder);
+                let err = <$type as Deserialize>::deserialize(de).unwrap_err();
+
+                match err {
+                    DeError::$kind(e) => assert_eq!(e, $reason),
+                    _ => panic!(
+                        "Expected `{}({})`, found `{:?}`",
+                        stringify!($kind),
+                        $reason,
+                        err
+                    ),
+                }
+            }
+        };
+    }
+
+    #[derive(Debug, Deserialize, PartialEq)]
+    struct Unit;
+
+    #[derive(Debug, Deserialize, PartialEq)]
+    struct Newtype(String);
+
+    #[derive(Debug, Deserialize, PartialEq)]
+    struct BorrowedNewtype<'a>(&'a str);
+
+    #[derive(Debug, Deserialize, PartialEq)]
+    struct Struct {
+        key: String,
+        val: usize,
+    }
+
+    #[derive(Debug, Deserialize, PartialEq)]
+    enum Enum {
+        Unit,
+        Newtype(String),
+        Tuple(String, usize),
+        Struct { key: String, val: usize },
+    }
+
+    #[derive(Debug, Deserialize, PartialEq)]
+    #[serde(field_identifier)]
+    enum Id {
+        Field,
+    }
+
+    #[derive(Debug, Deserialize)]
+    struct Any(IgnoredAny);
+    impl PartialEq for Any {
+        fn eq(&self, _other: &Any) -> bool {
+            true
+        }
+    }
+
+    /// Tests for deserialize atomic and union values, as defined in XSD specification
+    mod atomic {
+        use super::*;
+        use pretty_assertions::assert_eq;
+
+        /// Checks that given `$input` successfully deserializing into given `$result`
+        macro_rules! deserialized_to {
+            ($name:ident: $type:ty = $input:literal => $result:expr) => {
+                #[test]
+                fn $name() {
+                    let de = AtomicDeserializer {
+                        content: Content::Input($input),
+                        escaped: true,
+                    };
+                    let data: $type = Deserialize::deserialize(de).unwrap();
+
+                    assert_eq!(data, $result);
+                }
+            };
+        }
+
+        /// Checks that attempt to deserialize given `$input` as a `$type` results to a
+        /// deserialization error `$kind` with `$reason`
+        macro_rules! err {
+            ($name:ident: $type:ty = $input:literal => $kind:ident($reason:literal)) => {
+                #[test]
+                fn $name() {
+                    let de = AtomicDeserializer {
+                        content: Content::Input($input),
+                        escaped: true,
+                    };
+                    let err = <$type as Deserialize>::deserialize(de).unwrap_err();
+
+                    match err {
+                        DeError::$kind(e) => assert_eq!(e, $reason),
+                        _ => panic!(
+                            "Expected `{}({})`, found `{:?}`",
+                            stringify!($kind),
+                            $reason,
+                            err
+                        ),
+                    }
+                }
+            };
+        }
+
+        deserialized_to!(any_owned: String = "&lt;escaped&#x20;string" => "<escaped string");
+        deserialized_to!(any_borrowed: &str = "non-escaped string" => "non-escaped string");
+
+        deserialized_to!(false_: bool = "false" => false);
+        deserialized_to!(true_: bool  = "true" => true);
+
+        deserialized_to!(i8_:  i8  = "-2" => -2);
+        deserialized_to!(i16_: i16 = "-2" => -2);
+        deserialized_to!(i32_: i32 = "-2" => -2);
+        deserialized_to!(i64_: i64 = "-2" => -2);
+
+        deserialized_to!(u8_:  u8  = "3" => 3);
+        deserialized_to!(u16_: u16 = "3" => 3);
+        deserialized_to!(u32_: u32 = "3" => 3);
+        deserialized_to!(u64_: u64 = "3" => 3);
+
+        serde_if_integer128! {
+            deserialized_to!(i128_: i128 = "-2" => -2);
+            deserialized_to!(u128_: u128 = "2" => 2);
+        }
+
+        deserialized_to!(f32_: f32 = "1.23" => 1.23);
+        deserialized_to!(f64_: f64 = "1.23" => 1.23);
+
+        deserialized_to!(char_unescaped: char = "h" => 'h');
+        deserialized_to!(char_escaped: char = "&lt;" => '<');
+
+        deserialized_to!(string: String = "&lt;escaped&#x20;string" => "<escaped string");
+        deserialized_to!(borrowed_str: &str = "non-escaped string" => "non-escaped string");
+        err!(escaped_str: &str = "escaped&#x20;string"
+                => Custom("invalid type: string \"escaped string\", expected a borrowed string"));
+
+        err!(byte_buf: ByteBuf = "&lt;escaped&#x20;string"
+                => Unsupported("byte arrays are not supported as `xs:list` items"));
+        err!(borrowed_bytes: Bytes = "non-escaped string"
+                => Unsupported("byte arrays are not supported as `xs:list` items"));
+
+        deserialized_to!(option_none: Option<&str> = "" => None);
+        deserialized_to!(option_some: Option<&str> = "non-escaped string" => Some("non-escaped string"));
+
+        deserialized_to!(unit: () = "<root>anything</root>" => ());
+        deserialized_to!(unit_struct: Unit = "<root>anything</root>" => Unit);
+
+        deserialized_to!(newtype_owned: Newtype = "&lt;escaped&#x20;string" => Newtype("<escaped string".into()));
+        deserialized_to!(newtype_borrowed: BorrowedNewtype = "non-escaped string" => BorrowedNewtype("non-escaped string"));
+
+        err!(seq: Vec<()> = "non-escaped string"
+                => Unsupported("sequences are not supported as `xs:list` items"));
+        err!(tuple: ((), ()) = "non-escaped string"
+                => Unsupported("tuples are not supported as `xs:list` items"));
+        err!(tuple_struct: ((), ()) = "non-escaped string"
+                => Unsupported("tuples are not supported as `xs:list` items"));
+
+        err!(map: HashMap<(), ()> = "non-escaped string"
+                => Unsupported("maps are not supported as `xs:list` items"));
+        err!(struct_: Struct = "non-escaped string"
+                => Unsupported("structures are not supported as `xs:list` items"));
+
+        deserialized_to!(enum_unit: Enum = "Unit" => Enum::Unit);
+        err!(enum_newtype: Enum = "Newtype"
+                => Unsupported("enum newtype variants are not supported as `xs:list` items"));
+        err!(enum_tuple: Enum = "Tuple"
+                => Unsupported("enum tuple variants are not supported as `xs:list` items"));
+        err!(enum_struct: Enum = "Struct"
+                => Unsupported("enum struct variants are not supported as `xs:list` items"));
+        err!(enum_other: Enum = "any data"
+                => Custom("unknown variant `any data`, expected one of `Unit`, `Newtype`, `Tuple`, `Struct`"));
+
+        deserialized_to!(identifier: Id = "Field" => Id::Field);
+        deserialized_to!(ignored_any: Any = "any data" => Any(IgnoredAny));
+
+        /// Checks that deserialization from an owned content is working
+        #[test]
+        #[cfg(feature = "encoding")]
+        fn owned_data() {
+            let de = AtomicDeserializer {
+                content: Content::Owned("string slice".into(), 7),
+                escaped: true,
+            };
+            assert_eq!(de.content.as_str(), "slice");
+
+            let data: String = Deserialize::deserialize(de).unwrap();
+            assert_eq!(data, "slice");
+        }
+
+        /// Checks that deserialization from a content borrowed from some
+        /// buffer other that input is working
+        #[test]
+        fn borrowed_from_deserializer() {
+            let de = AtomicDeserializer {
+                content: Content::Slice("string slice"),
+                escaped: true,
+            };
+            assert_eq!(de.content.as_str(), "string slice");
+
+            let data: String = Deserialize::deserialize(de).unwrap();
+            assert_eq!(data, "string slice");
+        }
+    }
+
+    /// Module for testing list accessor
+    mod list {
+        use super::*;
+        use pretty_assertions::assert_eq;
+
+        #[test]
+        fn empty() {
+            let mut seq = ListIter {
+                content: Some(Content::Input("")),
+                escaped: true,
+            };
+
+            assert_eq!(seq.next_element::<&str>().unwrap(), None);
+            assert_eq!(seq.next_element::<&str>().unwrap(), None);
+        }
+
+        #[test]
+        fn only_spaces() {
+            let mut seq = ListIter {
+                content: Some(Content::Input("  ")),
+                escaped: true,
+            };
+
+            assert_eq!(seq.next_element::<&str>().unwrap(), None);
+            assert_eq!(seq.next_element::<&str>().unwrap(), None);
+        }
+
+        #[test]
+        fn one_item() {
+            let mut seq = ListIter {
+                content: Some(Content::Input("abc")),
+                escaped: true,
+            };
+
+            assert_eq!(seq.next_element::<&str>().unwrap(), Some("abc"));
+            assert_eq!(seq.next_element::<&str>().unwrap(), None);
+            assert_eq!(seq.next_element::<&str>().unwrap(), None);
+        }
+
+        #[test]
+        fn two_items() {
+            let mut seq = ListIter {
+                content: Some(Content::Input("abc def")),
+                escaped: true,
+            };
+
+            assert_eq!(seq.next_element::<&str>().unwrap(), Some("abc"));
+            assert_eq!(seq.next_element::<&str>().unwrap(), Some("def"));
+            assert_eq!(seq.next_element::<&str>().unwrap(), None);
+            assert_eq!(seq.next_element::<&str>().unwrap(), None);
+        }
+
+        #[test]
+        fn leading_spaces() {
+            let mut seq = ListIter {
+                content: Some(Content::Input("  def")),
+                escaped: true,
+            };
+
+            assert_eq!(seq.next_element::<&str>().unwrap(), Some("def"));
+            assert_eq!(seq.next_element::<&str>().unwrap(), None);
+            assert_eq!(seq.next_element::<&str>().unwrap(), None);
+        }
+
+        #[test]
+        fn trailing_spaces() {
+            let mut seq = ListIter {
+                content: Some(Content::Input("abc  ")),
+                escaped: true,
+            };
+
+            assert_eq!(seq.next_element::<&str>().unwrap(), Some("abc"));
+            assert_eq!(seq.next_element::<&str>().unwrap(), None);
+            assert_eq!(seq.next_element::<&str>().unwrap(), None);
+        }
+
+        #[test]
+        fn mixed_types() {
+            let mut seq = ListIter {
+                content: Some(Content::Input("string 1.23 42 true false h Unit")),
+                escaped: true,
+            };
+
+            assert_eq!(seq.next_element::<&str>().unwrap(), Some("string"));
+            assert_eq!(seq.next_element::<f32>().unwrap(), Some(1.23));
+            assert_eq!(seq.next_element::<u32>().unwrap(), Some(42));
+            assert_eq!(seq.next_element::<bool>().unwrap(), Some(true));
+            assert_eq!(seq.next_element::<bool>().unwrap(), Some(false));
+            assert_eq!(seq.next_element::<char>().unwrap(), Some('h'));
+            assert_eq!(seq.next_element::<Enum>().unwrap(), Some(Enum::Unit));
+            assert_eq!(seq.next_element::<()>().unwrap(), None);
+            assert_eq!(seq.next_element::<()>().unwrap(), None);
+        }
+    }
+
+    mod utf8 {
+        use super::*;
+        use pretty_assertions::assert_eq;
+
+        simple!(utf8, i8_:  i8  = "-2" => -2);
+        simple!(utf8, i16_: i16 = "-2" => -2);
+        simple!(utf8, i32_: i32 = "-2" => -2);
+        simple!(utf8, i64_: i64 = "-2" => -2);
+
+        simple!(utf8, u8_:  u8  = "3" => 3);
+        simple!(utf8, u16_: u16 = "3" => 3);
+        simple!(utf8, u32_: u32 = "3" => 3);
+        simple!(utf8, u64_: u64 = "3" => 3);
+
+        serde_if_integer128! {
+            simple!(utf8, i128_: i128 = "-2" => -2);
+            simple!(utf8, u128_: u128 = "2" => 2);
+        }
+
+        simple!(utf8, f32_: f32 = "1.23" => 1.23);
+        simple!(utf8, f64_: f64 = "1.23" => 1.23);
+
+        simple!(utf8, false_: bool = "false" => false);
+        simple!(utf8, true_: bool  = "true" => true);
+        simple!(utf8, char_unescaped: char = "h" => 'h');
+        simple!(utf8, char_escaped: char = "&lt;" => '<');
+
+        simple!(utf8, string: String = "&lt;escaped&#x20;string" => "<escaped string");
+        simple!(utf8, byte_buf: ByteBuf = "&lt;escaped&#x20;string" => ByteBuf(b"&lt;escaped&#x20;string".to_vec()));
+
+        simple!(utf8, borrowed_str: &str = "non-escaped string" => "non-escaped string");
+        simple!(utf8, borrowed_bytes: Bytes = "&lt;escaped&#x20;string" => Bytes(b"&lt;escaped&#x20;string"));
+
+        simple!(utf8, option_none: Option<&str> = "" => None);
+        simple!(utf8, option_some: Option<&str> = "non-escaped string" => Some("non-escaped string"));
+
+        simple!(utf8, unit: () = "any data" => ());
+        simple!(utf8, unit_struct: Unit = "any data" => Unit);
+
+        simple!(utf8, newtype_owned: Newtype = "&lt;escaped&#x20;string" => Newtype("<escaped string".into()));
+        simple!(utf8, newtype_borrowed: BorrowedNewtype = "non-escaped string" => BorrowedNewtype("non-escaped string"));
+
+        err!(utf8, map: HashMap<(), ()> = "any data"
+             => Unsupported("maps are not supported for XSD `simpleType`s"));
+        err!(utf8, struct_: Struct = "any data"
+             => Unsupported("structures are not supported for XSD `simpleType`s"));
+
+        simple!(utf8, enum_unit: Enum = "Unit" => Enum::Unit);
+        err!(utf8, enum_newtype: Enum = "Newtype"
+             => Unsupported("enum newtype variants are not supported for XSD `simpleType`s"));
+        err!(utf8, enum_tuple: Enum = "Tuple"
+             => Unsupported("enum tuple variants are not supported for XSD `simpleType`s"));
+        err!(utf8, enum_struct: Enum = "Struct"
+             => Unsupported("enum struct variants are not supported for XSD `simpleType`s"));
+        err!(utf8, enum_other: Enum = "any data"
+             => Custom("unknown variant `any data`, expected one of `Unit`, `Newtype`, `Tuple`, `Struct`"));
+
+        simple!(utf8, identifier: Id = "Field" => Id::Field);
+        simple!(utf8, ignored_any: Any = "any data" => Any(IgnoredAny));
+    }
+
+    #[cfg(feature = "encoding")]
+    mod utf16 {
+        use super::*;
+        use pretty_assertions::assert_eq;
+
+        fn to_utf16(string: &str) -> Vec<u8> {
+            let mut bytes = Vec::new();
+            for ch in string.encode_utf16() {
+                bytes.extend(&ch.to_le_bytes());
+            }
+            bytes
+        }
+
+        macro_rules! utf16 {
+            ($name:ident: $type:ty = $xml:literal => $result:expr) => {
+                simple!(utf16, $name: $type = to_utf16($xml) => $result);
+            };
+        }
+
+        macro_rules! unsupported {
+            ($name:ident: $type:ty = $xml:literal => $err:literal) => {
+                err!(utf16, $name: $type = to_utf16($xml) => Unsupported($err));
+            };
+        }
+
+        utf16!(i8_:  i8  = "-2" => -2);
+        utf16!(i16_: i16 = "-2" => -2);
+        utf16!(i32_: i32 = "-2" => -2);
+        utf16!(i64_: i64 = "-2" => -2);
+
+        utf16!(u8_:  u8  = "3" => 3);
+        utf16!(u16_: u16 = "3" => 3);
+        utf16!(u32_: u32 = "3" => 3);
+        utf16!(u64_: u64 = "3" => 3);
+
+        serde_if_integer128! {
+            utf16!(i128_: i128 = "-2" => -2);
+            utf16!(u128_: u128 = "2" => 2);
+        }
+
+        utf16!(f32_: f32 = "1.23" => 1.23);
+        utf16!(f64_: f64 = "1.23" => 1.23);
+
+        utf16!(false_: bool = "false" => false);
+        utf16!(true_: bool  = "true" => true);
+        utf16!(char_unescaped: char = "h" => 'h');
+        utf16!(char_escaped: char = "&lt;" => '<');
+
+        utf16!(string: String = "&lt;escaped&#x20;string" => "<escaped string");
+        utf16!(byte_buf: ByteBuf = "&lt;escaped&#x20;string" => ByteBuf(to_utf16("&lt;escaped&#x20;string")));
+
+        utf16!(option_none: Option<()> = "" => None);
+        utf16!(option_some: Option<()> = "any data" => Some(()));
+
+        utf16!(unit: () = "any data" => ());
+        utf16!(unit_struct: Unit = "any data" => Unit);
+
+        utf16!(newtype_owned: Newtype = "&lt;escaped&#x20;string" => Newtype("<escaped string".into()));
+
+        // UTF-16 data never borrow because data was decoded not in-place
+        err!(utf16, newtype_borrowed: BorrowedNewtype = to_utf16("non-escaped string")
+             => Custom("invalid type: string \"non-escaped string\", expected a borrowed string"));
+
+        unsupported!(map: HashMap<(), ()> = "any data"
+                     => "maps are not supported for XSD `simpleType`s");
+        unsupported!(struct_: Struct = "any data"
+                     => "structures are not supported for XSD `simpleType`s");
+
+        utf16!(enum_unit: Enum = "Unit" => Enum::Unit);
+        err!(utf16, enum_newtype: Enum = to_utf16("Newtype")
+             => Unsupported("enum newtype variants are not supported for XSD `simpleType`s"));
+        err!(utf16, enum_tuple: Enum = to_utf16("Tuple")
+             => Unsupported("enum tuple variants are not supported for XSD `simpleType`s"));
+        err!(utf16, enum_struct: Enum = to_utf16("Struct")
+             => Unsupported("enum struct variants are not supported for XSD `simpleType`s"));
+        err!(utf16, enum_other: Enum = to_utf16("any data")
+             => Custom("unknown variant `any data`, expected one of `Unit`, `Newtype`, `Tuple`, `Struct`"));
+
+        utf16!(identifier: Id = "Field" => Id::Field);
+        utf16!(ignored_any: Any = "any data" => Any(IgnoredAny));
+    }
+}
diff --git a/src/events/mod.rs b/src/events/mod.rs
index 0d799e7..ea32101 100644
--- a/src/events/mod.rs
+++ b/src/events/mod.rs
@@ -121,9 +121,9 @@ impl<'a> From<BytesText<'a>> for BytesStartText<'a> {
 #[derive(Clone, Eq, PartialEq)]
 pub struct BytesStart<'a> {
     /// content of the element, before any utf8 conversion
-    buf: Cow<'a, [u8]>,
+    pub(crate) buf: Cow<'a, [u8]>,
     /// end of the element name, the name starts at that the start of `buf`
-    name_len: usize,
+    pub(crate) name_len: usize,
 }
 
 impl<'a> BytesStart<'a> {
diff --git a/src/reader.rs b/src/reader.rs
index 4c556a8..c3d0bbf 100644
--- a/src/reader.rs
+++ b/src/reader.rs
@@ -1549,16 +1549,23 @@ impl Decoder {
     }
 }
 
+/// This implementation is required for tests of other parts of the library
+#[cfg(test)]
+#[cfg(feature = "serialize")]
 impl Decoder {
-    /// This implementation is required for tests of other parts of the library
-    #[cfg(test)]
-    #[cfg(feature = "serialize")]
     pub(crate) fn utf8() -> Self {
         Decoder {
             #[cfg(feature = "encoding")]
             encoding: encoding_rs::UTF_8,
         }
     }
+
+    #[cfg(feature = "encoding")]
+    pub(crate) fn utf16() -> Self {
+        Decoder {
+            encoding: encoding_rs::UTF_16LE,
+        }
+    }
 }
 
 /// Automatic encoding detection of XML files based using the [recommended algorithm]


Test patch:
diff --git a/tests/serde-de.rs b/tests/serde-de.rs
index 1b100ff..be9e153 100644
--- a/tests/serde-de.rs
+++ b/tests/serde-de.rs
@@ -1039,6 +1039,134 @@ mod seq {
                 )
                 .unwrap_err();
             }
+
+            /// Checks that sequences represented by elements can contain sequences,
+            /// represented by [`xs:list`s](https://www.w3schools.com/xml/el_list.asp)
+            mod xs_list {
+                use super::*;
+                use pretty_assertions::assert_eq;
+
+                /// Special case: zero elements
+                #[test]
+                fn zero() {
+                    #[derive(Debug, Deserialize, PartialEq)]
+                    struct List {
+                        /// Outer list mapped to elements, inner -- to `xs:list`.
+                        ///
+                        /// `#[serde(default)]` is required to correctly deserialize
+                        /// empty sequence, because without elements the field
+                        /// also is missing and derived `Deserialize` implementation
+                        /// would complain about that unless field is marked as
+                        /// `default`.
+                        #[serde(default)]
+                        item: [Vec<String>; 0],
+                    }
+
+                    let data: List = from_str(
+                        r#"
+                        <root>
+                        </root>
+                        "#,
+                    )
+                    .unwrap();
+
+                    assert_eq!(data, List { item: [] });
+                }
+
+                /// Special case: one element
+                #[test]
+                fn one() {
+                    #[derive(Debug, Deserialize, PartialEq)]
+                    struct List {
+                        /// Outer list mapped to elements, inner -- to `xs:list`.
+                        ///
+                        /// `#[serde(default)]` is not required, because correct
+                        /// XML will always contains at least 1 element.
+                        item: [Vec<String>; 1],
+                    }
+
+                    let data: List = from_str(
+                        r#"
+                        <root>
+                            <item>first list</item>
+                        </root>
+                        "#,
+                    )
+                    .unwrap();
+
+                    assert_eq!(
+                        data,
+                        List {
+                            item: [vec!["first".to_string(), "list".to_string()]]
+                        }
+                    );
+                }
+
+                /// Special case: outer list is always mapped to an elements sequence,
+                /// not to an `xs:list`
+                #[test]
+                fn element() {
+                    #[derive(Debug, Deserialize, PartialEq)]
+                    struct List {
+                        /// Outer list mapped to elements, inner -- to `xs:list`.
+                        ///
+                        /// `#[serde(default)]` is not required, because correct
+                        /// XML will always contains at least 1 element.
+                        item: [String; 1],
+                    }
+
+                    let data: List = from_str(
+                        r#"
+                        <root>
+                            <item>first item</item>
+                        </root>
+                        "#,
+                    )
+                    .unwrap();
+
+                    assert_eq!(
+                        data,
+                        List {
+                            item: ["first item".to_string()]
+                        }
+                    );
+                }
+
+                /// This tests demonstrates, that for `$value` field (`list`) actual
+                /// name of XML element (`item`) does not matter. That allows list
+                /// item to be an enum, where tag name determines enum variant
+                #[test]
+                fn many() {
+                    #[derive(Debug, Deserialize, PartialEq)]
+                    struct List {
+                        /// Outer list mapped to elements, inner -- to `xs:list`.
+                        ///
+                        /// `#[serde(default)]` is not required, because correct
+                        /// XML will always contains at least 1 element.
+                        item: [Vec<String>; 2],
+                    }
+
+                    let data: List = from_str(
+                        r#"
+                        <root>
+                            <item>first list</item>
+                            <item>second list</item>
+                        </root>
+                        "#,
+                    )
+                    .unwrap();
+
+                    assert_eq!(
+                        data,
+                        List {
+                            item: [
+                                vec!["first".to_string(), "list".to_string()],
+                                vec!["second".to_string(), "list".to_string()],
+                            ]
+                        }
+                    );
+                }
+            }
         }
 
         /// This module contains tests where size of the list have an unspecified size
@@ -1505,6 +1633,115 @@ mod seq {
                 )
                 .unwrap_err();
             }
+
+            /// Checks that sequences represented by elements can contain sequences,
+            /// represented by `xs:list`s
+            mod xs_list {
+                use super::*;
+                use pretty_assertions::assert_eq;
+
+                #[derive(Debug, Deserialize, PartialEq)]
+                struct List {
+                    /// Outer list mapped to elements, inner -- to `xs:list`.
+                    /// `#[serde(default)]` is required to correctly deserialize
+                    /// empty sequence, because without elements the field
+                    /// also is missing and derived `Deserialize` implementation
+                    /// would complain about that unless field is marked as
+                    /// `default`.
+                    #[serde(default)]
+                    item: Vec<Vec<String>>,
+                }
+
+                /// Special case: zero elements
+                #[test]
+                fn zero() {
+                    let data: List = from_str(
+                        r#"
+                        <root>
+                        </root>
+                        "#,
+                    )
+                    .unwrap();
+
+                    assert_eq!(data, List { item: vec![] });
+                }
+
+                /// Special case: one element
+                #[test]
+                fn one() {
+                    let data: List = from_str(
+                        r#"
+                        <root>
+                            <item>first list</item>
+                        </root>
+                        "#,
+                    )
+                    .unwrap();
+
+                    assert_eq!(
+                        data,
+                        List {
+                            item: vec![vec!["first".to_string(), "list".to_string()]]
+                        }
+                    );
+                }
+
+                /// Special case: outer list is always mapped to an elements sequence,
+                /// not to an `xs:list`
+                #[test]
+                fn element() {
+                    #[derive(Debug, Deserialize, PartialEq)]
+                    struct List {
+                        /// Outer list mapped to elements, inner -- to `xs:list`.
+                        ///
+                        /// `#[serde(default)]` is not required, because correct
+                        /// XML will always contains at least 1 element.
+                        item: Vec<String>,
+                    }
+
+                    let data: List = from_str(
+                        r#"
+                        <root>
+                            <item>first item</item>
+                        </root>
+                        "#,
+                    )
+                    .unwrap();
+
+                    assert_eq!(
+                        data,
+                        List {
+                            item: vec!["first item".to_string()]
+                        }
+                    );
+                }
+
+                /// This tests demonstrates, that for `$value` field (`list`) actual
+                /// name of XML element (`item`) does not matter. That allows list
+                /// item to be an enum, where tag name determines enum variant
+                #[test]
+                fn many() {
+                    let data: List = from_str(
+                        r#"
+                        <root>
+                            <item>first list</item>
+                            <item>second list</item>
+                        </root>
+                        "#,
+                    )
+                    .unwrap();
+
+                    assert_eq!(
+                        data,
+                        List {
+                            item: vec![
+                                vec!["first".to_string(), "list".to_string()],
+                                vec!["second".to_string(), "list".to_string()],
+                            ]
+                        }
+                    );
+                }
+            }
         }
     }
 
@@ -2349,6 +2586,132 @@ mod seq {
                 )
                 .unwrap_err();
             }
+
+            /// Checks that sequences represented by elements can contain sequences,
+            /// represented by `xs:list`s
+            mod xs_list {
+                use super::*;
+                use pretty_assertions::assert_eq;
+
+                /// Special case: zero elements
+                #[test]
+                fn zero() {
+                    #[derive(Debug, Deserialize, PartialEq)]
+                    struct List {
+                        /// Outer list mapped to elements, inner -- to `xs:list`.
+                        ///
+                        /// `#[serde(default)]` is required to correctly deserialize
+                        /// empty sequence, because without elements the field
+                        /// also is missing and derived `Deserialize` implementation
+                        /// would complain about that unless field is marked as
+                        /// `default`.
+                        #[serde(default)]
+                        #[serde(rename = "$value")]
+                        element: [Vec<String>; 0],
+                    }
+
+                    let data: List = from_str(
+                        r#"
+                        <root>
+                        </root>
+                        "#,
+                    )
+                    .unwrap();
+
+                    assert_eq!(data, List { element: [] });
+                }
+
+                /// Special case: one element
+                #[test]
+                fn one() {
+                    #[derive(Debug, Deserialize, PartialEq)]
+                    struct List {
+                        /// Outer list mapped to elements, inner -- to `xs:list`.
+                        ///
+                        /// `#[serde(default)]` is not required, because correct
+                        /// XML will always contains at least 1 element.
+                        #[serde(rename = "$value")]
+                        element: [Vec<String>; 1],
+                    }
+
+                    let data: List = from_str(
+                        r#"
+                        <root>
+                            <item>first list</item>
+                        </root>
+                        "#,
+                    )
+                    .unwrap();
+
+                    assert_eq!(
+                        data,
+                        List {
+                            element: [vec!["first".to_string(), "list".to_string()]]
+                        }
+                    );
+                }
+
+                /// Special case: outer list is always mapped to an elements sequence,
+                /// not to an `xs:list`
+                #[test]
+                fn element() {
+                    #[derive(Debug, Deserialize, PartialEq)]
+                    struct List {
+                        /// Outer list mapped to elements, inner -- to `xs:list`.
+                        ///
+                        /// `#[serde(default)]` is not required, because correct
+                        /// XML will always contains at least 1 element.
+                        #[serde(rename = "$value")]
+                        element: [String; 1],
+                    }
+
+                    let data: List = from_str(
+                        r#"
+                        <root>
+                            <item>first item</item>
+                        </root>
+                        "#,
+                    )
+                    .unwrap();
+
+                    assert_eq!(
+                        data,
+                        List {
+                            element: ["first item".to_string()]
+                        }
+                    );
+                }
+
+                #[test]
+                fn many() {
+                    #[derive(Debug, Deserialize, PartialEq)]
+                    struct List {
+                        /// Outer list mapped to elements, inner -- to `xs:list`
+                        #[serde(rename = "$value")]
+                        element: [Vec<String>; 2],
+                    }
+
+                    let data: List = from_str(
+                        r#"
+                        <root>
+                            <item>first list</item>
+                            <item>second list</item>
+                        </root>
+                        "#,
+                    )
+                    .unwrap();
+
+                    assert_eq!(
+                        data,
+                        List {
+                            element: [
+                                vec!["first".to_string(), "list".to_string()],
+                                vec!["second".to_string(), "list".to_string()],
+                            ]
+                        }
+                    );
+                }
+            }
         }
 
         /// This module contains tests where size of the list have an unspecified size
@@ -3032,6 +3395,115 @@ mod seq {
                 )
                 .unwrap_err();
             }
+
+            /// Checks that sequences represented by elements can contain sequences,
+            /// represented by `xs:list`s
+            mod xs_list {
+                use super::*;
+                use pretty_assertions::assert_eq;
+
+                #[derive(Debug, Deserialize, PartialEq)]
+                struct List {
+                    /// Outer list mapped to elements, inner -- to `xs:list`.
+                    ///
+                    /// `#[serde(default)]` is required to correctly deserialize
+                    /// empty sequence, because without elements the field
+                    /// also is missing and derived `Deserialize` implementation
+                    /// would complain about that unless field is marked as
+                    /// `default`.
+                    #[serde(default)]
+                    #[serde(rename = "$value")]
+                    element: Vec<Vec<String>>,
+                }
+
+                /// Special case: zero elements
+                #[test]
+                fn zero() {
+                    let data: List = from_str(
+                        r#"
+                        <root>
+                        </root>
+                        "#,
+                    )
+                    .unwrap();
+
+                    assert_eq!(data, List { element: vec![] });
+                }
+
+                /// Special case: one element
+                #[test]
+                fn one() {
+                    let data: List = from_str(
+                        r#"
+                        <root>
+                            <item>first list</item>
+                        </root>
+                        "#,
+                    )
+                    .unwrap();
+
+                    assert_eq!(
+                        data,
+                        List {
+                            element: vec![vec!["first".to_string(), "list".to_string()]]
+                        }
+                    );
+                }
+
+                /// Special case: outer list is always mapped to an elements sequence,
+                /// not to an `xs:list`
+                #[test]
+                fn element() {
+                    #[derive(Debug, Deserialize, PartialEq)]
+                    struct List {
+                        /// Outer list mapped to elements.
+                        #[serde(rename = "$value")]
+                        element: Vec<String>,
+                    }
+
+                    let data: List = from_str(
+                        r#"
+                        <root>
+                            <item>first item</item>
+                        </root>
+                        "#,
+                    )
+                    .unwrap();
+
+                    assert_eq!(
+                        data,
+                        List {
+                            element: vec!["first item".to_string()]
+                        }
+                    );
+                }
+
+                /// This tests demonstrates, that for `$value` field (`list`) actual
+                /// name of XML element (`item`) does not matter. That allows list
+                /// item to be an enum, where tag name determines enum variant
+                #[test]
+                fn many() {
+                    let data: List = from_str(
+                        r#"
+                        <root>
+                            <item>first list</item>
+                            <item>second list</item>
+                        </root>
+                        "#,
+                    )
+                    .unwrap();
+
+                    assert_eq!(
+                        data,
+                        List {
+                            element: vec![
+                                vec!["first".to_string(), "list".to_string()],
+                                vec!["second".to_string(), "list".to_string()],
+                            ]
+                        }
+                    );
+                }
+            }
         }
     }
 }
@@ -4127,3 +4599,169 @@ mod enum_ {
         }
     }
 }
+
+/// https://www.w3schools.com/xml/el_list.asp
+mod xml_schema_lists {
+    use super::*;
+
+    macro_rules! list {
+        ($name:ident: $type:ty = $xml:literal => $result:expr) => {
+            #[test]
+            fn $name() {
+                let data: List<$type> = from_str($xml).unwrap();
+
+                assert_eq!(data, List { list: $result });
+            }
+        };
+    }
+
+    macro_rules! err {
+        ($name:ident: $type:ty = $xml:literal => $kind:ident($err:literal)) => {
+            #[test]
+            fn $name() {
+                let err = from_str::<List<$type>>($xml).unwrap_err();
+
+                match err {
+                    DeError::$kind(e) => assert_eq!(e, $err),
+                    _ => panic!(
+                        "Expected `{}({})`, found `{:?}`",
+                        stringify!($kind),
+                        $err,
+                        err
+                    ),
+                }
+            }
+        };
+    }
+
+    /// Checks that sequences can be deserialized from an XML attribute content
+    /// according to the `xs:list` XML Schema type
+    mod attribute {
+        use super::*;
+        use pretty_assertions::assert_eq;
+
+        #[derive(Debug, Deserialize, PartialEq)]
+        struct List<T> {
+            list: Vec<T>,
+        }
+
+        list!(i8_:  i8  = r#"<root list="1 -2  3"/>"# => vec![1, -2, 3]);
+        list!(i16_: i16 = r#"<root list="1 -2  3"/>"# => vec![1, -2, 3]);
+        list!(i32_: i32 = r#"<root list="1 -2  3"/>"# => vec![1, -2, 3]);
+        list!(i64_: i64 = r#"<root list="1 -2  3"/>"# => vec![1, -2, 3]);
+
+        list!(u8_:  u8  = r#"<root list="1 2  3"/>"# => vec![1, 2, 3]);
+        list!(u16_: u16 = r#"<root list="1 2  3"/>"# => vec![1, 2, 3]);
+        list!(u32_: u32 = r#"<root list="1 2  3"/>"# => vec![1, 2, 3]);
+        list!(u64_: u64 = r#"<root list="1 2  3"/>"# => vec![1, 2, 3]);
+
+        serde_if_integer128! {
+            list!(i128_: i128 = r#"<root list="1 -2  3"/>"# => vec![1, -2, 3]);
+            list!(u128_: u128 = r#"<root list="1 2  3"/>"# => vec![1, 2, 3]);
+        }
+
+        list!(f32_: f32 = r#"<root list="1.23 -4.56  7.89"/>"# => vec![1.23, -4.56, 7.89]);
+        list!(f64_: f64 = r#"<root list="1.23 -4.56  7.89"/>"# => vec![1.23, -4.56, 7.89]);
+
+        list!(bool_: bool = r#"<root list="true false  true"/>"# => vec![true, false, true]);
+        list!(char_: char = r#"<root list="4 2  j"/>"# => vec!['4', '2', 'j']);
+
+        list!(string: String = r#"<root list="first second  third&#x20;3"/>"# => vec![
+            "first".to_string(),
+            "second".to_string(),
+            "third 3".to_string(),
+        ]);
+        err!(byte_buf: ByteBuf = r#"<root list="first second  third&#x20;3"/>"#
+                => Unsupported("byte arrays are not supported as `xs:list` items"));
+
+        list!(unit: () = r#"<root list="1 second  false"/>"# => vec![(), (), ()]);
+    }
+
+    /// Checks that sequences can be deserialized from an XML text content
+    /// according to the `xs:list` XML Schema type
+    mod element {
+        use super::*;
+
+        #[derive(Debug, Deserialize, PartialEq)]
+        struct List<T> {
+            // Give it a special name that means text content of the XML node
+            #[serde(rename = "$value")]
+            list: Vec<T>,
+        }
+
+        mod text {
+            use super::*;
+            use pretty_assertions::assert_eq;
+
+            list!(i8_:  i8  = "<root>1 -2  3</root>" => vec![1, -2, 3]);
+            list!(i16_: i16 = "<root>1 -2  3</root>" => vec![1, -2, 3]);
+            list!(i32_: i32 = "<root>1 -2  3</root>" => vec![1, -2, 3]);
+            list!(i64_: i64 = "<root>1 -2  3</root>" => vec![1, -2, 3]);
+
+            list!(u8_:  u8  = "<root>1 2  3</root>" => vec![1, 2, 3]);
+            list!(u16_: u16 = "<root>1 2  3</root>" => vec![1, 2, 3]);
+            list!(u32_: u32 = "<root>1 2  3</root>" => vec![1, 2, 3]);
+            list!(u64_: u64 = "<root>1 2  3</root>" => vec![1, 2, 3]);
+
+            serde_if_integer128! {
+                list!(i128_: i128 = "<root>1 -2  3</root>" => vec![1, -2, 3]);
+                list!(u128_: u128 = "<root>1 2  3</root>" => vec![1, 2, 3]);
+            }
+
+            list!(f32_: f32 = "<root>1.23 -4.56  7.89</root>" => vec![1.23, -4.56, 7.89]);
+            list!(f64_: f64 = "<root>1.23 -4.56  7.89</root>" => vec![1.23, -4.56, 7.89]);
+
+            list!(bool_: bool = "<root>true false  true</root>" => vec![true, false, true]);
+            list!(char_: char = "<root>4 2  j</root>" => vec!['4', '2', 'j']);
+
+            list!(string: String = "<root>first second  third&#x20;3</root>" => vec![
+                "first".to_string(),
+                "second".to_string(),
+                "third 3".to_string(),
+            ]);
+            err!(byte_buf: ByteBuf = "<root>first second  third&#x20;3</root>"
+                => Unsupported("byte arrays are not supported as `xs:list` items"));
+
+            list!(unit: () = "<root>1 second  false</root>" => vec![(), (), ()]);
+        }
+
+        mod cdata {
+            use super::*;
+            use pretty_assertions::assert_eq;
+
+            list!(i8_:  i8  = "<root><![CDATA[1 -2  3]]></root>" => vec![1, -2, 3]);
+            list!(i16_: i16 = "<root><![CDATA[1 -2  3]]></root>" => vec![1, -2, 3]);
+            list!(i32_: i32 = "<root><![CDATA[1 -2  3]]></root>" => vec![1, -2, 3]);
+            list!(i64_: i64 = "<root><![CDATA[1 -2  3]]></root>" => vec![1, -2, 3]);
+
+            list!(u8_:  u8  = "<root><![CDATA[1 2  3]]></root>" => vec![1, 2, 3]);
+            list!(u16_: u16 = "<root><![CDATA[1 2  3]]></root>" => vec![1, 2, 3]);
+            list!(u32_: u32 = "<root><![CDATA[1 2  3]]></root>" => vec![1, 2, 3]);
+            list!(u64_: u64 = "<root><![CDATA[1 2  3]]></root>" => vec![1, 2, 3]);
+
+            serde_if_integer128! {
+                list!(i128_: i128 = "<root><![CDATA[1 -2  3]]></root>" => vec![1, -2, 3]);
+                list!(u128_: u128 = "<root><![CDATA[1 2  3]]></root>" => vec![1, 2, 3]);
+            }
+
+            list!(f32_: f32 = "<root><![CDATA[1.23 -4.56  7.89]]></root>" => vec![1.23, -4.56, 7.89]);
+            list!(f64_: f64 = "<root><![CDATA[1.23 -4.56  7.89]]></root>" => vec![1.23, -4.56, 7.89]);
+
+            list!(bool_: bool = "<root><![CDATA[true false  true]]></root>" => vec![true, false, true]);
+            list!(char_: char = "<root><![CDATA[4 2  j]]></root>" => vec!['4', '2', 'j']);
+
+            // Cannot get whitespace in the value in any way if CDATA used:
+            // - literal spaces means list item delimiters
+            // - escaped sequences are not decoded in CDATA
+            list!(string: String = "<root><![CDATA[first second  third&#x20;3]]></root>" => vec![
+                "first".to_string(),
+                "second".to_string(),
+                "third&#x20;3".to_string(),
+            ]);
+            err!(byte_buf: ByteBuf = "<root>first second  third&#x20;3</root>"
+                => Unsupported("byte arrays are not supported as `xs:list` items"));
+
+            list!(unit: () = "<root>1 second  false</root>" => vec![(), (), ()]);
+        }
+    }
+}