방법: XmlReader에서 XML 조각 스트림
큰 XML 파일을 처리해야 하는 경우 전체 XML 트리를 메모리에 로드하지 못할 수도 있습니다.이 항목에서는 XmlReader를 사용하여 조각을 스트림하는 방법을 보여 줍니다.
XmlReader를 사용하여 XElement 개체를 읽는 가장 효과적인 방법 중 하나는 사용자 지정 축 메서드를 직접 작성하는 것입니다.일반적으로 축 메서드는 이 항목의 예제에 나와 있는 대로 XElement의 IEnumerable<T>과 같은 컬렉션을 반환합니다.사용자 지정 축 메서드에서는 ReadFrom 메서드를 호출하여 XML 조각을 만든 후 yield return을 사용하여 컬렉션을 반환합니다.이것은 사용자 지정 축 메서드에 지연된 실행 의미를 제공합니다.
XmlReader 개체에서 XML 트리를 만드는 경우 XmlReader가 요소에 배치되어야 합니다.ReadFrom 메서드는 요소의 닫는 태그를 읽을 때까지 반환되지 않습니다.
부분 트리를 만들려는 경우 XmlReader를 인스턴스화하고 XElement 트리로 변환할 노드에 판독기를 배치한 다음 XElement 개체를 만들 수 있습니다.
방법: 헤더 정보에 액세스하여 XML 조각 스트림 항목에는 더 복잡한 문서를 스트림하는 방법에 대한 정보와 예제가 포함되어 있습니다.
방법: 큰 XML 문서의 스트리밍 변환 수행 항목에는 LINQ to XML을 사용하여 작은 메모리 사용 공간을 유지하면서 매우 큰 XML 문서를 변환하는 예제가 포함되어 있습니다.
예
이 예제에서는 사용자 지정 축 메서드를 만듭니다.LINQ 쿼리를 사용하여 이 메서드를 쿼리할 수 있습니다. 사용자 지정 축 메서드 StreamRootChildDoc는 반복되는 Child 요소가 있는 문서를 읽도록 특별히 디자인된 메서드입니다.
[!참고]
다음 예제에서는 C#의 yield return 구문을 사용합니다.Visual Basic에서는 IEnumerable(Of XElement) 인터페이스를 구현하는 클래스를 사용하여 동등한 코드가 제공됩니다.Visual Basic에서 IEnumerable(Of T)을 구현하는 예제는 연습: Visual Basic에서 IEnumerable(Of T) 구현을 참조하십시오.
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 요소가 수백만 있더라도 이 예제에서는 여전히 작은 메모리 공간만 사용할 것입니다.