Используйте XMLReader.ReadSubTree, чтобы убедиться, что правильное значение анализируется / узел полностью потребляется

Предположим, у меня есть XML, который выглядит следующим образом:

<Node1>
    <ChildNd>
        <GrandChildNd>
            <a />
            <b />
        </GrandChildNd>
        ...
        <GrandChildNd>
            <b />
            <c />
        </GrandChildNd>
    </ChildNd>
    ...
    </ChildNd>
</Node1>
...
<NodeN>

Другими словами, как и большинство других XML, очень похожая структура между узлами и некоторыми повторяющимися атрибутами / элементами внутри них.

И поскольку большинство моих XML-файлов имеют размер> 200 МБ, я работаю над созданием собственного анализатора с использованием XMLReader, а не более простых моделей XPath / Linq To XML.

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

Так, например, предположим, что я хочу перебрать все <GrandChildNd> в конкретном <ChildNd>, я закодировал это примерно так:

Using reader As XmlReader = XmlReader.Create(uri)

    reader.ReadToFollowing("Node1")
    reader.ReadToDescendant("ChildNd")
    reader.ReadStartElement("ChildNd")

    ' Loop through all the <GrandChildNd>s
    Do Until reader.NodeType = XmlNodeType.EndElement
        Using GrandChildNdRdr As XmlReader = reader.ReadSubtree
            ParseGrandChild(GrandChildNdRdr)
        End Using

        ' Exit current <GrandChildNd>
        reader.ReadEndElement()
    Loop
End Using

И даже в моем ParseGrandChild методе я использую еще больше ReadSubTree вызовов, так как обнаружил, что он гарантирует мне, что я не буду читать ничего за пределами этого текущего узла, и когда я закрываю это вспомогательное средство чтения, он помещает меня в конечный тег узел, который я потреблял.

Из того, что я читал в Интернете, кажется, что метод ReadSubTree довольно легкий и не плохой в использовании, но мне просто интересно, есть ли, помимо перехода от XPath / Linq к маршруту XML, лучший способ сделать это / Я просто делаю что-то совершенно неправильно.

Для меня это все еще в новинку, поэтому буду благодарен за любые ссылки / примеры !!

Кроме того, я знаю, что этот пример кода был написан на VB.NET, но мне одинаково комфортно работать с решениями C # / VB.NET.

Спасибо!!


person John Bustos    schedule 23.10.2014    source источник
comment
Просто из любопытства: что побудило вас написать собственный парсер? Что-то не так с XPath / Linq to XML?   -  person DMAN    schedule 29.10.2014
comment
Возможно, это сообщение SO отвечает на ваш вопрос: stackoverflow.com/questions/407350/   -  person DMAN    schedule 29.10.2014
comment
@DMAN, спасибо за ссылку, но, к сожалению, она не отвечает на мой конкретный вопрос о том, подходит ли ReadSubTree() или нет. Что касается того, почему я пишу свой собственный синтаксический анализатор, это потому, что файлы ОГРОМНЫ, и даже использование методов объединения XMLReader с любым из этих двух методов все еще убивает меня с точки зрения памяти ... Я написал синтаксический анализатор сейчас, я просто интересно, является ли метод, который я использовал, плохой идеей или не более того, чем использование других методов. Спасибо!!   -  person John Bustos    schedule 30.10.2014
comment
проверьте эту ссылку о ReadSubTree () - msdn.microsoft. com / en-us / library / stackoverflow.com/questions/2736622/   -  person Rolwin Crasta    schedule 31.10.2014
comment
@RolwinC, спасибо за эти 2 ссылки! - Я определенно использовал его прямо в своем парсере (к счастью), поскольку я знаю, что узлы будут использоваться, и это позволяет мне ограничивать данные, которые я просматриваю. Мне просто интересно, хороший ли это способ делать что-то ... Пока что никто не говорит, что это не так, по крайней мере :)   -  person John Bustos    schedule 31.10.2014
comment
@JohnBustos: Я не думаю, что есть лучший способ, чем использование ReadSubTree, поскольку вы находитесь в dotNet. Для этого создается ReadSubTree, отвечающее требованиям dotNet. Если вы ищете производительность и использование памяти, вам лучше изобрести колесо, используя C (или C ++) без дополнительных проверок безопасности ReadsubTree, если вы знаете, что делаете ... Да, похоже, я иметь старый XMLParser с указателями и прямым доступом к памяти / буферам, конечно, он быстрый и легкий, но он не безопасен при неправильном использовании; теперь у меня больше проблем с его использованием, чем с их решением.   -  person Karl Stephen    schedule 01.11.2014
comment
Что именно вы пытаетесь делать с данными после их прочтения? Вы можете объединить XmlReader с LINQ to XML, прочитав дочерний узел как XElement, а не как весь документ ... Я обнаружил, что это работает очень хорошо.   -  person Jon Skeet    schedule 03.11.2014
comment
@JonSkeet, Моя основная цель - получить очень небольшой объем данных и сохранить их в таблице БД, чтобы их можно было запросить во второй программе. Моя проблема заключается в том, что мне нужно вытащить в основном те же ключи из рекурсивных узлов (т.е. одинаковые имена элементов у родителей и детей) в ОГРОМНОМ XML, поэтому рекурсивный метод работает очень хорошо, но использование подхода Xelement ужасно, поскольку верхний родитель I Я бы сделал это, потому что у него много дочерних ключей, а его размер составляет ›100 МБ. Моя логика заключалась в том, чтобы рекурсивно использовать ReadSubTree, чтобы убедиться, что я знаю, где я нахожусь, и не убить свою оперативную память. Имеет ли это смысл?   -  person John Bustos    schedule 03.11.2014
comment
@JohnBustos: Почему вы не можете использовать XmlReader, чтобы добраться до элемента, который не огромен, а затем загрузить из него XElement? Требования для меня до сих пор несколько непонятны ...   -  person Jon Skeet    schedule 03.11.2014
comment
@JonSkeet, прошу прощения за то, что не так хорошо это сформулировал, проблема в рекурсивном характере моего дерева. Мне нужно несколько элементов из родительского элемента (например, ›100 МБ), затем несколько элементов из его дочернего элемента (например, 60 МБ), затем из его дочернего элемента и т. Д. Задача состоит в том, чтобы получить данные из очень большого родительские узлы - поскольку я не знаю, как загружать узел без его дочерних узлов - и если я загружаю весь родительский узел, я начинаю сталкиваться с проблемами ОЗУ ... особенно, если у меня, скажем, 3-4 родительских узла Мне нужно вникнуть. Имеет ли смысл то, что я говорю?   -  person John Bustos    schedule 03.11.2014
comment
Хорошо, да, я понимаю, что вы имеете в виду. Подумайте об этом.   -  person Jon Skeet    schedule 03.11.2014
comment
Если у вас есть ЛЮБОЕ представление о том, как загрузить только узел без его дочерних элементов, это может сработать (и, возможно, даже лучше, с тех пор я получаю все доступные мне функции Linq), но я думал, что ReadSubTree по крайней мере ограничивает мою область к любому конкретному узлу, и я могу использовать это рекурсивно, если каждый дочерний элемент имеет ту же структуру, что и родительский. Я просто не был уверен, что это плохая практика ...   -  person John Bustos    schedule 03.11.2014