122122//! # Ok::<(), Box<dyn std::error::Error>>(())
123123//! ```
124124//!
125+ //! The reserved name `#content` is used to flatten one level of the hierarchy and
126+ //! revisit those nodes and attributes as if embedded inside another struct. This can
127+ //! useful to handle partial alternatives:
128+ //!
129+ //! ```
130+ //! use serde::Deserialize;
131+ //! use serde_roxmltree::from_str;
132+ //!
133+ //! #[derive(Debug, PartialEq, Deserialize)]
134+ //! #[serde(rename_all = "lowercase")]
135+ //! enum Alternative {
136+ //! Float(f32),
137+ //! Integer(i32),
138+ //! }
139+ //!
140+ //! #[derive(Debug, PartialEq, Deserialize)]
141+ //! struct Record {
142+ //! #[serde(rename = "#content")]
143+ //! alternative: Alternative,
144+ //! string: String,
145+ //! }
146+ //!
147+ //! let record = from_str::<Record>("<record><float>42.0</float><string>foo</string></record>")?;
148+ //! assert_eq!(record.alternative, Alternative::Float(42.0));
149+ //! assert_eq!(record.string, "foo");
150+ //!
151+ //! let record = from_str::<Record>("<record><integer>23</integer><string>bar</string></record>")?;
152+ //! assert_eq!(record.alternative, Alternative::Integer(23));
153+ //! assert_eq!(record.string, "bar");
154+ //! #
155+ //! # Ok::<(), Box<dyn std::error::Error>>(())
156+ //! ```
157+ //!
125158//! Optionally, attribute names can be prefixed by `@` to distinguish them from tag names:
126159//!
127160//! ```
@@ -362,6 +395,7 @@ enum Source<'de, 'input> {
362395 Node ( Node < ' de , ' input > ) ,
363396 Attribute ( Attribute < ' de , ' input > ) ,
364397 Text ( & ' de str ) ,
398+ Content ( Node < ' de , ' input > ) ,
365399}
366400
367401#[ derive( Default ) ]
@@ -440,12 +474,13 @@ where
440474 }
441475 }
442476 Source :: Text ( _) => "$text" ,
477+ Source :: Content ( _) => "#content" ,
443478 }
444479 }
445480
446481 fn node ( & self ) -> Result < & Node < ' de , ' input > , Error > {
447482 match & self . source {
448- Source :: Node ( node) => Ok ( node) ,
483+ Source :: Node ( node) | Source :: Content ( node ) => Ok ( node) ,
449484 Source :: Attribute ( _) | Source :: Text ( _) => Err ( Error :: MissingNode ) ,
450485 }
451486 }
@@ -473,7 +508,9 @@ where
473508
474509 let text = once ( Source :: Text ( node. text ( ) . unwrap_or_default ( ) ) ) ;
475510
476- Ok ( children. chain ( attributes) . chain ( text) )
511+ let content = once ( Source :: Content ( * node) ) ;
512+
513+ Ok ( children. chain ( attributes) . chain ( text) . chain ( content) )
477514 }
478515
479516 fn siblings ( & self ) -> Result < impl Iterator < Item = Node < ' de , ' de > > , Error > {
@@ -494,7 +531,7 @@ where
494531
495532 fn text ( & self ) -> & ' de str {
496533 match self . source {
497- Source :: Node ( node) => node. text ( ) . unwrap_or_default ( ) ,
534+ Source :: Node ( node) | Source :: Content ( node ) => node. text ( ) . unwrap_or_default ( ) ,
498535 Source :: Attribute ( attr) => attr. value ( ) ,
499536 Source :: Text ( text) => text,
500537 }
@@ -1174,6 +1211,51 @@ mod tests {
11741211 assert_eq ! ( val, Root :: Bar ( 42 ) ) ;
11751212 }
11761213
1214+ #[ test]
1215+ fn mixed_enum_and_struct_children ( ) {
1216+ #[ derive( Debug , PartialEq , Deserialize ) ]
1217+ enum Foobar {
1218+ Foo ( u32 ) ,
1219+ Bar ( i64 ) ,
1220+ }
1221+
1222+ #[ derive( Deserialize ) ]
1223+ struct Root {
1224+ #[ serde( rename = "#content" ) ]
1225+ foobar : Foobar ,
1226+ qux : f32 ,
1227+ }
1228+
1229+ let val = from_str :: < Root > ( r#"<root><Foo>23</Foo><qux>42.0</qux></root>"# ) . unwrap ( ) ;
1230+ assert_eq ! ( val. foobar, Foobar :: Foo ( 23 ) ) ;
1231+ assert_eq ! ( val. qux, 42.0 ) ;
1232+ }
1233+
1234+ #[ test]
1235+ fn mixed_enum_and_repeated_struct_children ( ) {
1236+ #[ derive( Debug , PartialEq , Deserialize ) ]
1237+ enum Foobar {
1238+ Foo ( u32 ) ,
1239+ Bar ( i64 ) ,
1240+ }
1241+
1242+ #[ derive( Deserialize ) ]
1243+ struct Root {
1244+ #[ serde( rename = "#content" ) ]
1245+ foobar : Foobar ,
1246+ qux : Vec < f32 > ,
1247+ baz : String ,
1248+ }
1249+
1250+ let val = from_str :: < Root > (
1251+ r#"<root><Bar>42</Bar><qux>1.0</qux><baz>baz</baz><qux>2.0</qux><qux>3.0</qux></root>"# ,
1252+ )
1253+ . unwrap ( ) ;
1254+ assert_eq ! ( val. foobar, Foobar :: Bar ( 42 ) ) ;
1255+ assert_eq ! ( val. qux, [ 1.0 , 2.0 , 3.0 ] ) ;
1256+ assert_eq ! ( val. baz, "baz" ) ;
1257+ }
1258+
11771259 #[ test]
11781260 fn borrowed_str ( ) {
11791261 let doc = Document :: parse ( "<root><child>foobar</child></root>" ) . unwrap ( ) ;
0 commit comments