因此,我目前对C#XmlReader
的工作方式的理解是,当我将其包装在以下构造中时,它将获取给定的XML文件并逐个节点读取它:
using System.Xml;
using System;
using System.Diagnostics;
...
XmlReaderSettings settings = new XmlReaderSettings();
settings.IgnoreComments = true;
settings.IgnoreWhitespace = true;
settings.IgnoreProcessingInstructions = true;
using (XmlReader reader = XmlReader.Create(path, settings))
{
while (reader.Read())
{
// All reader methods I call here will reference the current node
// until I move the pointer to some further node by calling methods like
// reader.Read(), reader.MoveToContent(), reader.MoveToElement() etc
}
}
为什么以下两个代码片段(在上述构造中)会产生两个截然不同的结果,即使它们都调用相同的方法?
I used this example file for testing.
Debug.WriteLine(new string(' ', reader.Depth * 2) + "<" + reader.NodeType.ToString() + "|" + reader.Name + ">" + reader.ReadString() + "</>");
(摘录1)与(摘要2)
string xmlcontent = reader.ReadString();
string xmlname = reader.Name.ToString();
string xmltype = reader.NodeType.ToString();
int xmldepth = reader.Depth;
Debug.WriteLine(new string(' ', xmldepth * 2) + "<" + xmltype + "|" + xmlname + ">" + xmlcontent + "</>");
摘要1的输出:
<XmlDeclaration|xml></>
<Element|rss></>
<Element|head></>
<Text|>Test Xml File</>
<Element|description>This will test my xml reader</>
<EndElement|head></>
<Element|body></>
<Element|g:id>1QBX23</>
<Element|g:title>Example Title</>
<Element|g:description>Example Description</>
<EndElement|item></>
<Element|item></>
<Text|>2QXB32</>
<Element|g:title>Example Title</>
<Element|g:description>Example Description</>
<EndElement|item></>
<EndElement|body></>
<EndElement|xml></>
<EndElement|rss></>
是的,其格式与我的输出窗口中的格式相同。可以看出,它跳过了某些元素,并为其他一些元素输出了错误的深度。因此,与代码段2不同,NodeType是正确的,该代码段输出:
<XmlDeclaration|xml></>
<Element|xml></>
<Element|title></>
<EndElement|title>Test Xml File</>
<EndElement|description>This will test my xml reader</>
<EndElement|head></>
<Element|item></>
<EndElement|g:id>1QBX23</>
<EndElement|g:title>Example Title</>
<EndElement|g:description>Example Description</>
<EndElement|item></>
<Element|g:id></>
<EndElement|g:id>2QXB32</>
<EndElement|g:title>Example Title</>
<EndElement|g:description>Example Description</>
<EndElement|item></>
<EndElement|body></>
<EndElement|xml></>
<EndElement|rss></>
再一次,深度被弄乱了,但是它不如代码片段1那样重要。它还跳过了某些元素并分配了错误的NodeType。
为什么它不能输出预期的结果?为什么这两个代码片段会产生两个完全不同的深度不同的输出,即节点类型和跳过的节点?我对此表示感谢。我搜寻了很多有关此问题的答案,但似乎我是唯一遇到这些问题的人。我在Visual Studio 2017中将.NET Framework 4.6.2与Asp.net Web窗体一起使用。
首先,您正在使用方法XmlReader.ReadString()
已弃用:
XmlReader.ReadString方法
...以字符串的形式读取元素或文本节点的内容。但是,我们建议您改用
XmlReader.ReadString()
方法,因为它提供了一种更直接的方式来处理此操作。
但是,除了警告我们不要使用该方法外,文档并没有确切说明其实际作用。要确定这一点,我们需要转到ReadElementContentAsString
:
ReadElementContentAsString
此方法执行以下操作:
如果当前节点是一个空元素节点,则返回一个空字符串。
如果当前节点是不为空的元素,请高级阅读器。
如果当前节点是元素的末尾,则返回一个空字符串。
虽然当前节点是文本节点,但是将文本添加到字符串中并高级阅读器。如果当前节点不是文本节点,请立即返回累积的字符串。
因此,我们可以看到此方法旨在提高阅读器。我们还可以看到,对于像reference source这样的混合内容XML,public virtual string ReadString() {
if (this.ReadState != ReadState.Interactive) {
return string.Empty;
}
this.MoveToElement();
if (this.NodeType == XmlNodeType.Element) {
if (this.IsEmptyElement) {
return string.Empty;
}
else if (!this.Read()) {
throw new InvalidOperationException(Res.GetString(Res.Xml_InvalidOperation));
}
if (this.NodeType == XmlNodeType.EndElement) {
return string.Empty;
}
}
string result = string.Empty;
while (IsTextualNode(this.NodeType)) {
result += this.Value;
if (!this.Read()) {
break;
}
}
return result;
}
将仅部分读取<head>text <b>BOLD</b> more text</head>
元素,而使读取器位于ReadString()
上。奇怪的是,为什么Microsoft不赞成使用此方法。
我们还可以看到为什么您的两个摘要功能不同。首先,您需要先获取<head>
和<b>
,然后再调用reader.Depth
并推进阅读器。在第二个步骤中,您将在使阅读器前进之后获得这些属性。
因为您的意图是遍历节点并获取每个节点的值,而不是reader.NodeType
或ReadString()
,所以应该只使用ReadString()
:
获取当前节点的文本值。
因此,已更正的代码应如下所示:
ReadElementContentAsString()
XmlReader.Value
很难使用。您始终需要检查文档以确定给定方法将阅读器放置在什么位置。例如,XmlReader.Value
将阅读器移至元素的末尾,而 string xmlcontent = reader.Value;
string xmlname = reader.Name.ToString();
string xmltype = reader.NodeType.ToString();
int xmldepth = reader.Depth;
Console.WriteLine(new string(' ', xmldepth * 2) + "<" + xmltype + "|" + xmlname + ">" + xmlcontent + "</>");
将阅读器移至元素的末尾。但是作为一般规则,任何名为XmlReader
的方法都会使阅读器更先进,因此您需要在外部XmlReader.ReadElementContentAsString()
循环内使用XmlReader.ReadElementContentAsString()
方法时要小心。演示小提琴XmlReader.ReadSubtree()
。
也许我错了,但是不同的结果适用于不同的情况。一个结果是RSS类型的输出,另一个是XML类型的输出。不同的格式...
查看更多信息: