From 19f88050e2da63227fbd5234a335518c63a858fe Mon Sep 17 00:00:00 2001 From: Linus Hamlin Date: Wed, 18 Feb 2026 16:25:46 +0100 Subject: [PATCH] Log and restore XmlNodeType in XmlNodeReader --- .../src/System/Xml/Dom/XmlNodeReader.cs | 30 +++++++++++-------- .../XmlNodeReaderMoveToAttributeTests.cs | 11 +++++++ 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Dom/XmlNodeReader.cs b/src/libraries/System.Private.Xml/src/System/Xml/Dom/XmlNodeReader.cs index ab4e98aaa85d19..ff82535a4cd241 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Dom/XmlNodeReader.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Dom/XmlNodeReader.cs @@ -40,6 +40,7 @@ internal sealed class XmlNodeReaderNavigator //variables for roll back the moves private int _nLogLevel; private int _nLogAttrInd; + private XmlNodeType _logNodeType; private bool _bLogOnAttrVal; private readonly bool _bCreatedOnAttribute; @@ -73,6 +74,7 @@ public XmlNodeReaderNavigator(XmlNode node) _curNode = node; _logNode = node; XmlNodeType nt = _curNode.NodeType; + _logNodeType = nt; if (nt == XmlNodeType.Attribute) { _elemNode = null; @@ -547,22 +549,24 @@ public int GetDocTypeAttrInd(string name) throw new ArgumentOutOfRangeException(nameof(attributeIndex)); //for other senario, AttributeCount is 0, i has to be out of range } - public void LogMove(int level) + public void LogMove(int level, XmlNodeType nt) { _logNode = _curNode; _nLogLevel = level; _nLogAttrInd = _nAttrInd; + _logNodeType = nt; _logAttrIndex = _attrIndex; _bLogOnAttrVal = _bOnAttrVal; } //The function has to be used in pair with ResetMove when the operation fails after LogMove() is // called because it relies on the values of nOrigLevel, logNav and nOrigAttrInd to be accurate. - public void RollBackMove(ref int level) + public void RollBackMove(ref int level, ref XmlNodeType nt) { _curNode = _logNode; level = _nLogLevel; _nAttrInd = _nLogAttrInd; + nt = _logNodeType; _attrIndex = _logAttrIndex; _bOnAttrVal = _bLogOnAttrVal; } @@ -600,7 +604,7 @@ public void ResetToAttribute(ref int level) public void ResetMove(ref int level, ref XmlNodeType nt) { - LogMove(level); + LogMove(level, nt); if (_bCreatedOnAttribute) return; if (_nAttrInd != -1) @@ -1368,7 +1372,7 @@ public override bool MoveToAttribute(string name) return false; _readerNav.ResetMove(ref _curDepth, ref _nodeType); if (_readerNav.MoveToAttribute(name)) - { //, ref curDepth ) ) { + { _curDepth++; _nodeType = _readerNav.NodeType; if (_bInReadBinary) @@ -1377,7 +1381,7 @@ public override bool MoveToAttribute(string name) } return true; } - _readerNav.RollBackMove(ref _curDepth); + _readerNav.RollBackMove(ref _curDepth, ref _nodeType); return false; } @@ -1389,7 +1393,7 @@ public override bool MoveToAttribute(string name, string? namespaceURI) _readerNav.ResetMove(ref _curDepth, ref _nodeType); string ns = namespaceURI ?? string.Empty; if (_readerNav.MoveToAttribute(name, ns)) - { //, ref curDepth ) ) { + { _curDepth++; _nodeType = _readerNav.NodeType; if (_bInReadBinary) @@ -1398,7 +1402,7 @@ public override bool MoveToAttribute(string name, string? namespaceURI) } return true; } - _readerNav.RollBackMove(ref _curDepth); + _readerNav.RollBackMove(ref _curDepth, ref _nodeType); return false; } @@ -1423,7 +1427,7 @@ public override void MoveToAttribute(int attributeIndex) } catch { - _readerNav.RollBackMove(ref _curDepth); + _readerNav.RollBackMove(ref _curDepth, ref _nodeType); throw; } _curDepth++; @@ -1447,7 +1451,7 @@ public override bool MoveToFirstAttribute() } return true; } - _readerNav.RollBackMove(ref _curDepth); + _readerNav.RollBackMove(ref _curDepth, ref _nodeType); return false; } @@ -1456,7 +1460,7 @@ public override bool MoveToNextAttribute() { if (!IsInReadingStates() || _nodeType == XmlNodeType.EndElement) return false; - _readerNav.LogMove(_curDepth); + _readerNav.LogMove(_curDepth, _nodeType); _readerNav.ResetToAttribute(ref _curDepth); if (_readerNav.MoveToNextAttribute(ref _curDepth)) { @@ -1467,7 +1471,7 @@ public override bool MoveToNextAttribute() } return true; } - _readerNav.RollBackMove(ref _curDepth); + _readerNav.RollBackMove(ref _curDepth, ref _nodeType); return false; } @@ -1476,7 +1480,7 @@ public override bool MoveToElement() { if (!IsInReadingStates()) return false; - _readerNav.LogMove(_curDepth); + _readerNav.LogMove(_curDepth, _nodeType); _readerNav.ResetToAttribute(ref _curDepth); if (_readerNav.MoveToElement()) { @@ -1488,7 +1492,7 @@ public override bool MoveToElement() } return true; } - _readerNav.RollBackMove(ref _curDepth); + _readerNav.RollBackMove(ref _curDepth, ref _nodeType); return false; } diff --git a/src/libraries/System.Private.Xml/tests/XmlNodeReader/System.Xml.XmlNodeReader.Tests/XmlNodeReaderMoveToAttributeTests.cs b/src/libraries/System.Private.Xml/tests/XmlNodeReader/System.Xml.XmlNodeReader.Tests/XmlNodeReaderMoveToAttributeTests.cs index 89e94af1f7a98c..876822e4d9d7d2 100644 --- a/src/libraries/System.Private.Xml/tests/XmlNodeReader/System.Xml.XmlNodeReader.Tests/XmlNodeReaderMoveToAttributeTests.cs +++ b/src/libraries/System.Private.Xml/tests/XmlNodeReader/System.Xml.XmlNodeReader.Tests/XmlNodeReaderMoveToAttributeTests.cs @@ -121,5 +121,16 @@ public void NodeReaderMoveToElementWithSimpleXml() nodeReader.ReadContentAsBase64(new byte[33], 10, 10); Assert.True(nodeReader.MoveToElement()); } + + [Fact] + public void XmlNodeReaderMoveToUnexistedAttribute() + { + string xml = ""; + XmlNodeReader nodeReader = NodeReaderTestHelper.CreateNodeReader(xml); + Assert.True(nodeReader.ReadToDescendant("child")); + Assert.True(nodeReader.MoveToAttribute("attr1")); + Assert.False(nodeReader.MoveToAttribute("attr2")); + nodeReader.ReadStartElement("child"); + } } }