我正在尝试尽可能快地阅读以下Xml文档,并让其他类管理每个子块的读取.
<ApplicationPool>
<Accounts>
<Account>
<NameOfKin></NameOfKin>
<StatementsAvailable>
<Statement></Statement>
</StatementsAvailable>
</Account>
</Accounts>
</ApplicationPool>
Run Code Online (Sandbox Code Playgroud)
但是,我正在尝试使用XmlReader对象来读取每个帐户,然后使用"StatementsAvailable".你建议使用XmlReader.Read并检查每个元素并处理它吗?
我想过分离我的类来正确处理每个节点.所以这是一个AccountBase类,它接受一个XmlReader实例,该实例读取NameOfKin和该帐户的其他几个属性.然后我想要通过语句进行交互,让另一个类填写有关语句(并随后将其添加到IList).
到目前为止,我通过执行XmlReader.ReadElementString()来完成"每个类"部分,但是我无法训练如何告诉指针移动到StatementsAvailable元素并让我遍历它们并让另一个类读取每个proeprties .
听起来很简单!
Jon*_*eet 155
我的经验XmlReader是,很容易意外地阅读太多.我知道你说你想尽快读它,但是你尝试过使用DOM模型吗?我发现LINQ to XML使XML的工作变得更加容易.
如果你的文件是特别巨大的,你可以结合XmlReader通过创建和LINQ to XML XElement从XmlReader每个以流的方式你的"外"的元素:这可以让你做的大部分转换工作的LINQ to 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;
}
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
我之前使用它将StackOverflow用户数据(这是巨大的)转换为另一种格式 - 它运行良好.
来自雷达宝宝的编辑,由Jon重新格式化 - 虽然目前尚不清楚哪个"读得太远"的问题被提及......
这应该简化嵌套并处理"读得太远"的问题.
using (XmlReader reader = XmlReader.Create(inputUrl))
{
reader.ReadStartElement("theRootElement");
while (reader.Name == "TheNodeIWant")
{
XElement el = (XElement) XNode.ReadFrom(reader);
}
reader.ReadEndElement();
}
Run Code Online (Sandbox Code Playgroud)
这会解决"读取太远"的问题,因为它实现了经典的while循环模式:
initial read;
(while "we're not at the end") {
do stuff;
read;
}
Run Code Online (Sandbox Code Playgroud)
mdi*_*bio 28
三年后,也许重新强调了WebApi和xml数据,我遇到了这个问题.从代码方面来说,我倾向于在没有降落伞的情况下从飞机上走出Skeet,并且看到他的初始代码被MS Xml团队文章以及BOL Streaming Transform of Large Xml Docs中的一个例子双重破坏,我很快就忽略了其他评论,特别是来自'pbz',他指出,如果连续按名称使用相同的元素,则由于双重读取而跳过其他每个元素.事实上,BOL和MS的博客文章都解析了源文档,其目标元素嵌套比第二级更深,掩盖了这种副作用.
其他答案解决了这个问题.我只是想提供一个稍微简单的修订版本,到目前为止似乎运行良好,并考虑到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();
}
}
Run Code Online (Sandbox Code Playgroud)
Pau*_*der 17
我们一直在进行这种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;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
该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;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
这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
}
}
}
Run Code Online (Sandbox Code Playgroud)
对于子对象,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 {}}}}
});
}
}
Run Code Online (Sandbox Code Playgroud)
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();
Run Code Online (Sandbox Code Playgroud)
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();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
323144 次 |
| 最近记录: |