如何让 XmlReader 读取 C# 中的属性?

How to make an XmlReader read the attributes in C#?

我有一个 XML-Stream,其中包含以下 XML 内容:

<WebError Key="A">
  <Message>B</Message>
  <Parameters>
    <Parameter name="C">D</Parameter>
  </Parameters>
</WebError>

我找不到让 XmlReader 读取 Key 属性的方法,因此 reader.NodeTypeXmlNodeType.Attributereader.LocalName"Key".

这就是我初始化 XmlReader 的方式:

XmlReader.Create(stream, new XmlReaderSettings { CloseInput = true, IgnoreWhitespace = true });

这个 reader 然后通过几个方法级别,直到到达我的解析器函数。

这是我试图让 reader 读取该元素的所有替代代码。从代码中剥离了控制结构,因此您只能看到实际调用的函数。

第一次尝试,通过 MoveToFirstAttribute() 调用移动到属性:

reader.Read(); // true
reader.IsStartElement("WebError"); // true
using (var nodeReader = reader.ReadSubtree()) {
  nodeReader.HasAttributes; // true
  nodeReader.MoveToFirstAttribute(); // false
  nodeReader.Read(); // true
  nodeReader.NodeType; // XmlNodeType.Element
  nodeReader.LocalName; // "WebError"
  using (var subLevelReader = nodeReader.ReadSubtree()) {
  }
  nodeReader.Read(); // false
}

很明显,MoveToFirstAttribute 不会移动 reader。通常用于解析内部 XmlElement 节点的副作用 subLevelReader 现在会获取整个 WebError 节点,并且当 subLevelReader 被释放时,整个 WebError节点被跨过。

第二次尝试,调用 MoveToContent() 并搜索属性:

reader.Read(); // true
reader.IsStartElement("WebError"); // true
using (var nodeReader = reader.ReadSubtree()) {
  nodeReader.MoveToContent(); // XmlNodeType.Element
  nodeReader.LocalName; // "WebError"
  nodeReader.Read(); // true
  nodeReader.NodeType; // XmlNodeType.Element
  nodeReader.LocalName; // "Message"
  ...
}

显然,当我调用 MoveToContent() 时,我已经走得太远了,因为它移到了 WebError 起始标记的末尾。

第三次尝试,调用前读取属性MoveToContent():

reader.Read(); // true
reader.IsStartElement("WebError"); // true
using (var nodeReader = reader.ReadSubtree()) {
  nodeReader.MoveToAttribute("Key"); // false
  nodeReader.MoveToContent(); // XmlNodeType.Element
  nodeReader.LocalName; // "WebError"
  nodeReader.Read(); // true
  nodeReader.NodeType; // XmlNodeType.Element
  nodeReader.LocalName; // "Message"
  ...
}

这也不行。那么,如何到达 WebError@Key 节点?

This question (which unfortunately does not turn up in the search results for "xmlreader c# attribute") contains an answer 让我明白了问题所在:Read() 没有将 reader 定位在属性上。您首先移动到一个元素,然后移动到它的内容,然后移动到它的属性。只有这个命令有效。

事实证明 所有 如果您调用 MoveToContent() before MoveToAttribute("Key"), [=14= 我的方法有效] 或 MoveToFirstAttribute(),但还没有 Read(),因为它读取到 Message 节点。

所以这是实际代码:

while (reader.Read()) {
  if (!reader.IsStartElement("WebError")) { continue; }

  // We found the WebError node
  using (var nodeReader = reader.ReadSubtree()) {
    nodeReader.MoveToContent();

    // Read the attributes
    while (nodeReader.MoveToNextAttribute()) {
      var nodeName = nodeReader.LocalName;
      if (nodeName == "Key") {
        m_Key = nodeReader.Value; // "A"
        break;
      }
    }

    // Read the XML sub nodes
    while (nodeReader.Read()) {
      if (nodeReader.NodeType != XmlNodeType.Element) { continue; }

      using (var subLevelReader = nodeReader.ReadSubtree()) {
        // Parse sub levels of XML (Message, Parameters)
      }
    }
  }
}

最简单的方法是使用ReadToFollowingGetAttribute方法。

reader.ReadToFollowing("WebError");
string keyAttr = reader.GetAttribute("Key");