Вы можете использовать парсер стиля SAX. Так как парсеры SAX не создают документ из XML, они полезны для анализа больших документов. Недостатком является то, что вам нужно будет отслеживать состояние самостоятельно. Я никогда не использовал OGA для разбора SAX, но я предполагаю, что он подойдет для ваших 5 ГБ XML.
Вот отдельный пример. Просто вставьте его в файл и запустите (часть после __END__
будет доступна в качестве ввода, в DATA
).
require "oga"
class PeopleHandler
PERSON_PATH = ["xml", "people", "person"]
ATTRIBUTE_PATH = ["xml", "people", "person", "attribute"]
attr_reader :people
def initialize
@people = []
@current_person = nil
@current_path = []
end
def on_element(_namespace, name, attrs = {})
current_path.push(name)
if current_path == PERSON_PATH
people.push({id: attrs["id"]})
elsif current_path == ATTRIBUTE_PATH
people.last[attrs["name"]] = attrs["value"]
end
end
def after_element(_namespace, name)
current_path.pop
end
private
attr_reader :current_path, :current_person
end
handler = PeopleHandler.new
Oga.sax_parse_xml(handler, DATA.read)
p handler.people
# [{:id=>"12", "first-name"=>"Pascal", "country"=>"Switzerland"}, {:id=>"13", "first-name"=>"Fred", "country"=>"Sweden"}, {:id=>"45", "first-name"=>"Karl", "country"=>"Hungary"}]
__END__
<xml>
<people>
<person id="12">
<attribute name="first-name" value="Pascal" />
<attribute name="country" value="Switzerland" />
</person>
<person id="13">
<attribute name="first-name" value="Fred" />
<attribute name="country" value="Sweden" />
</person>
<person id="45">
<attribute name="first-name" value="Karl" />
<attribute name="country" value="Hungary" />
</person>
</xml>
Sax-парсеры работают, отправляя события в обработчик. Смотрите список доступных событий (методы, которые вызываются) здесь: https://github.com/YorickPeterse/oga/blob/master/lib/oga/xml/sax_parser.rb
В примере используется массив (current_path
) для отслеживания позиции внутри документа. Возможно, это не требуется в вашем случае, и достаточно имени элемента.
Если достигнут элемент <person>
, я добавляю sh Ха sh в мой список людей. Затем для каждого элемента <attribute>
я увеличиваю это ha sh (people.last
) несколькими парами ключ / значение. После того, как синтаксический анализ завершен, у меня есть список людей handler.people
, которые я могу обработать дальше.
Это только для того, чтобы дать вам пример того, как работают SAX-парсеры.
- Возможно, вы делаете не нужно отслеживать путь, возможно, имя элемента достаточно хорошее (т. е. когда ваш элемент имеет уникальное имя). Тогда вы можете избежать отслеживания позиции в массиве.
- Может быть, вы не хотите создавать коллекцию элементов для дальнейшей обработки. Возможно, вы торгуете памятью, сохраненной с помощью SAX-парсера, для памяти, которая вам нужна для ваших предметов. Вместо этого вы можете захотеть обработать элемент, когда у вас есть вся необходимая информация (вероятно, в
after_element
), а затем выбросить его.
Если вы хотите синхронизировать различные разделы вашего кода, вы можете использовать простое решение:
Сроки можно сделать довольно просто, чтобы получить представление:
t1 = Time.now
operation_1
t2 = Time.now
operation_2
t3 = Time.now
puts "Operation 1 took: #{t2 - t1}"
puts "Operation 2 took: #{t3 - t2}"