XmlReader.Read()和XmlReader.ReadStartElement()之间不一致



试图理解XmlReader.Read()XmlReader.ReadStartElement()之间的"不一致"。在下面的reader1中,一切都是意料之中的,即需要3次读取才能读取整个xml;更重要的是,当第一次读取即读取<firstname>时,reader1.Value为空。第二个读数reader1.Value是文本节点值。

但在reader2中,我期望相同的读取顺序,因为据我所知,ReadStartElement()内部调用Read(),它应该只读取一个XmlNodeType,例如这里的<firstname>。这几乎就像我们可以用一个调用来替换ReadStartElement("firstname"),以检查它是否是名为firstname的起始元素和对Read()的调用。为什么reader2.ValueReadStartElement("firstname")之后不为空?我最初是在@lesscode的问题下问这个问题的,他的解释是,根据msdn,ReadStartElement()将把XmlReader提前到下一个节点,reader.Value是当前节点的值。但如果是这样的话,Read()ReadStartElement()之间不是不一致吗?因为使用Read()之后必须检索Value,而使用ReadStartElement()之前必须检索Value

var simpleElement = "<firstname>Jim</firstname>";
using (var reader1 = XmlReader.Create(new StringReader(simpleElement)))
{
var i = 1;
while (reader1.Read())
{
WriteLine($"i = {i++}; value = {reader1.Value}");
}           
}
using (var reader2 = XmlReader.Create(new StringReader(simpleElement)))
{
// this internally calls Read() which should have ONLY read the 'firstname' start element node. 
reader2.ReadStartElement("firstname"); 
// prints Jim; but why??? The text node has NOT been read yet!
WriteLine(reader2.Value); 
reader2.Read(); //WHY needs this line given text node has been read already?
reader2.ReadEndElement(); 
}

您可以查看Github上的源代码:XmlReader.cs.

正如您在下面看到的,这些方法的行为不同:

// Checks that the current node is an element and advances the reader to the next node.
public virtual void ReadStartElement() {
if (MoveToContent() != XmlNodeType.Element) {
throw new XmlException(Res.Xml_InvalidNodeType, this.NodeType.ToString(), this as IXmlLineInfo);
}
Read();
}
// Checks whether the current node is a content (non-whitespace text, CDATA, Element, EndElement, EntityReference
// or EndEntity) node. If the node is not a content node, then the method skips ahead to the next content node or 
// end of file. Skips over nodes of type ProcessingInstruction, DocumentType, Comment, Whitespace and SignificantWhitespace.
public virtual  XmlNodeType  MoveToContent() {
do {
switch (this.NodeType) {
case XmlNodeType.Attribute:
MoveToElement();
goto case XmlNodeType.Element;
case XmlNodeType.Element:
case XmlNodeType.EndElement:
case XmlNodeType.CDATA:
case XmlNodeType.Text:
case XmlNodeType.EntityReference:
case XmlNodeType.EndEntity:
return this.NodeType;
}
} while (Read());
return this.NodeType;
}

因此,ReadStartElement方法,调用MoveToContent,可以进行多次Read调用,以便找到内容节点。此后,ReadStartElement读取当前启动元件。

最新更新