XmlReader извлекает два разных набора элементов за одно чтение документа.

Я пытаюсь прочитать файл XML размером 2,5 ГБ и удалить определенные узлы, скажем, элементы «CD» и элементы «DVD». В настоящее время я делаю что-то вроде этого:

using (XmlReader reader = XmlReader.Create("file.xml"))
{
    DeleteElements(reader.ReadElements("CD"));
    DeleteElements(reader.ReadElements("DVD")); // reader returns 0 elements
}

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

В настоящее время я обнаружил, что ни один элемент «DVD» не получен. Если вы работали с XmlReader раньше, я уверен, что вы можете понять причину проблемы здесь: после того, как читатель читает документ для узлов «CD», читатель не находит никаких элементов «DVD», потому что читатель находится в конце документа.

Учитывая большой размер XML-файла и количество элементов, которые я пытаюсь получить, я не могу загрузить весь документ в память, потому что вы получите OutOfMemoryException — это означает отсутствие XDocument или XPathDocument.

Есть ли способ заставить XmlReader возвращать как «CD», так и «DVD» при чтении документа? Первоначальная загрузка документа занимает довольно много времени, поэтому я не хочу делать это несколько раз. Что-то потрясающее, например reader.ReadElements("DVD|CD"), было бы приятно.


person ajbeaven    schedule 12.12.2012    source источник


Ответы (1)


XmlReader — это парсер xml, работающий только в прямом направлении. Если бы был метод ReadElements, то он запустил бы ридер до конца, и тогда элементов DVD больше нет. Таким образом, вам придется дважды запустить файл.

Основное использование XmlReader:

using (XmlReader reader = XmlReader.Create("input.xml")) {
  while (reader.Read()) {
    switch (reader.NodeType) {
    case XmlNodeType.Element:
      switch (reader.Name) {
      case "CD":
        // do something with a CD
        break;
      case "DVD":
        // do something with a DVD
        break;
      default:
        // do something with all other elements
        break;
      }
      break;
    }
  }
}

Что вы делаете в методе DeleteElements? Вероятно, вам нужно создать XmlWriter для нового временного файла, затем записать все элементы, кроме одного, который вы хотите удалить, во временный файл, и, по крайней мере, заменить исходный файл с временным файлом.

Таким образом, у вас есть один цикл для всех элементов, включая удаление (исключение) некоторых.

person metadings    schedule 21.12.2012
comment
Отличный ответ - в итоге я сделал именно то, что вы предложили здесь, поэтому должен был вернуться и ответить сам! - person ajbeaven; 21.12.2012