2012-02-28 2 views
4

Мне нужно перебирать большой XML-файл (~ 2 ГБ) и выборочно копировать определенные узлы в один или несколько отдельных XML-файлов.Iterate Large XML File and Copy Select Nodes

Моя первая мысль заключается в использовании XPath для перебора соответствующих узлов и для каждого теста узла, который другой файл (ы) узел должен быть скопирован, например:

var doc = new XPathDocument(@"C:\Some\Path.xml"); 
var nav = doc.CreateNavigator(); 
var nodeIter = nav.Select("//NodesOfInterest"); 
while (nodeIter.MoveNext()) 
{ 
    foreach (Thing thing in ThingsThatMightGetNodes) 
    { 
     if (thing.AllowedToHaveNode(nodeIter.Current)) 
     { 
      thing.WorkingXmlDoc.AppendChild(... nodeIter.Current ...); 
     } 
    } 
} 

В этом варианте осуществления, Thing определяет public System.Xml.XmlDocument WorkingXmlDoc, чтобы удерживать узлы, что это AllowedToHave(). Однако я не понимаю, как создать новый XmlNode, который является копией nodeIter.Current.

Если есть лучший подход, я был бы рад услышать его.

+0

Чтобы использовать XPath на двухъядерном XML-документе, ваш компьютер должен иметь> 10 ГБ оперативной памяти, возможно> 16 ГБ. Это так? –

+0

@DimitreNovatchev: Да, да, я не знал, что XPath требует столько оперативной памяти, и это кажется довольно расточительным (это сервер, и другие процессы, безусловно, пострадают). Можете ли вы предложить другое решение? –

+0

Я рекомендую использовать XmlReader - таким образом, вы не ограничены для ОЗУ. Ваша логика останется в основном той же. –

ответ

3

Оценка выражения XPath требует, чтобы весь XML-документ (XML Infoset) находился в ОЗУ.

Для файла XML, текстовое представление которого превышает 2 ГБ, обычно для хранения XML-документа должно быть доступно более 10 ГБ ОЗУ.

Поэтому, хотя это и не невозможно, может быть предпочтительным (особенно на сервере, который должен иметь ресурсы, которые быстро доступны для многих запросов) для использования другой техники.

XmlReader (основанные классы) - отличный инструмент для этого сценария. Он работает быстро, только вперед и не требует сохранения считываемых узлов в памяти. Кроме того, ваша логика останется почти такой же.

1

Вы должны рассмотреть LINQ to XML. Проверьте этот блог для деталей и примеров:

http://james.newtonking.com/archive/2007/12/11/linq-to-xml-over-large-documents.aspx

+1

Как LINQ to XML работает с ~ 2GB входными файлами? –

+0

Прямо, наверное, не очень. Но вы можете работать против потока. См. Здесь: http://msdn.microsoft.com/en-us/library/system.xml.linq.xstreamingelement.aspx#Y1392. –

+0

Это очень здорово! –

0

Попробуйте процессор XQuery, который реализует документ проекцию (идею первого опубликованную Марион и Симеон). Он реализован в ряде процессоров, включая Saxon-EE. В принципе, если вы запустите запрос, например //, он будет фильтровать поток входных событий и построить дерево, которое содержит только информацию, необходимую для обработки этого запроса; он выполнит запрос обычным способом, но против гораздо меньшего дерева. Если это небольшая часть общего документа, вы можете легко уменьшить потребность в памяти на 95% или около того.