Skip to content

Commit 899d573

Browse files
Mingundralley
authored andcommitted
Skip unwanted text events in sequences
If sequence expected only tags, skip any texts (CDATA included) If sequence expected any values, skip texts (CDATA included) if there is a dedicated "$text" field Fixed: serde-de-seq: fixed_name::variable_size::text_and_value variable_name::variable_size::text_and_value serde-issues: issue868
1 parent 5942a13 commit 899d573

File tree

2 files changed

+25
-4
lines changed

2 files changed

+25
-4
lines changed

Changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ types should preserve whitespace, while all other primitives have collapse behav
3939

4040
- [#868]: Allow to have both `$text` and `$value` special fields in one struct. Previously
4141
any text will be recognized as `$value` field even when `$text` field is also presented.
42+
- [#868]: Skip text events when deserialize a sequence of items overlapped with text (including CDATA).
4243

4344
### Misc Changes
4445

src/de/map.rs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -619,7 +619,7 @@ where
619619
_ => unreachable!(),
620620
}
621621
} else {
622-
TagFilter::Exclude(self.map.fields)
622+
TagFilter::Exclude(self.map.fields, self.map.has_text_field)
623623
};
624624
visitor.visit_seq(MapValueSeqAccess {
625625
#[cfg(feature = "overlapped-lists")]
@@ -860,15 +860,27 @@ enum TagFilter<'de> {
860860
Include(BytesStart<'de>), //TODO: Need to store only name instead of a whole tag
861861
/// A `SeqAccess` interested in tags with any name, except explicitly listed.
862862
/// Excluded tags are used as struct field names and therefore should not
863-
/// fall into a `$value` category
864-
Exclude(&'static [&'static str]),
863+
/// fall into a `$value` category.
864+
///
865+
/// The `bool` represents the having of a `$text` special field in fields array.
866+
/// It is used to exclude text events when `$text` fields is defined together with
867+
/// `$value` fieldб and `$value` accepts sequence.
868+
Exclude(&'static [&'static str], bool),
865869
}
866870

867871
impl<'de> TagFilter<'de> {
868872
fn is_suitable(&self, start: &BytesStart) -> Result<bool, DeError> {
869873
match self {
870874
Self::Include(n) => Ok(n.name() == start.name()),
871-
Self::Exclude(fields) => not_in(fields, start),
875+
Self::Exclude(fields, _) => not_in(fields, start),
876+
}
877+
}
878+
const fn need_skip_text(&self) -> bool {
879+
match self {
880+
// If we look only for tags, we should skip any $text keys
881+
Self::Include(_) => true,
882+
// If we look fo any data, we should exclude $text keys if it in the list
883+
Self::Exclude(_, has_text_field) => *has_text_field,
872884
}
873885
}
874886
}
@@ -953,9 +965,17 @@ where
953965
self.map.de.skip()?;
954966
continue;
955967
}
968+
// Skip any text events if sequence expects only specific tag names
969+
#[cfg(feature = "overlapped-lists")]
970+
DeEvent::Text(_) if self.filter.need_skip_text() => {
971+
self.map.de.skip()?;
972+
continue;
973+
}
956974
// Stop iteration when list elements ends
957975
#[cfg(not(feature = "overlapped-lists"))]
958976
DeEvent::Start(e) if !self.filter.is_suitable(e)? => Ok(None),
977+
#[cfg(not(feature = "overlapped-lists"))]
978+
DeEvent::Text(_) if self.filter.need_skip_text() => Ok(None),
959979

960980
// Stop iteration after reaching a closing tag
961981
// The matching tag name is guaranteed by the reader

0 commit comments

Comments
 (0)