C#XmlReader读取XML错误且基于我调用读取器方法的方式而有所不同

问题描述 投票:2回答:1

因此,我目前对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窗体一起使用。

c# xml parsing xml-parsing xmlreader
1个回答
2
投票

首先,您正在使用方法XmlReader.ReadString() 已弃用

XmlReader.ReadString方法

...以字符串的形式读取元素或文本节点的内容。但是,我们建议您改用XmlReader.ReadString()方法,因为它提供了一种更直接的方式来处理此操作。

但是,除了警告我们不要使用该方法外,文档并没有确切说明其实际作用。要确定这一点,我们需要转到ReadElementContentAsString

ReadElementContentAsString

此方法执行以下操作:

  1. 如果当前节点是一个空元素节点,则返回一个空字符串。

  2. 如果当前节点是不为空的元素,请高级阅读器

    如果当前节点是元素的末尾,则返回一个空字符串。

  3. 虽然当前节点是文本节点,但是将文本添加到字符串中并高级阅读器。如果当前节点不是文本节点,请立即返回累积的字符串。

因此,我们可以看到此方法旨在提高阅读器。我们还可以看到,对于像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.NodeTypeReadString(),所以应该只使用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()


-1
投票

也许我错了,但是不同的结果适用于不同的情况。一个结果是RSS类型的输出,另一个是XML类型的输出。不同的格式...

查看更多信息:

© www.soinside.com 2019 - 2024. All rights reserved.