Câu hỏi Đọc Xml với XmlReader trong C #
Tôi đang cố đọc tài liệu Xml sau đây nhanh nhất có thể và để các lớp bổ sung quản lý việc đọc từng khối phụ.
<ApplicationPool>
<Accounts>
<Account>
<NameOfKin></NameOfKin>
<StatementsAvailable>
<Statement></Statement>
</StatementsAvailable>
</Account>
</Accounts>
</ApplicationPool>
Tuy nhiên, tôi đang cố gắng sử dụng đối tượng XmlReader để đọc từng Tài khoản và sau đó là "Bảng sao kê có sẵn". Bạn có đề nghị sử dụng XmlReader.Read và kiểm tra từng phần tử và xử lý nó?
Tôi đã nghĩ đến việc phân tách các lớp của tôi để xử lý từng nút một cách chính xác. Vì vậy, có một lớp AccountBase chấp nhận một cá thể XmlReader đọc NameOfKin và một số thuộc tính khác về tài khoản. Sau đó, tôi đã muốn giao tiếp thông qua các báo cáo và để cho một lớp khác tự điền vào Bản Tuyên Bố (và sau đó thêm nó vào một IList).
Vì vậy, đến nay tôi có phần "mỗi lớp" được thực hiện bằng cách làm XmlReader.ReadElementString () nhưng tôi không thể tập luyện làm thế nào để nói cho con trỏ để di chuyển đến phần tử StatementsAvailable và cho phép tôi lặp qua chúng và để cho một lớp khác đọc từng trong số các proeprties đó .
Nghe có vẻ dễ dàng!
76
2018-03-14 09:06
gốc
Các câu trả lời:
Kinh nghiệm của tôi về XmlReader
là rất dễ dàng để vô tình đọc quá nhiều. Tôi biết bạn đã nói bạn muốn đọc nó càng nhanh càng tốt, nhưng có bạn đã thử sử dụng mô hình DOM thay thế? Tôi đã thấy rằng LINQ to XML làm cho XML hoạt động được nhiều nhiều dễ dàng hơn.
Nếu tài liệu của bạn đặc biệt lớn, bạn có thể kết hợp XmlReader
và LINQ to XML bằng cách tạo XElement
từ một XmlReader
cho mỗi phần tử "bên ngoài" của bạn theo cách trực tuyến: điều này cho phép bạn thực hiện hầu hết công việc chuyển đổi trong LINQ thành XML, nhưng vẫn chỉ cần một phần nhỏ tài liệu trong bộ nhớ cùng một lúc. Dưới đây là một số mã mẫu (được điều chỉnh một chút từ bài đăng trên blog này):
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;
}
}
}
}
}
}
Tôi đã sử dụng điều này để chuyển đổi dữ liệu người dùng StackOverflow (rất lớn) thành một định dạng khác trước đây - nó hoạt động rất tốt.
EDIT từ radarbob, định dạng lại bởi Jon - mặc dù nó không phải là khá rõ ràng mà "đọc quá xa" vấn đề đang được giới thiệu ...
Điều này sẽ đơn giản hóa việc lồng ghép và xử lý vấn đề "đọc quá xa".
using (XmlReader reader = XmlReader.Create(inputUrl))
{
reader.ReadStartElement("theRootElement");
while (reader.Name == "TheNodeIWant")
{
XElement el = (XElement) XNode.ReadFrom(reader);
}
reader.ReadEndElement();
}
Thao tác này sẽ xử lý vấn đề "đọc quá xa" vì nó thực hiện mẫu vòng lặp cổ điển trong khi:
initial read;
(while "we're not at the end") {
do stuff;
read;
}
138
2018-03-14 09:17
Ba năm sau, có lẽ với sự nhấn mạnh mới về dữ liệu WebApi và xml, tôi đã xem qua câu hỏi này. Kể từ khi codewise tôi nghiêng theo Skeet ra khỏi một chiếc máy bay mà không có một chiếc dù, và nhìn thấy mã ban đầu của ông gấp đôi corraborated bởi bài viết đội MS Xml cũng như một ví dụ trong BOL Chuyển đổi trực tuyến Tài liệu Xml Lớn, Tôi rất nhanh chóng bỏ qua các nhận xét khác, đặc biệt nhất từ 'pbz', người đã chỉ ra rằng nếu bạn có cùng các yếu tố theo tên liên tiếp, mọi người khác bị bỏ qua vì đọc đôi. Và trên thực tế, các bài viết trên blog BOL và MS đều phân tích cú pháp các tài liệu nguồn với các phần tử mục tiêu được lồng sâu hơn mức thứ hai, che dấu hiệu ứng phụ này.
Các câu trả lời khác giải quyết vấn đề này. Tôi chỉ muốn cung cấp một bản sửa đổi hơi đơn giản mà có vẻ hoạt động tốt cho đến nay, và đưa vào tài khoản rằng xml có thể đến từ các nguồn khác nhau, không chỉ là một uri, và do đó phần mở rộng hoạt động trên người dùng quản lý XmlReader. Giả định một là người đọc đang ở trạng thái ban đầu của nó, vì nếu không thì 'Read ()' đầu tiên có thể tiến qua một nút mong muốn:
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();
}
}
25
2017-10-03 17:38
Chúng tôi thực hiện loại phân tích cú pháp XML này mọi lúc. Điều quan trọng là xác định nơi phương pháp phân tích cú pháp sẽ rời khỏi trình đọc khi thoát. Nếu bạn luôn để người đọc trên phần tử tiếp theo sau phần tử được đọc lần đầu thì bạn có thể đọc một cách an toàn và dự đoán được trong luồng XML. Vì vậy, nếu người đọc hiện đang lập chỉ mục <Account>
phần tử, sau khi phân tích cú pháp người đọc sẽ lập chỉ mục </Accounts>
đóng thẻ.
Mã phân tích trông giống như sau:
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;
}
}
}
}
Các Statements
lớp học chỉ đọc trong <StatementsAvailable>
nút
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;
}
}
}
}
Các Statement
lớp học sẽ trông rất giống nhau
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
}
}
}
15
2018-03-14 09:41
Đối với các đối tượng phụ, ReadSubtree()
cung cấp cho bạn một trình đọc xml giới hạn đối với các đối tượng con, nhưng tôi có thật không nghĩ rằng bạn đang làm điều này một cách khó khăn. Trừ khi bạn có vô cùng đặc biệt các yêu cầu để xử lý xml không bình thường / không thể đạt được, sử dụng XmlSerializer
(có lẽ kết hợp với sgen.exe
nếu bạn thực sự muốn).
XmlReader
là ... khó khăn. Tương phản với:
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 {}}}}
});
}
}
5
2018-03-14 09:15
Ví dụ sau điều hướng qua luồng để xác định loại nút hiện tại và sau đó sử dụng XmlWriter để xuất nội dung 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();
Ví dụ sau sử dụng các phương thức XmlReader để đọc nội dung của các phần tử và các thuộc tính.
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();
1
2018-04-14 07:49
Tôi không có kinh nghiệm. Nhưng tôi nghĩ XmlReader là không cần thiết.
Nó rất khó sử dụng.
XElement rất dễ sử dụng.
Nếu bạn cần hiệu suất (nhanh hơn), bạn phải thay đổi định dạng tệp và sử dụng các lớp StreamReader và StreamWriter.
0
2017-12-28 09:08
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");
Bạn có thể lặp qua xmlnode và lấy dữ liệu ...... C # XML Reader
-1
2018-04-03 05:52