Как создать XmlNodes из XmlReader
Я разбираю большое количество больших файлов и после профилирования моего узкого места:
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?
}
}
Я хотел бы создать объект List<XmlNode>
. Я нахожусь на .NET 2.0.
Любая помощь оценивается!
Ответы
Ответ 1
Тип 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);
}
}
Ответ 2
Почему бы просто не сделать следующее?
XmlDocument doc = new XmlDocument();
XmlNode node = doc.ReadNode(reader);
Ответ 3
XmlReader
и XmlDocument
имеют очень четкий способ обработки. XmlReader
не хранит ничего в памяти и использует подход только вперед, а не создание полного дерева DOM в памяти для XmlDocument
. Это полезно, когда производительность является проблемой, но также требует, чтобы вы писали свое приложение по-другому: вместо использования XmlNode
вы ничего не держите и только обрабатываете "в пути": т.е. Когда элемент проходит мимо этого вам нужно, вы что-то делаете. Это близко к подходу SAX, но без модели обратного вызова.
Ответ на вопрос "как получить XmlElement" заключается в следующем: вам придется создавать их с нуля на основе информации от читателя. Это, к сожалению, не соответствует повышению производительности. Часто лучше избегать использования подходов DOM вообще после переключения на XmlReader, если только для нескольких отдельных случаев.
Кроме того, "очень удобный" способ извлечения узлов с использованием XPath (SelectNodes
- это то, что вы показываете выше) не может быть использован здесь: XPath требует дерева DOM. Подумайте об этом подходе к фильтрации: вы можете добавить фильтры в XmlReader и сказать ему пропустить определенные узлы или прочитать до определенного node. Это очень быстро, но отличается по-другому.
Ответ 4
Используйте XmlDocument.ReadNode
для этого подхода. Поместите XmlReader
в инструкцию using и используйте XmlReader.LocalName
вместо имени, чтобы удалить префикс пространства имен.
Ответ 5
Я использовал следующее обходное решение, когда мне пришлось вставлять данные из 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();
Ответ 6
Вот мой подход:
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"}))
{
....
}
Затем узлы могут быть импортированы в другой документ для дальнейшей обработки.