关于XmlReader.ReadSubtree方法的说明

时间:2018-04-18 13:23:37

标签: c# xml xmlreader

我阅读了有关此方法的mdsn文档,但我无法弄清楚以下行为的原因:

假设有这个xml:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<project>
    <caseInformation Name="1">
        <field >aaaaaaa</field>
        <field >bvbbbb</field>
        <field >cccc</field>
        <field >ddddd</field>
    </caseInformation>
</project>

现在,如果您运行以下代码:

while (reader.Read())
{
    if (reader.NodeType == XmlNodeType.Element)
    {
        var name = reader.Name;
        if(name == "caseInformation")
        {
            using (var innerReader = reader.ReadSubtree())
            {
                while (innerReader.ReadToFollowing("field"))
                {

                    var element = (XElement)XNode.ReadFrom(innerReader);
                    element.Dump();
                }
            }
         }
     }
}

这将产生以下输出:

<field>aaaaaaa</field>

<field>bvbbbb</field>

<field>cccc</field>

<field>ddddd</field>

如果我改变了使用此指令获取元素的方式

var element = (XElement)XNode.ReadFrom(reader);

我得到相同的输出。但我无法理解为什么。

在msdn上声明

  

ReadSubTree()返回一个新的XmlReader实例,该实例可用于读取当前节点及其所有后代。

那个

  

关闭新的XML阅读器后,原始阅读器位于子树的EndElement节点上

所以这意味着实际上当我移动innerReader时原始阅读器也会移动?

2 个答案:

答案 0 :(得分:2)

实际上,由ReadSubtree()方法返回的新XmlReader并不是真正的新XmlReader,而是源XmlReader上的包装器。

您可以在sourcecode框架中看到它:

    public virtual  XmlReader  ReadSubtree() {
        if (NodeType != XmlNodeType.Element) {
            throw new InvalidOperationException(Res.GetString(Res.Xml_ReadSubtreeNotOnElement));
        }
        return new XmlSubtreeReader(this);
    }

XmlSubtreeReader继承自XmlWrappingReader

如果您看到构造函数:

    internal XmlWrappingReader( XmlReader baseReader ) {
        Debug.Assert( baseReader != null );
        this.reader = baseReader;
        this.readerAsIXmlLineInfo = baseReader as IXmlLineInfo;
    }
  

所以这意味着实际上当我移动innerReader时   原始读者的举动?

无论如何,这都不成问题,因为在关闭“ subReader”之前,您不应该在原始阅读器上调用方法,否则会出现异常。

根据您的示例代码对该方法的示例用法:

    public void ReadProjectInfo()
    {
        //...

        while (reader.Read())
        {
            if (reader.NodeType == XmlNodeType.Element)
            {
                if (reader.Name == "caseInformation")
                {
                    ReadCaseInformation(reader.ReadSubtree());
                }
            }
        }
    }

    public void ReadCaseInformation(XmlReader reader)
    {
        try
        {
            // if something raise an exception here
            // the main reader is not really affected by that
            // because when the methods ends, the "subReader" is closed
            // and then the main reader is set on the closing tag.
            // so the main XML reader can continue to analyze the xml stream
        }
        catch (Exception)
        {
            //...
        }
    }

希望这会有所帮助

答案 1 :(得分:0)

替换:

var element = (XElement)XNode.ReadFrom(innerReader);

致:

var element = innerReader.ReadElementContentAsString();

输出:

aaaaaaa
bvbbbb
cccc
ddddd
相关问题