У меня есть гигантский 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}
Любая справка была бы большой Спасибо!
Используйте 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%
максимальным размером одного файла в байтах.
Прежде всего, вы используете косую черту внутри регулярного выражения. На всякий случай можно процитировать его, чтобы его не перепутали с конечным разделителем: / <\ / list> /
.
Однако в этом случае было бы удобнее разделить по начальному тегу, а не по конечному тегу, поскольку каждый фрагмент содержит до , но не включает соответствующую строку. Так что вы можете попробовать что-то вроде этого:
csplit myfile.xml '/^<listing>/' '{*}'
Использовал якорь начала строки ^
, чтобы убедиться, что он разделяется только перед строками, где начальный тег появляется в начале строки.
Таким способом нельзя получить действительный файл XML. Я бы порекомендовал вам написать java-программу с использованием StaX, которая, если вы используете реализацию WoodStox, будет действительно довольно быстро передавать поток XML внутрь и наружу.
Я бы не рекомендовал использовать regexps (или наивное сопоставление текста) для любых манипуляций с xml, включая разделение. XML достаточно сложен, чтобы иметь дело с тем, что парсер должен использоваться; и из-за ограничений памяти, тот, который может выполнять «потоковую» (также известную как инкрементальный / фрагментированный) парсинг. Я больше всего знаком с Java, где вы будете использовать парсер Stax (или SAX) и writer/generator для этого; большинство других языков имеют нечто подобное. Или, если ввод достаточно регулярный, инструмент привязки данных (JAXB), который может связывать поддеревья.
Делать это правильно может быть немного больше работы, но на самом деле будет работать, имея дело с вещами, которые может иметь xml (например, разделы CDATA не могут быть разделены; решения regexp неизменно имеют случаи, которые они не будут обрабатывать, пока вы в основном не напишут полный синтаксический анализатор xml).