C#에서 XmlReader로 Xml 읽기
나는 가능한 한 빨리 아래의 Xml 문서를 읽고 추가 클래스가 각 서브 블록의 읽기를 관리할 수 있도록 노력하고 있습니다.
<ApplicationPool>
<Accounts>
<Account>
<NameOfKin></NameOfKin>
<StatementsAvailable>
<Statement></Statement>
</StatementsAvailable>
</Account>
</Accounts>
</ApplicationPool>
그러나 XmlReader 개체를 사용하여 각 계정을 읽고 "사용 가능한 문"을 읽으려고 합니다.XmlReader를 사용할 것을 제안합니다.각 요소를 읽고 확인한 후 처리?
각 노드를 제대로 처리하기 위해 수업을 분리하는 것을 생각해 보았습니다.따라서 계정에 대한 NameOfKin 및 여러 다른 속성을 읽는 XmlReader 인스턴스를 받아들이는 AccountBase 클래스가 있습니다.그런 다음 저는 명세서를 통해 상호작용하여 다른 학급이 명세서에 대해 스스로 작성하도록 하고 싶었습니다(그리고 이후 IList에 추가).
지금까지 XmlReader를 수행하여 "클래스별" 부분을 수행했습니다.ElementString()을 읽지만 포인터가 StatementAvailable 요소로 이동하도록 지시하고 이 요소를 반복하여 다른 클래스에서 각 속성을 읽도록 하는 방법을 찾을 수 없습니다.
쉬운 것 같네요!
나의 경험은XmlReader
실수로 너무 많이 읽기 쉽기 때문입니다.최대한 빨리 읽고 싶다고 말씀하신 건 알지만, 대신 DOM 모델을 사용해보셨나요?저는 LINQ to XML이 XML 작업을 훨씬 쉽게 해준다는 것을 알았습니다.
문서의 크기가 특히 크다면 다음을 조합할 수 있습니다.XmlReader
를 생성하여 XML에 LINQ를 적용합니다.XElement
로부터XmlReader
각 "외부" 요소를 스트리밍 방식으로 사용할 수 있습니다. 이렇게 하면 대부분의 변환 작업을 LINQ에서 XML로 수행할 수 있지만 한 번에 메모리에 있는 문서의 일부만 필요합니다.다음은 샘플 코드입니다(이 블로그 게시물에서 약간 수정됨).
static IEnumerable<XElement> SimpleStreamAxis(string inputUrl,
string elementName)
{
using (XmlReader reader = XmlReader.Create(inputUrl))
{
reader.MoveToContent();
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
if (reader.Name == elementName)
{
XElement el = XNode.ReadFrom(reader) as XElement;
if (el != null)
{
yield return el;
}
}
}
}
}
}
이전에 StackOverflow 사용자 데이터(엄청난 데이터)를 다른 형식으로 변환하는 데 사용한 적이 있습니다. 매우 잘 작동합니다.
Radarbob에서 편집, Jon에 의해 다시 포맷됨 - 어떤 "너무 멀리 읽기" 문제가 언급되고 있는지 확실하지는 않지만...
이렇게 하면 네스팅을 단순화하고 "너무 멀리 읽기" 문제를 해결할 수 있습니다.
using (XmlReader reader = XmlReader.Create(inputUrl))
{
reader.ReadStartElement("theRootElement");
while (reader.Name == "TheNodeIWant")
{
XElement el = (XElement) XNode.ReadFrom(reader);
}
reader.ReadEndElement();
}
이것은 루프 패턴 동안 고전적인 것을 구현하기 때문에 "너무 멀리 읽기" 문제를 해결합니다.
initial read;
(while "we're not at the end") {
do stuff;
read;
}
3년 후, 아마도 WebApi와 xml 데이터에 대한 새로운 강조와 함께, 저는 이 질문을 접하게 되었습니다.코드적으로 나는 낙하산 없이 스키트를 따라 비행기 밖으로 나가는 경향이 있고, 그의 초기 코드가 MS Xml 팀 기사와 Large Xml Docs의 BOL Streaming Transform의 예시에 의해 이중으로 결합된 것을 볼 때, 나는 다른 코멘트들, 특히 'pbz'로부터 매우 빠르게 간과했습니다. 그들은 당신이 같은 el을 가지고 있다면 그것을 지적했습니다.이름별 요소가 연속적으로 나열됩니다. 이중 읽기로 인해 나머지 요소는 모두 건너뜁니다.그리고 실제로 BOL과 MS 블로그 기사는 모두 대상 요소가 2단계보다 더 깊게 중첩된 소스 문서를 파싱하고 있어 이러한 부작용을 은폐하고 있었습니다.
다른 답변들은 이 문제를 해결합니다.나는 단지 지금까지 잘 작동하는 것처럼 보이는 조금 더 간단한 개정판을 제공하고 싶었을 뿐이며, xml이 uri뿐만 아니라 다른 소스에서 온 것일 수도 있기 때문에 확장판은 사용자가 관리하는 xmlReader에서 작동합니다.한 가지 가정은 리더가 초기 상태에 있다는 것입니다. 그렇지 않으면 첫 번째 'Read()'가 원하는 노드를 지나갈 수 있기 때문에 그렇지 않을 경우 첫 번째 'Read()'가 원하는 노드를 지나갈 수 있습니다.
public static IEnumerable<XElement> ElementsNamed(this XmlReader reader, string elementName)
{
reader.MoveToContent(); // will not advance reader if already on a content node; if successful, ReadState is Interactive
reader.Read(); // this is needed, even with MoveToContent and ReadState.Interactive
while(!reader.EOF && reader.ReadState == ReadState.Interactive)
{
// corrected for bug noted by Wes below...
if(reader.NodeType == XmlNodeType.Element && reader.Name.Equals(elementName))
{
// this advances the reader...so it's either XNode.ReadFrom() or reader.Read(), but not both
var matchedElement = XNode.ReadFrom(reader) as XElement;
if(matchedElement != null)
yield return matchedElement;
}
else
reader.Read();
}
}
우리는 항상 이런 종류의 XML 파싱을 합니다.핵심은 구문 분석 방법이 판독기를 종료 상태로 둘 위치를 정의하는 것입니다.처음 읽은 요소 뒤에 있는 다음 요소에 항상 판독기를 두면 XML 스트림에서 안전하고 예측 가능하게 판독할 수 있습니다.그러면 리더가 현재 색인을 작성하고 있는 경우<Account>
분석 후 element를 . reader는에다다을t에,가xe,</Accounts>
클로징 태그
구문 분석 코드는 다음과 같습니다.
public class Account
{
string _accountId;
string _nameOfKin;
Statements _statmentsAvailable;
public void ReadFromXml( XmlReader reader )
{
reader.MoveToContent();
// Read node attributes
_accountId = reader.GetAttribute( "accountId" );
...
if( reader.IsEmptyElement ) { reader.Read(); return; }
reader.Read();
while( ! reader.EOF )
{
if( reader.IsStartElement() )
{
switch( reader.Name )
{
// Read element for a property of this class
case "NameOfKin":
_nameOfKin = reader.ReadElementContentAsString();
break;
// Starting sub-list
case "StatementsAvailable":
_statementsAvailable = new Statements();
_statementsAvailable.Read( reader );
break;
default:
reader.Skip();
}
}
else
{
reader.Read();
break;
}
}
}
}
Statements
에서 .<StatementsAvailable>
마디를
public class Statements
{
List<Statement> _statements = new List<Statement>();
public void ReadFromXml( XmlReader reader )
{
reader.MoveToContent();
if( reader.IsEmptyElement ) { reader.Read(); return; }
reader.Read();
while( ! reader.EOF )
{
if( reader.IsStartElement() )
{
if( reader.Name == "Statement" )
{
var statement = new Statement();
statement.ReadFromXml( reader );
_statements.Add( statement );
}
else
{
reader.Skip();
}
}
else
{
reader.Read();
break;
}
}
}
}
Statement
은 매우 입니다.
public class Statement
{
string _satementId;
public void ReadFromXml( XmlReader reader )
{
reader.MoveToContent();
// Read noe attributes
_statementId = reader.GetAttribute( "statementId" );
...
if( reader.IsEmptyElement ) { reader.Read(); return; }
reader.Read();
while( ! reader.EOF )
{
....same basic loop
}
}
}
개체의 경우 의 ,ReadSubtree()
하위 개체로 제한된 xml-reader를 제공합니다. 하지만 저는 당신이 이것을 어렵게 하고 있다고 생각합니다.비정상적이거나 예측할 수 없는 xml을 처리하기 위한 매우 구체적인 요구 사항이 없는 경우 를 사용합니다.XmlSerializer
(아마도 와 결합되어 있을 것입니다.sgen.exe
당신이 정말 원한다면요)
XmlReader
◦ 대비:
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
public class ApplicationPool {
private readonly List<Account> accounts = new List<Account>();
public List<Account> Accounts {get{return accounts;}}
}
public class Account {
public string NameOfKin {get;set;}
private readonly List<Statement> statements = new List<Statement>();
public List<Statement> StatementsAvailable {get{return statements;}}
}
public class Statement {}
static class Program {
static void Main() {
XmlSerializer ser = new XmlSerializer(typeof(ApplicationPool));
ser.Serialize(Console.Out, new ApplicationPool {
Accounts = { new Account { NameOfKin = "Fred",
StatementsAvailable = { new Statement {}, new Statement {}}}}
});
}
}
다음 예제에서는 스트림을 탐색하여 현재 노드 유형을 확인한 다음 XmlWriter를 사용하여 XmlReader 콘텐츠를 출력합니다.
StringBuilder output = new StringBuilder();
String xmlString =
@"<?xml version='1.0'?>
<!-- This is a sample XML document -->
<Items>
<Item>test with a child element <more/> stuff</Item>
</Items>";
// Create an XmlReader
using (XmlReader reader = XmlReader.Create(new StringReader(xmlString)))
{
XmlWriterSettings ws = new XmlWriterSettings();
ws.Indent = true;
using (XmlWriter writer = XmlWriter.Create(output, ws))
{
// Parse the file and display each of the nodes.
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
writer.WriteStartElement(reader.Name);
break;
case XmlNodeType.Text:
writer.WriteString(reader.Value);
break;
case XmlNodeType.XmlDeclaration:
case XmlNodeType.ProcessingInstruction:
writer.WriteProcessingInstruction(reader.Name, reader.Value);
break;
case XmlNodeType.Comment:
writer.WriteComment(reader.Value);
break;
case XmlNodeType.EndElement:
writer.WriteFullEndElement();
break;
}
}
}
}
OutputTextBlock.Text = output.ToString();
다음 예제에서는 XmlReader 메서드를 사용하여 요소 및 특성의 내용을 읽습니다.
StringBuilder output = new StringBuilder();
String xmlString =
@"<bookstore>
<book genre='autobiography' publicationdate='1981-03-22' ISBN='1-861003-11-0'>
<title>The Autobiography of Benjamin Franklin</title>
<author>
<first-name>Benjamin</first-name>
<last-name>Franklin</last-name>
</author>
<price>8.99</price>
</book>
</bookstore>";
// Create an XmlReader
using (XmlReader reader = XmlReader.Create(new StringReader(xmlString)))
{
reader.ReadToFollowing("book");
reader.MoveToFirstAttribute();
string genre = reader.Value;
output.AppendLine("The genre value: " + genre);
reader.ReadToFollowing("title");
output.AppendLine("Content of the title element: " + reader.ReadElementContentAsString());
}
OutputTextBlock.Text = output.ToString();
XmlDataDocument xmldoc = new XmlDataDocument();
XmlNodeList xmlnode ;
int i = 0;
string str = null;
FileStream fs = new FileStream("product.xml", FileMode.Open, FileAccess.Read);
xmldoc.Load(fs);
xmlnode = xmldoc.GetElementsByTagName("Product");
xmlnode를 루프로 통과하여 데이터를 얻을 수 있습니다...C# XML 판독기
저는 경험이 없어요.하지만 XmlReader는 불필요하다고 생각합니다.그것은 사용하기 매우 어렵습니다.
XElement는 사용하기 아주 쉽습니다.
성능(더 빠른)이 필요한 경우 파일 형식을 변경하고 StreamReader 및 StreamWriter 클래스를 사용해야 합니다.
언급URL : https://stackoverflow.com/questions/2441673/reading-xml-with-xmlreader-in-c-sharp
'programing' 카테고리의 다른 글
NuGet 패키지에 솔루션 수준 항목 추가 (0) | 2023.09.13 |
---|---|
입력을 대문자로 변경 (0) | 2023.09.13 |
XmlNode 값 대 내부 텍스트 (0) | 2023.09.13 |
부트스트랩 3의 툴팁에 줄 바꿈 추가 (0) | 2023.09.13 |
MariaDB 도커 이미지 빌드 실패 (0) | 2023.09.08 |