@@ -215,6 +215,21 @@ where
215215 has_value_field : fields. contains ( & VALUE_KEY ) ,
216216 } )
217217 }
218+
219+ /// Determines if subtree started with the specified event shoould be skipped.
220+ ///
221+ /// Used to map elements with `xsi:nil` attribute set to true to `None` in optional contexts.
222+ ///
223+ /// We need to handle two attributes:
224+ /// - on parent element: <map xsi:nil="true"><foo/></map>
225+ /// - on this element: <map><foo xsi:nil="true"/></map>
226+ ///
227+ /// We check parent element too because `xsi:nil` affects only nested elements of the
228+ /// tag where it is defined. We can map structure with fields mapped to attributes to
229+ /// the `<map>` element and set to `None` all its optional elements.
230+ fn should_skip_subtree ( & self , start : & BytesStart ) -> bool {
231+ self . de . reader . reader . has_nil_attr ( & self . start ) || self . de . reader . reader . has_nil_attr ( start)
232+ }
218233}
219234
220235impl < ' de , ' d , R , E > MapAccess < ' de > for ElementMapAccess < ' de , ' d , R , E >
@@ -540,8 +555,14 @@ where
540555 where
541556 V : Visitor < ' de > ,
542557 {
543- match self . map . de . peek ( ) ? {
558+ // We cannot use result of `peek()` directly because of borrow checker
559+ let _ = self . map . de . peek ( ) ?;
560+ match self . map . de . last_peeked ( ) {
544561 DeEvent :: Text ( t) if t. is_empty ( ) => visitor. visit_none ( ) ,
562+ DeEvent :: Start ( start) if self . map . should_skip_subtree ( start) => {
563+ self . map . de . skip_next_tree ( ) ?;
564+ visitor. visit_none ( )
565+ }
545566 _ => visitor. visit_some ( self ) ,
546567 }
547568 }
0 commit comments