XmlReader에서 XML 조각을 스트리밍하는 방법(LINQ to XML)
큰 XML 파일을 처리해야 하는 경우 전체 XML 트리를 메모리에 로드하는 것이 가능하지 않을 수 있습니다. 이 문서에서는 C# 및 Visual Basic에서 XmlReader를 사용하여 조각을 스트리밍하는 방법을 보여 줍니다.
XmlReader를 사용하여 XElement 개체를 읽는 가장 효과적인 방법 중 하나는 사용자 지정 축 메서드를 직접 작성하는 것입니다. 일반적으로 축 메서드는 이 문서의 예에 나와 있는 대로 IEnumerable<T>의 XElement와 같은 컬렉션을 반환합니다. 사용자 지정 축 메서드에서는 ReadFrom 메서드를 호출하여 XML 조각을 만든 후 yield return
을 사용하여 컬렉션을 반환합니다. 이것은 사용자 지정 축 메서드에 지연된 실행 의미를 제공합니다.
XmlReader 개체에서 XML 트리를 만드는 경우 XmlReader가 요소에 배치되어야 합니다. ReadFrom 메서드는 요소의 닫기 태그를 읽을 때까지 반환되지 않습니다.
부분 트리를 만들려는 경우 XmlReader를 인스턴스화하고 XElement 트리로 변환할 노드에 판독기를 배치한 다음 XElement 개체를 만들 수 있습니다.
헤더 정보에 액세스하여 XML 조각을 스트리밍하는 방법 문서에는 더 복잡한 문서 스트리밍에 대한 정보가 포함되어 있습니다.
큰 XML 문서의 스트리밍 변환을 수행하는 방법 문서에는 LINQ to XML을 사용하여 작은 메모리 공간을 유지하면서 매우 큰 XML 문서를 변환하는 예가 포함되어 있습니다.
예: 사용자 지정 축 메서드 만들기
이 예제에서는 사용자 지정 축 메서드를 만듭니다. LINQ 쿼리를 사용하여 이 메서드를 쿼리할 수 있습니다. 사용자 지정 축 메서드 StreamRootChildDoc
는 반복되는 Child
요소가 있는 문서를 읽을 수 있습니다.
static IEnumerable<XElement> StreamRootChildDoc(StringReader stringReader)
{
using (XmlReader reader = XmlReader.Create(stringReader))
{
reader.MoveToContent();
// Parse the file and display each of the nodes.
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
if (reader.Name == "Child") {
XElement el = XElement.ReadFrom(reader) as XElement;
if (el != null)
yield return el;
}
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);
}
}
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)
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
Public Function GetEnumerator1() As IEnumerator Implements IEnumerable.GetEnumerator
Return Me.GetEnumerator()
End Function
End Class
Public Class StreamChildEnumerator
Implements IEnumerator(Of XElement)
Private _current As XElement
Private _reader As Xml.XmlReader
Private _stringReader As IO.StringReader
Public Sub New(ByVal stringReader As IO.StringReader)
_stringReader = stringReader
_reader = Xml.XmlReader.Create(_stringReader)
_reader.MoveToContent()
End Sub
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
End If
End Select
End While
Return False
End Function
Public Sub Reset() Implements IEnumerator.Reset
_reader = Xml.XmlReader.Create(_stringReader)
_reader.MoveToContent()
End Sub
#Region "IDisposable Support"
Private disposedValue As Boolean ' To detect redundant calls
' 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
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region
End Class
이 예제는 다음과 같은 출력을 생성합니다.
bbb
ccc
이 예에 사용된 기술은 수백만 개의 Child
요소에 대해서도 작은 메모리 공간을 유지합니다.
참고 항목
.NET
피드백
https://aka.ms/ContentUserFeedback
출시 예정: 2024년 내내 콘텐츠에 대한 피드백 메커니즘으로 GitHub 문제를 단계적으로 폐지하고 이를 새로운 피드백 시스템으로 바꿀 예정입니다. 자세한 내용은 다음을 참조하세요.다음에 대한 사용자 의견 제출 및 보기