如何在不向前移动XmlReader的情况下读取内容?

13

我有这样的情况:

while (reader.Read())
{
    if (reader.NodeType == XmlNodeType.Element && reader.Name == itemElementName)
    {
        XElement item = null;
        try
        {
            item = XElement.ReadFrom(reader) as XElement;
        }
        catch (XmlException ex)
        {
           //log line number and stuff from XmlException class  
        }
    }
}
在上述循环中,我正在将某个节点(itemElementName)转换为XElement。
有些节点将是良好的XML,并将进入XElement,但有些则不会。
在CATCH中,我不仅想捕获标准的XmlException内容...我还想捕获当前Xml的摘录和字符串。
然而,如果在将节点传递给XElement之前对其进行任何类型的读取操作,它会将阅读器向前移动。
如何获取阅读器OuterXml内容的"快照",而不干扰其位置?
6个回答

11

实际上,ReadSubtree将返回一个“包装”原始阅读器的阅读器。因此,通过新阅读器进行阅读最终会使原始阅读器也向前移动。 您必须将XmlReader视为单向阅读器,它根本无法回退。 至于您的情况,与其尝试记住XML的一部分,不如请求阅读器在输入文件中的位置。只需将其强制转换为IXmlLineInfo接口,它有返回行和位置的方法。使用这个接口可以记住某个起始位置(在问题元素之前),然后记住错误的结束位置。然后从输入文件中读取该部分作为纯文本。


是的,完美,谢谢你,这正是发生的事情。感谢您的解释! - andy
啊..我完全误解了ReadSubTree的意义..对此感到抱歉。说实话,从对象浏览器的文档中并没有明确表述,但MSDN页面更加清晰明了。 - Flynn1179
1
我刚才回去看了一下使用它的代码;实际上,在完成子树的读取后,它会完全停止读取,所以我从未注意到它也推进了原始读取器。 - Flynn1179

5
另一个想法:先读取外部XML(这会推进读取器),然后从该XML创建一个新的读取器,使您能够“返回”并处理当前节点的元素。
while (r.ReadToFollowing("ParentNode"))
{
    parentXml = r.ReadOuterXml();

    //since ReadOuterXml() advances the reader to the next parent node, create a new reader to read the remaining elements of the current parent
    XmlReader r2 = XmlReader.Create(new StringReader(parentXml));
    r2.ReadToFollowing("ChildNode");
    childValue = r2.ReadElementContentAsString();
    r2.Close();
}                  

这对我非常有效,尽管我为StringReader和XmlReader添加了'using'块。 - gotorg

4
不要在读取器上使用任何“读取”操作-如您所发现的那样,它会使其前进。使用调用属性(例如reader.HasValuereader.Value)来检查内容。在对象浏览器中查找“XmlReader”,有很多属性可以阅读。
编辑:我认为没有简单的方法只获取XML,可能是因为当前节点本身可能不是有效的XML,例如XmlWhiteSpace、XmlText节点甚至是XmlAttribute。

谢谢Flynn...所以根据我的需要,我希望在尝试创建XElement时抛出错误之前获得无效XML的摘录。您是在说这是不可能的吗? - andy
1
可能不是不可能的;我很后悔之前没想起来,但如果你调用 reader.ReadSubtree(),它会创建一个全新的 XmlReader,从 reader 所在的位置开始;你可以随意读取它,而不会影响原始的 reader。不确定如何在你的情况下使用它,但看起来这可能是正确的方法。 - Flynn1179

1
我所做的是仅将元素读入XmlDocument,然后读取该文档。在我的情况下,我必须将流文档转换为HTML。我不得不读取一个内部元素,以为父HTML元素分配“样式”。

0

-1

类似于使用ReadSubtree的东西

using (XmlReader reader = XmlReader.Create(new StringReader(xml)))
                                {
                                    reader.MoveToContent();
                                    while (reader.Read())
                                    {
                                        switch (reader.NodeType)
                                        {
                                            case XmlNodeType.Element:
                                                if (reader.Name == "Field") // for example i need to read node field
                                                {

                                                    XmlReader inner = reader.ReadSubtree();  // the reader stays in the same  position
                                                    XElement El = XElement.Load(inner) as XElement;
                                                    inner.Close();
                                                }
                                        }
                                    }
                                }

嗨,Stef,感谢您在StackExchange上回答问题!虽然这段代码可能回答了问题,但提供有关它如何以及/或为什么解决问题的额外上下文将改善答案的长期价值。另请参阅:https://meta.stackoverflow.com/questions/392712/explaining-entirely-code-based-answers - fNek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接