如何让 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.NodeType
是 XmlNodeType.Attribute
和 reader.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)
}
}
}
}
最简单的方法是使用ReadToFollowing
和GetAttribute
方法。
reader.ReadToFollowing("WebError");
string keyAttr = reader.GetAttribute("Key");
我有一个 XML-Stream,其中包含以下 XML 内容:
<WebError Key="A">
<Message>B</Message>
<Parameters>
<Parameter name="C">D</Parameter>
</Parameters>
</WebError>
我找不到让 XmlReader
读取 Key
属性的方法,因此 reader.NodeType
是 XmlNodeType.Attribute
和 reader.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)
}
}
}
}
最简单的方法是使用ReadToFollowing
和GetAttribute
方法。
reader.ReadToFollowing("WebError");
string keyAttr = reader.GetAttribute("Key");