C #에서 XmlReader로 Xml 읽기
가능한 한 빨리 다음 Xml 문서를 읽고 추가 클래스가 각 하위 블록의 읽기를 관리하도록하려고합니다.
<ApplicationPool>
<Accounts>
<Account>
<NameOfKin></NameOfKin>
<StatementsAvailable>
<Statement></Statement>
</StatementsAvailable>
</Account>
</Accounts>
</ApplicationPool>
그러나 XmlReader 개체를 사용하여 각 계정을 읽은 후 "StatementsAvailable"을 읽으려고합니다. XmlReader.Read를 사용하여 각 요소를 확인하고 처리 할 것을 제안합니까?
각 노드를 올바르게 처리하기 위해 클래스를 분리하는 것을 생각했습니다. 따라서 NameOfKin 및 계정에 대한 여러 다른 속성을 읽는 XmlReader 인스턴스를 허용하는 AccountBase 클래스가 있습니다. 그런 다음 Statements를 통해 상호 작용하고 다른 클래스가 Statement에 대해 자체적으로 채우고 IList에 추가하고 싶었습니다.
지금까지 XmlReader.ReadElementString ()을 수행하여 "클래스 별"부분을 수행했지만 포인터가 StatementsAvailable 요소로 이동하도록 지시하고이를 반복하여 다른 클래스가 각 속성을 읽도록하는 방법을 연습 할 수 없습니다. .
쉽게 들리 네요!
내 경험은 XmlReader
실수로 너무 많이 읽는 것이 매우 쉽다는 것입니다. 난 당신이 가능한 한 빨리 그것을 읽고 싶은 말한 알아,하지만 당신은 시도 대신 DOM 모델을 사용하고 계십니까? LINQ to XML을 사용하면 XML 작업이 훨씬 쉬워진다 는 것을 알게되었습니다 .
문서가 특히 큰 경우 스트리밍 방식으로 각 "외부"요소에 대한 from XmlReader
을 만들어 결합 하고 LINQ to XML을 사용할 수 있습니다. 이렇게하면 LINQ to XML에서 대부분의 변환 작업을 수행 할 수 있지만 여전히 필요합니다. 한 번에 문서의 작은 부분을 메모리에 저장합니다. 다음은 몇 가지 샘플 코드입니다 ( 이 블로그 게시물 에서 약간 수정 됨 ).XElement
XmlReader
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();
}
이것은 고전적인 while 루프 패턴을 구현하기 때문에 "너무 많이 읽음"문제를 처리합니다.
initial read;
(while "we're not at the end") {
do stuff;
read;
}
3 년 후 아마도 WebApi와 xml 데이터에 대한 새로운 강조와 함께 저는이 질문을 발견했습니다. 코드 측면에서 나는 낙하산없이 비행기에서 Skeet을 따라 가고, 그의 초기 코드가 MS Xml 팀 기사와 BOL Streaming Transform of Large Xml Docs 의 예제에 의해 두 배로 통합되는 것을 보는 경향이 있기 때문에 다른 댓글을 매우 빠르게 간과했습니다. , 가장 구체적으로 말한 'pbz'는 이름별로 동일한 요소가 연속적으로 있으면 이중 읽기로 인해 다른 요소는 모두 건너 뛴다 고 지적했습니다. 실제로 BOL과 MS 블로그 기사는 둘 다 대상 요소가 2 단계보다 더 깊게 중첩 된 소스 문서를 구문 분석하여 이러한 부작용을 마스킹했습니다.
다른 답변은이 문제를 해결합니다. 지금까지 잘 작동하는 것처럼 보이는 약간 더 간단한 개정판을 제공하고 싶었고 xml이 uri가 아닌 다른 소스에서 올 수 있으므로 확장이 사용자 관리 XmlReader에서 작동한다는 점을 고려했습니다. 한 가지 가정은 독자가 초기 상태에 있다는 것입니다. 그렇지 않으면 첫 번째 '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>
요소를 인덱싱하고있는 경우 파싱 후 판독기는 </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 판독기를 제공합니다,하지만 난 정말 이 어려운 방법을하고 있다고 생각합니다. 당신이하지 않는 매우 구체적인 특이한 / 예측 불가능한 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");
You can loop through xmlnode and get the data...... C# XML Reader
I am not experiented .But i think XmlReader is unnecessary. It is very hard to use.
XElement is very easy to use.
If you need performance ( faster ) you must change file format and use StreamReader and StreamWriter classes.
참고URL : https://stackoverflow.com/questions/2441673/reading-xml-with-xmlreader-in-c-sharp
'programing tip' 카테고리의 다른 글
std :: cout 조작 후 상태 복원 (0) | 2020.09.05 |
---|---|
원격 JMX 연결 (0) | 2020.09.05 |
OrderBy 파이프 문제 (0) | 2020.09.05 |
IEqualityComparer를 사용하는 방법 (0) | 2020.09.05 |
Notepad ++에서 플러그인 관리자를 보는 방법 (0) | 2020.09.05 |