Во-первых, вы используете метод XmlReader.ReadString()
, который устарел :
Метод XmlReader.ReadString
... читает содержимое элемента или текстового узла в виде строки. Однако мы рекомендуем вместо этого использовать метод ReadElementContentAsString
, поскольку он обеспечивает более простой способ выполнения этой операции.
Однако, помимо предупреждения нас о методе,документация точно не определяет, что на самом деле делает. Чтобы определить это, нам нужно перейти к эталонному источнику :
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;
}
Этот метод выполняет следующие действия:
Если текущий узелявляется пустым элементом узла, возвращает пустую строку.
Если текущий узел является непустым элементом, продвигает читателя .
Если текущий текущий узел является концом элемента, верните пустую строку.
Пока текущий узел является текстовым узлом, добавьте текст встрока и продвигают читателя . Как только текущий узел не является текстовым узлом, верните накопленную строку.
Таким образом, мы видим, что этот метод предназначен для продвижения читателя . Мы также можем видеть, что, учитывая смешанный контент XML, такой как <head>text <b>BOLD</b> more text</head>
, ReadString()
будет только частично читать элемент <head>
, оставляя читателя в положении <b>
. Вероятно, из-за этой странности Microsoft отказалась от этого метода.
Мы также видим, почему ваши два фрагмента функционируют по-разному. Во-первых, вы получаете reader.Depth
и reader.NodeType
перед вызовом ReadString()
и продвижением читателя. Во втором вы получите эти свойства после продвижения читателя.
Поскольку ваша цель состоит в том, чтобы перебирать узлы и получать значение каждого, а не ReadString()
или ReadElementContentAsString()
, вам следует просто использовать 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.ReadSubtree()
перемещает считыватель к концуэлемента. Но, как правило, любой метод с именем Read
продвигает читателя, поэтому вы должны быть осторожны, используя метод Read
внутри внешнего цикла while (reader.Read())
.
Демонстрационная скрипка здесь.