C# 如何从XmlReader构建XmlNodes

C# 如何从XmlReader构建XmlNodes,c#,xml,.net-2.0,xmlreader,C#,Xml,.net 2.0,Xmlreader,我正在分析大量的大文件,在分析之后,我的瓶颈是: XmlDocument doc = new XmlDocument(); doc.Load(filename); 这种方法非常方便,因为我可以提取如下节点: XmlNodeList nodeList = doc.SelectNodes("myXPath"); 我正在切换到XmlReader,但当我找到需要提取的元素时,我一直在考虑如何从中构建XmlNode,因为我对XmlReader不太熟悉: XmlReader xmlReader = Xm

我正在分析大量的大文件,在分析之后,我的瓶颈是:

XmlDocument doc = new XmlDocument();
doc.Load(filename);
这种方法非常方便,因为我可以提取如下节点:

XmlNodeList nodeList = doc.SelectNodes("myXPath");
我正在切换到XmlReader,但当我找到需要提取的元素时,我一直在考虑如何从中构建XmlNode,因为我对XmlReader不太熟悉:

XmlReader xmlReader = XmlReader.Create(fileName);

while (xmlReader.Read())
{
   //keep reading until we see my element
   if (xmlReader.Name.Equals("myElementName") && (xmlReader.NodeType == XmlNodeType.Element))
   {
       // How do I get the Xml element from the reader here?
   }
}
我希望能够构建一个
列表
对象。我在.NET2.0上


感谢您的帮助

XmlNode类型没有公共构造函数,因此您不能自己创建它们。您需要有一个
XmlDocument
,可以用来创建它们:

XmlDocument doc = new XmlDocument();
while (xmlReader.Read())
{
    //keep reading until we see my element
    if (xmlReader.Name.Equals("myElementName") && (xmlReader.NodeType == XmlNodeType.Element))
    {
        // How do I get the Xml element from the reader here?
        XmlNode myNode = doc.CreateNode(XmlNodeType.Element, xmlReader.Name, "");
        nodeList.Add(myNode);
    }        
}

XmlReader
XmlDocument
具有非常独特的处理方式
XmlReader
在内存中不保留任何内容,并使用仅向前的方法,而不是在内存中为
XmlDocument
构建完整的DOM树。当性能是一个问题时,它很有帮助,但它也要求您以不同的方式编写应用程序:不使用
XmlNode
,您不保留任何内容,只“在运行中”处理:即,当需要的元素经过时,您可以做一些事情。这接近于SAX方法,但没有回调模型

“如何获取XmlElement”的答案是:您必须根据读者提供的信息从头开始构建它们。不幸的是,这与性能增益背道而驰。一旦切换到XmlReader,通常最好不要完全使用DOM方法,除非有一些不同的情况


此外,这里不能使用使用XPath提取节点的“非常方便”的方法(
SelectNodes
就是您上面展示的方法):XPath需要DOM树。将此方法视为一种过滤方法:您可以向XMLRe读器添加筛选器,并告诉它跳过某些节点或读取到某个节点。这非常快,但思维方式不同。

使用
XmlDocument.ReadNode
进行此方法。将
XmlReader
放入using语句中,并使用
XmlReader.LocalName
而不是Name来删除命名空间前缀。

当我不得不将
XmlReader
中的数据插入
XmlDocumenht
时,我使用了以下解决方法:

XmlReader rdr = cmd.ExecuteXmlReader();

XmlDocument doc = new XmlDocument();

// create a container node for our resultset
XmlElement root = doc.CreateElement("QueryRoot");
doc.AppendChild(root);

StringBuilder xmlBody = new StringBuilder();

while(rdr.Read())
{
    xmlBody.Append(rdr.ReadOuterXml());
}

root.InnerXml = xmlBody.ToString();

为什么不做下面的事情呢

XmlDocument doc = new XmlDocument();
XmlNode node = doc.ReadNode(reader);
我的做法如下:

public static IEnumerable<XmlNode> StreamNodes(
    string path,
    string[] tagNames) 
{            
    var doc = new XmlDocument();            
    using (XmlReader xr = XmlReader.Create(path)) 
    {
        xr.MoveToContent();
        while (true) {
            if (xr.NodeType == XmlNodeType.Element &&
                tagNames.Contains(xr.Name)) 
            {
                var node = doc.ReadNode(xr);
                yield return node;
            } 
            else 
            {
                if (!xr.Read()) 
                {
                    break;
                }
            }
        }
        xr.Close();
    }                        
}
// Used like this:
foreach (var el in StreamNodes("orders.xml", new string[]{"order"})) 
{
    ....
}
公共静态IEnumerable StreamNodes(
字符串路径,
字符串[]标记名)
{            
var doc=新的XmlDocument();
使用(XmlReader xr=XmlReader.Create(path))
{
xr.MoveToContent();
while(true){
if(xr.NodeType==XmlNodeType.Element&&
标记名.Contains(xr.Name))
{
var node=doc.ReadNode(xr);
收益回报节点;
} 
其他的
{
如果(!xr.Read())
{
打破
}
}
}
xr.Close();
}                        
}
//这样使用:
foreach(StreamNodes中的var el(“orders.xml”,新字符串[]{“order”}))
{
....
}

然后可以将节点导入到另一个文档中进行进一步处理。

它似乎正在创建空节点?是的,除非您向元素添加任何内容(例如,通过为
InnerText
属性指定内容),否则它们将为空。哦,是的-现在看起来很明显,因为我刚刚传入元素名称,谢天谢地,这只会导致空节点。您可以使用
doc.ReadNode(reader)
实际获取整个节点,因为
XmlNode
已经应答。请参阅。这是正确的答案,因为另一个节点为空!