关于 XmlReader.ReadSubtree 方法的说明

Clarification about XmlReader.ReadSubtree method

我阅读了关于此方法的 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() returns a new XmlReader instance that can be used to read the current node, and all its descendants.

那个

When the new XML reader has been closed, the original readeris positioned on the EndElement node of the sub-tree

所以这意味着实际上当我移动 innerReader 时,原来的 reader 也会移动?

实际上,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;
    }

so this means that actually when i move the innerReader also the original reader moves?

确实如此,无论如何这不是问题,因为在 "subReader" 关闭之前您不应该调用原始 reader 上的方法,否则您将得到一个异常。

基于您的示例代码的方法示例使用:

    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)
        {
            //...
        }
    }

希望对您有所帮助

替换:

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

收件人:

var element = innerReader.ReadElementContentAsString();

输出:

aaaaaaa
bvbbbb
cccc
ddddd