Как использовать Linux csplit, чтобы нарубить значительный XML-файл?

У меня есть гигантский XML-файл (на 4 ГБ), что я в настоящее время врываюсь в блоки с функцией "разделения" Linux (каждые 25 000 строк - не байтами). Это обычно работает отлично (я заканчиваю приблизительно с 50 файлами), кроме некоторых данных, описания имеют разрывы строки, и таким образом, часто файлы блока не имеют надлежащих закрывающих тэгов - и мой синтаксический анализатор дросселирует на полпути посредством обработки.

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

<?xml version="1.0" encoding="UTF-8"?>
<listings>
<listing><date>2009-09-22</date><desc>This is a description WITHOUT line breaks and works fine with split</desc><more_tags>stuff</more_tags></listing>
<listing><date>2009-09-22</date><desc>This is a really
annoying description field
WITH line breaks 
that screw the split function</desc><more_tags>stuff</more_tags></listing>
</listings>

Затем иногда мое разделение заканчивается как

<?xml version="1.0" encoding="UTF-8"?>
<listings>
<listing><date>2009-09-22</date><desc>This is a description WITHOUT line breaks and works fine with split</desc><more_tags>stuff</more_tags></listing>
<listing><date>2009-09-22</date><desc>This is a really
annoying description field
WITH line breaks ... 
EOF

Таким образом - я читал о "csplit", и он кажется, что мог бы работать для решения этой проблемы. Я, может казаться, не разбираюсь в регулярном выражении...

В основном я хочу тот же вывод ~50ish файлов

Что-то как:

*csplit -k myfile.xml '/</listing>/' 25000 {50}

Любая справка была бы большой Спасибо!

6
задан Fred 13 May 2010 в 22:36
поделиться

4 ответа

Используйте perl:

perl -p -i -e 'unless(defined$fname){$fname="xx00";open$fh,">",$fname;}$size+=length;print$fh $_;if($size>%MAX% and m@</listing>@){$fname++;$size=0;open$fh,">",$fname;}'

Замените % MAX% максимальным размером одного файла в байтах.

1
ответ дан 9 December 2019 в 20:40
поделиться

Прежде всего, вы используете косую черту внутри регулярного выражения. На всякий случай можно процитировать его, чтобы его не перепутали с конечным разделителем: / <\ / list> / .

Однако в этом случае было бы удобнее разделить по начальному тегу, а не по конечному тегу, поскольку каждый фрагмент содержит до , но не включает соответствующую строку. Так что вы можете попробовать что-то вроде этого:

csplit myfile.xml '/^<listing>/' '{*}'

Использовал якорь начала строки ^ , чтобы убедиться, что он разделяется только перед строками, где начальный тег появляется в начале строки.

1
ответ дан 9 December 2019 в 20:40
поделиться

Таким способом нельзя получить действительный файл XML. Я бы порекомендовал вам написать java-программу с использованием StaX, которая, если вы используете реализацию WoodStox, будет действительно довольно быстро передавать поток XML внутрь и наружу.

5
ответ дан 9 December 2019 в 20:40
поделиться

Я бы не рекомендовал использовать regexps (или наивное сопоставление текста) для любых манипуляций с xml, включая разделение. XML достаточно сложен, чтобы иметь дело с тем, что парсер должен использоваться; и из-за ограничений памяти, тот, который может выполнять «потоковую» (также известную как инкрементальный / фрагментированный) парсинг. Я больше всего знаком с Java, где вы будете использовать парсер Stax (или SAX) и writer/generator для этого; большинство других языков имеют нечто подобное. Или, если ввод достаточно регулярный, инструмент привязки данных (JAXB), который может связывать поддеревья.

Делать это правильно может быть немного больше работы, но на самом деле будет работать, имея дело с вещами, которые может иметь xml (например, разделы CDATA не могут быть разделены; решения regexp неизменно имеют случаи, которые они не будут обрабатывать, пока вы в основном не напишут полный синтаксический анализатор xml).

4
ответ дан 9 December 2019 в 20:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: