Skip to content

Commit e453679

Browse files
committed
Allow both &text and $value fields in the same struct
failures: fixed_name::variable_size::text_and_value variable_name::variable_size::text_and_value
1 parent 8258d97 commit e453679

File tree

3 files changed

+111
-5
lines changed

3 files changed

+111
-5
lines changed

Changelog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ XML specification. See the updated `custom_entities` example!
3333

3434
### Bug Fixes
3535

36+
- [#868]: Allow to have both `$text` and `$value` special fields in one struct. Previously
37+
any text will be recognized as `$value` field even when `$text` field is also presented.
38+
3639
### Misc Changes
3740

3841
- [#863]: Remove `From<QName<'a>> for BytesStart<'a>` because now `BytesStart` stores the
@@ -42,6 +45,7 @@ XML specification. See the updated `custom_entities` example!
4245

4346
[#766]: https://github.com/tafia/quick-xml/pull/766
4447
[#863]: https://github.com/tafia/quick-xml/pull/863
48+
[#868]: https://github.com/tafia/quick-xml/pull/868
4549
[general entity]: https://www.w3.org/TR/xml11/#gen-entity
4650

4751

src/de/map.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,8 @@ where
192192
/// <tag>value for VALUE_KEY field<tag>
193193
/// ```
194194
has_value_field: bool,
195+
/// Determines if struct have [`VALUE_KEY`], but not [`TEXT_KEY`] special fields.
196+
text_as_value: bool,
195197
}
196198

197199
impl<'de, 'd, R, E> ElementMapAccess<'de, 'd, R, E>
@@ -205,13 +207,16 @@ where
205207
start: BytesStart<'de>,
206208
fields: &'static [&'static str],
207209
) -> Result<Self, DeError> {
210+
let has_value_field = fields.contains(&VALUE_KEY);
208211
Ok(Self {
209212
de,
210213
iter: IterState::new(start.name().as_ref().len(), false),
211214
start,
212215
source: ValueSource::Unknown,
213216
fields,
214-
has_value_field: fields.contains(&VALUE_KEY),
217+
has_value_field,
218+
// If we have dedicated "$text" field, it will not be passed to "$value" field
219+
text_as_value: has_value_field && !fields.contains(&TEXT_KEY),
215220
})
216221
}
217222

@@ -264,10 +269,7 @@ where
264269
} else {
265270
// try getting from events (<key>value</key>)
266271
match self.de.peek()? {
267-
// We shouldn't have both `$value` and `$text` fields in the same
268-
// struct, so if we have `$value` field, the we should deserialize
269-
// text content to `$value`
270-
DeEvent::Text(_) if self.has_value_field => {
272+
DeEvent::Text(_) if self.text_as_value => {
271273
self.source = ValueSource::Content;
272274
// Deserialize `key` from special attribute name which means
273275
// that value should be taken from the text content of the

tests/serde-de-seq.rs

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -821,6 +821,28 @@ mod fixed_name {
821821
);
822822
}
823823

824+
#[test]
825+
fn text_and_value() {
826+
#[derive(Debug, PartialEq, Deserialize)]
827+
struct List {
828+
#[serde(rename = "$text")]
829+
text: (),
830+
item: [(); 2],
831+
}
832+
833+
from_str::<List>(
834+
r#"
835+
<root>
836+
<item/>
837+
<item/>
838+
text
839+
<![CDATA[cdata]]>
840+
</root>
841+
"#,
842+
)
843+
.unwrap();
844+
}
845+
824846
/// Checks that sequences represented by elements can contain sequences,
825847
/// represented by [`xs:list`s](https://www.w3schools.com/xml/el_list.asp)
826848
mod xs_list {
@@ -1656,6 +1678,33 @@ mod fixed_name {
16561678
);
16571679
}
16581680

1681+
#[test]
1682+
fn text_and_value() {
1683+
#[derive(Debug, PartialEq, Deserialize)]
1684+
struct List {
1685+
#[serde(rename = "$text")]
1686+
text: (),
1687+
item: Vec<()>,
1688+
}
1689+
1690+
let data: List = from_str(
1691+
r#"
1692+
<root>
1693+
<item/>
1694+
<item/>
1695+
text
1696+
<![CDATA[cdata]]>
1697+
</root>
1698+
"#,
1699+
)
1700+
.unwrap();
1701+
1702+
assert_eq!(data, List {
1703+
text: (),
1704+
item: vec![(); 2],
1705+
});
1706+
}
1707+
16591708
/// Checks that sequences represented by elements can contain sequences,
16601709
/// represented by `xs:list`s
16611710
mod xs_list {
@@ -2883,6 +2932,29 @@ mod variable_name {
28832932
);
28842933
}
28852934

2935+
#[test]
2936+
fn text_and_value() {
2937+
#[derive(Debug, PartialEq, Deserialize)]
2938+
struct List {
2939+
#[serde(rename = "$text")]
2940+
text: (),
2941+
#[serde(rename = "$value")]
2942+
value: [(); 2],
2943+
}
2944+
2945+
from_str::<List>(
2946+
r#"
2947+
<root>
2948+
<item/>
2949+
<item/>
2950+
text
2951+
<![CDATA[cdata]]>
2952+
</root>
2953+
"#,
2954+
)
2955+
.unwrap();
2956+
}
2957+
28862958
/// Checks that sequences represented by elements can contain sequences,
28872959
/// represented by `xs:list`s
28882960
mod xs_list {
@@ -3929,6 +4001,34 @@ mod variable_name {
39294001
.unwrap_err();
39304002
}
39314003

4004+
#[test]
4005+
fn text_and_value() {
4006+
#[derive(Debug, PartialEq, Deserialize)]
4007+
struct List {
4008+
#[serde(rename = "$text")]
4009+
text: (),
4010+
#[serde(rename = "$value")]
4011+
value: Vec<()>,
4012+
}
4013+
4014+
let data: List = from_str(
4015+
r#"
4016+
<root>
4017+
<item/>
4018+
<item/>
4019+
text
4020+
<![CDATA[cdata]]>
4021+
</root>
4022+
"#,
4023+
)
4024+
.unwrap();
4025+
4026+
assert_eq!(data, List {
4027+
text: (),
4028+
value: vec![(); 2],
4029+
});
4030+
}
4031+
39324032
/// Checks that sequences represented by elements can contain sequences,
39334033
/// represented by `xs:list`s
39344034
mod xs_list {

0 commit comments

Comments
 (0)