Разделить большой XML на несколько файлов

Мне просто интересно, как я могу разделить большой XML-выход Nokogiri

Например, я заполнил Nokogiri::XML данными и теперь хочу хранить все эти данные в отдельных файлах, каждый размером не более 10 МБ.

Правка из комментария: мы не хотим разделяться посередине тега, мы хотим реплицировать xml-заголовок в каждом файле, должно быть что-то в методах Nokogiri.


person com    schedule 31.10.2011    source источник
comment
Это звучит как хороший вопрос, но вы должны быть более точны в своих требованиях, предпочтительно с примерами ввода и вывода. Если у вас есть <root><p>18MB of text</p></root>, каким должен быть результат? Как насчет <root><a><b>6MB</b><b>6MB</b><b>6MB</b></a></root>? Как насчет <root><a><b>4MB</b><b>4MB</b></a><c>4MB</c></root>?   -  person Phrogz    schedule 31.10.2011
comment
Это не то, что Нокогири должен уметь делать; Nokogiri генерирует XML, который вы указываете ему создать. Вы, как разработчик, должны знать, сколько данных вы создаете, а затем предпринимать шаги, чтобы разбить эти данные на управляемые фрагменты перед созданием XML. Это верно независимо от того, создаете ли вы XML с помощью Nokogiri или генерируете YAML, JSON или сообщения электронной почты с помощью соответствующих генераторов.   -  person the Tin Man    schedule 31.10.2011
comment
Еще один особенно патологический случай: каким должен быть вывод для ‹r a='1' b='2' c='3' ... aa='27' ab='28' ... /› и т.д. пока у вас не будет атрибутов на несколько мегабайт?   -  person Phrogz    schedule 01.11.2011
comment
Мне нужно все это, чтобы сделать карту сайта. Таким образом, ломаются данные только по тегу ‹url›, и еще одна проблема заключается в добавлении заголовка xml в каждый файл карты сайта*.   -  person com    schedule 01.11.2011


Ответы (2)


Допустим, у вас есть xml:

xml = '<foo><child num="1"/><child num="2"/><child num="3"/></foo>'
doc = Nokogiri::XML(xml)

И вы хотите разбить диапазоны дочерних узлов и сохранить их отдельно, не теряя иерархии. Вы можете сделать что-то вроде:

[0..0, 1..1, 2..2].each do |range|
    c = doc.clone
    (c.xpath('/foo/child') - c.xpath('/foo/child')[range]).remove #remove nodes not in range
    File.open("#{range.first}.xml", 'w') {|f| f.write(c.to_s) }
end
person pguardiario    schedule 01.11.2011
comment
здорово! можно проще? Например, объект nokogiri (карта сайта) содержит огромное количество ‹url›*‹/url›. Мне нужно сделать что-то вроде каждого для этого объекта, при каждом запуске мы подсчитываем количество байтов - person com; 01.11.2011

Как насчет использования этого простого фрагмента:

def split_by_size(text, size = 10 * 1024 * 1024)
  text.scan /.{1, #{size}}/
end

split_by_size("12345" * 2, 3)  # => ["123", "451", "234", "5"]

Вы можете использовать этот массив чанков для сохранения их в отдельные файлы.

person WarHog    schedule 31.10.2011
comment
хорошо, но не подходит для XML, мы не хотим делиться в середине тега, мы хотим реплицировать заголовок xml в каждом файле, должно быть что-то в методах nokogiri - person com; 31.10.2011
comment
Это серьезно сломает файл XML. - person the Tin Man; 31.10.2011