Skip to content

Commit

Permalink
Fixed incorrect logic in XmlReader's example (#43799) (#44054)
Browse files Browse the repository at this point in the history
* Fixed incorrect logic in XmlReader's example (#43799)

* Refactor XML streaming example in C# and VB

* Format XML string for better readability

* Remove unnecessary else statements in XML reader doc

---------

Co-authored-by: Andy (Steve) De George <[email protected]>
  • Loading branch information
scale-tone and adegeo authored Dec 31, 2024
1 parent 0b5b1e3 commit f463647
Showing 1 changed file with 77 additions and 131 deletions.
208 changes: 77 additions & 131 deletions docs/standard/linq/stream-xml-fragments-xmlreader.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,163 +27,109 @@ The article [How to perform streaming transform of large XML documents](perform-
This example creates a custom axis method. You can query it by using a LINQ query. The custom axis method `StreamRootChildDoc` can read a document that has a repeating `Child` element.

```csharp
using System.Xml;
using System.Xml.Linq;

static IEnumerable<XElement> StreamRootChildDoc(StringReader stringReader)
{
using (XmlReader reader = XmlReader.Create(stringReader))
using XmlReader reader = XmlReader.Create(stringReader);

reader.MoveToContent();

// Parse the file and display each of the nodes.
while (true)
{
reader.MoveToContent();
// Parse the file and display each of the nodes.
while (reader.Read())
// If the current node is an element and named "Child"
if (reader.NodeType == XmlNodeType.Element && reader.Name == "Child")
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
if (reader.Name == "Child") {
XElement el = XElement.ReadFrom(reader) as XElement;
if (el != null)
yield return el;
}
break;
}
// Get the current node and advance the reader to the next
if (XNode.ReadFrom(reader) is XElement el)
yield return el;

}
else if (!reader.Read())
break;
}
}

static void Main(string[] args)
{
string markup = @"<Root>
<Child Key=""01"">
<GrandChild>aaa</GrandChild>
</Child>
<Child Key=""02"">
<GrandChild>bbb</GrandChild>
</Child>
<Child Key=""03"">
<GrandChild>ccc</GrandChild>
</Child>
</Root>";

IEnumerable<string> grandChildData =
from el in StreamRootChildDoc(new StringReader(markup))
where (int)el.Attribute("Key") > 1
select (string)el.Element("GrandChild");

foreach (string str in grandChildData) {
Console.WriteLine(str);
}
}
string markup = """
<Root>
<Child Key="01">
<GrandChild>aaa</GrandChild>
</Child>
<Child Key="02">
<GrandChild>bbb</GrandChild>
</Child>
<Child Key="03">
<GrandChild>ccc</GrandChild>
</Child>
</Root>
""";

IEnumerable<string> grandChildData =
from el in StreamRootChildDoc(new StringReader(markup))
where (int)el.Attribute("Key") > 1
select (string)el.Element("GrandChild");

foreach (string str in grandChildData)
Console.WriteLine(str);
```

```vb
Module Module1
Sub Main()
Dim markup = "<Root>" &
" <Child Key=""01"">" &
" <GrandChild>aaa</GrandChild>" &
" </Child>" &
" <Child Key=""02"">" &
" <GrandChild>bbb</GrandChild>" &
" </Child>" &
" <Child Key=""03"">" &
" <GrandChild>ccc</GrandChild>" &
" </Child>" &
"</Root>"

Dim grandChildData =
From el In New StreamRootChildDoc(New IO.StringReader(markup))
Where CInt(el.@Key) > 1
Select el.<GrandChild>.Value

For Each s In grandChildData
Console.WriteLine(s)
Next
End Sub
End Module

Public Class StreamRootChildDoc
Implements IEnumerable(Of XElement)
Imports System.Xml

Private _stringReader As IO.StringReader

Public Sub New(ByVal stringReader As IO.StringReader)
_stringReader = stringReader
End Sub

Public Function GetEnumerator() As IEnumerator(Of XElement) Implements IEnumerable(Of XElement).GetEnumerator
Return New StreamChildEnumerator(_stringReader)
End Function
Module Module1

Public Function GetEnumerator1() As IEnumerator Implements IEnumerable.GetEnumerator
Return Me.GetEnumerator()
End Function
End Class
Public Iterator Function StreamRootChildDoc(stringReader As IO.StringReader) As IEnumerable(Of XElement)
Using reader As XmlReader = XmlReader.Create(stringReader)
reader.MoveToContent()

Public Class StreamChildEnumerator
Implements IEnumerator(Of XElement)
' Parse the file and display each of the nodes.
While True

Private _current As XElement
Private _reader As Xml.XmlReader
Private _stringReader As IO.StringReader
' If the current node is an element and named "Child"
If reader.NodeType = XmlNodeType.Element And reader.Name = "Child" Then

Public Sub New(ByVal stringReader As IO.StringReader)
_stringReader = stringReader
_reader = Xml.XmlReader.Create(_stringReader)
_reader.MoveToContent()
End Sub
' Get the current node and advance the reader to the next
Dim el As XElement = TryCast(XNode.ReadFrom(reader), XElement)

Public ReadOnly Property Current As XElement Implements IEnumerator(Of XElement).Current
Get
Return _current
End Get
End Property

Public ReadOnly Property Current1 As Object Implements IEnumerator.Current
Get
Return Me.Current
End Get
End Property

Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext
While _reader.Read()
Select Case _reader.NodeType
Case Xml.XmlNodeType.Element
Dim el = TryCast(XElement.ReadFrom(_reader), XElement)
If el IsNot Nothing Then
_current = el
Return True
If (el IsNot Nothing) Then
Yield el
End If
End Select
End While

Return False
ElseIf Not reader.Read() Then
Exit While
End If

End While
End Using
End Function

Public Sub Reset() Implements IEnumerator.Reset
_reader = Xml.XmlReader.Create(_stringReader)
_reader.MoveToContent()
End Sub
Sub Main()

#Region "IDisposable Support"
Dim markup = "<Root>
<Child Key=""01"">
<GrandChild>aaa</GrandChild>
</Child>
<Child Key=""02"">
<GrandChild>bbb</GrandChild>
</Child>
<Child Key=""03"">
<GrandChild>ccc</GrandChild>
</Child>
</Root>"

Private disposedValue As Boolean ' To detect redundant calls
Dim grandChildData =
From el In StreamRootChildDoc(New IO.StringReader(markup))
Where CInt(el.@Key) > 1
Select el.<GrandChild>.Value

' IDisposable
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
_reader.Close()
End If
End If
Me.disposedValue = True
End Sub
For Each s In grandChildData
Console.WriteLine(s)
Next

Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region

End Class
End Module
```

This example produces the following output:
Expand Down

0 comments on commit f463647

Please sign in to comment.