Fix XmlSerializer consuming sibling elements when deserializing empty XmlElement member#126769
Fix XmlSerializer consuming sibling elements when deserializing empty XmlElement member#126769
Conversation
…rectly Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/a1d8fdd4-0c08-49e8-9258-3018c90b29f1 Co-authored-by: StephenMolloy <19562826+StephenMolloy@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Fixes an XmlSerializer deserialization bug where a self-closing/empty element mapped to an XmlElement/XmlNode member could incorrectly consume the next sibling element as its content, causing subsequent members to deserialize as null.
Changes:
- Update
XmlSerializationReader.ReadXmlNode(bool wrapped)to treat wrapped empty elements as having no content (skip and returnnull) rather than advancing into the next sibling. - Add a regression test in
XmlSerializerTests.RuntimeOnly.cscovering non-empty and empty element forms. - Add a new test type
TypeWithXmlElementMemberAndSibling.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/libraries/System.Runtime.Serialization.Xml/tests/SerializationTypes.cs | Adds TypeWithXmlElementMemberAndSibling test type (but see comment about compilation inclusion). |
| src/libraries/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.RuntimeOnly.cs | Adds regression coverage for empty XmlElement member not consuming a sibling. |
| src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReader.cs | Fixes wrapped empty-element handling in ReadXmlNode to avoid consuming siblings. |
|
@copilot is this a regression or a long standing bug? |
|
And shouldn't it still read the empty element in the XmlElement property in this case? |
🤖 Copilot Code Review — PR #126769Note This review was generated by Copilot and should be validated by a human reviewer. Holistic AssessmentMotivation: The bug is real and well-understood. When Approach: The fix adds an Summary: Detailed Findings✅ Correctness — Fix is sound and addresses root causeThe fix correctly identifies the root cause: The
|
There was a problem hiding this comment.
lgtm
The concern about producing a null property instead of an empty property are misplaced. Since this repo is about XmlElement, the property in the deserialized object is expected to be the xml element that was contained within the field being deserialized. In other words, the element that XmlElement represents is not the "Description" element in the test, rather it should be the xml contained within that wrapper. And if nothing is contained within that wrapper, that is the absence of an element. Thus, the XmlElement property is null.
Description
When deserializing a class with an
XmlElementmember followed by other members, a self-closing/empty element (e.g.,<Description/>) caused the serializer to consume the next sibling element as theXmlElement's content, leaving subsequent members null.Root Cause
ReadXmlNode(bool wrapped)called_r.ReadStartElement()without first checkingIsEmptyElement. For an empty element like<Description/>,ReadStartElement()advances the reader past the empty element to the next sibling. The subsequentMoveToContent()+NodeType != EndElementcheck then incorrectly read that sibling as child content.Fix
XmlSerializationReader.ReadXmlNode: AddIsEmptyElementguard beforeReadStartElement()— matching the pattern already used inReadNull(). If empty,Skip()and returnnull.TypeWithXmlElementMemberAndSiblingtoSerializationTypes.csand a[Theory]regression test (Xml_XmlElementMember_EmptyElement_SiblingNotConsumed) covering non-empty, space-before-slash, and compact empty element forms.