【问题标题】:How to read from an XmlReader without moving it forwards?如何从 XmlReader 读取而不向前移动它?
【发布时间】:2011-02-26 05:26:24
【问题描述】:

我得到了这个场景:

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 之前对节点执行任何类型的 READ 操作,它会向前移动阅读器。

如何在不干扰阅读器位置的情况下获取阅读器 OuterXml 内容的“快照”?

【问题讨论】:

    标签: c# .net xml xml-parsing xmlreader


    【解决方案1】:

    实际上,ReadSubtree 将返回一个“包装”原始阅读器的阅读器。因此,通读新的最终也会推进原始的。 您必须将 XmlReader 视为仅向前的阅读器,它根本无法返回。 至于您的场景,您可以向读者询问输入文件中的位置,而不是尝试记住部分 XML。只需将其转换为 IXmlLineInfo 接口,它具有返回线和位置的方法。使用它,您可以记住一些起始位置(在相关元素之前),然后是错误的结束位置。然后从输入文件中以纯文本形式读取该部分。

    【讨论】:

    • 是的,完美,谢谢,这正是正在发生的事情。谢谢你的解释!
    • 啊.. 我完全误解了 ReadSubTree 的意思.. 对此感到抱歉。老实说,对象浏览器中的文档并没有使这一点变得明显,但 MSDN 页面使其更清晰。
    • 我刚回去又查看了使用它的代码;它实际上在完成子树后完全停止阅读,所以我从来没有注意到它也提升了原始阅读器。
    【解决方案2】:

    另一个想法:读取外部 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 添加了“使用”块。
    【解决方案3】:

    不要在阅读器上使用任何“读取”操作 - 正如您所发现的那样,这会推进它。使用对 reader.HasValuereader.Value 等属性的调用来检查内容。在对象浏览器中查找“XmlReader”,可以读取的属性非常多。

    编辑:我认为没有简单的方法来简单地获取 XML,可能是因为当前节点本身可能不是有效的 XML,例如 XmlWhiteSpace、XmlText 节点甚至是 XmlAttribute。

    【讨论】:

    • 感谢 flynn... 所以出于我的目的,我希望在尝试创建 XElement 时引发错误之前获取无效 xml 的提取。你是说这不可能吗?
    • 可能不是不可能;我因为以前不记得这一点而自责,但如果你打电话给reader.ReadSubtree(),它会创建一个全新的XmlReader,从reader 所在的任何地方开始;您可以阅读所有您喜欢的内容,而不会影响您原来的reader。不是 100% 确定你会如何在你的情况下使用它,但看起来它可能是要走的路。
    【解决方案4】:

    我所做的只是将元素读入 XmlDocument,然后改为读取。就我而言,我必须将流文档转换为 HTML。我必须阅读内部元素才能为父 HTML 元素分配“样式”。

    【讨论】:

      【解决方案5】:

      事实上,虽然 Vitek Karas MSFT 是对的,但 Helena Kupkova 在https://msdn.microsoft.com/en-us/library/aa302292.aspx 上发布了一个灵巧的小型 XML 书签阅读器。这样就可以使用缓存进行后退。

      【讨论】:

        【解决方案6】:

        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 上回答问题!虽然此代码可能会回答问题,但提供有关它如何和/或为什么解决问题的额外上下文将提高​​答案的长期价值。另见:meta.stackoverflow.com/questions/392712/…
        猜你喜欢
        • 1970-01-01
        • 2016-11-22
        • 2011-05-10
        • 2018-05-09
        • 1970-01-01
        • 2022-01-12
        • 2010-11-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多