
У меня есть лог, содержащий строки XML. Пример формата ниже:
<head>
<body>
<line>
asdasd</line>
</body>
</head>
Я хочу просканировать файл журнала и добавить строки, которые не начинаются с '<', к предыдущей строке. Вывод будет таким:
<head>
<body>
<line>asdasd</line>
</body>
</head>
Спасибо
решение1
Думаю, я уже говорил это раньше, но рискую показаться заезженной пластинкой, — НЕ используйте регулярные выражения для разбора XML. Это хрупко и подвержено поломкам. Но сначала я бы спросил — зачем вы пытаетесь делать то, что делаете? Потому что это не должно иметь значения при работе с вашим XML.
Вместо этого используйте парсер:
#!/usr/bin/env perl
use strict;
use warnings;
use XML::Twig;
my $twig = XML::Twig->parsefile('your_file.xml');
foreach my $elt ( $twig->get_xpath('//#PCDATA') ) {
$elt->set_text( $elt->trimmed_text );
}
$twig->set_pretty_print('indented_a');
$twig->print;
Это делает то, что вам нужно... но если вы на самом деле работаете с XML в обычном режиме, этот trimmed_text
метод, вероятно, в любом случае устраняет необходимость в этой обработке.
решение2
Perl спешит на помощь!
perl -pe 'print "\n" if /^\s*+</; chomp;' input > output
т. е. символ новой строки удаляется из каждой строки и печатается, когда следующая строка начинается с пробела, за которым следует <
.
Чтобы сохранить последнюю новую строку, измените ее chomp
на chomp unless eof
или добавьтеEND { print "\n" }
решение3
Почти стандартная процедура sed
sed '$!N;s/\n\(\s*[^<[:blank:]]\)/\1/;P;D' log.xml
решение4
Использование функции XPath normalize-space
для удаления начального символа новой строки узла /head/body/line
:
xmlstarlet edit --update '/head/body/line' --expr 'normalize-space(text())' file.xml
Или, используя сокращенные названия:
xmlstarlet ed -u '/head/body/line' -x 'normalize-space(text())' file.xml
Выходные данные, учитывая вводные данные в вопросе, будут следующими:
<?xml version="1.0"?>
<head>
<body>
<line>asdasd</line>
</body>
</head>
Используйте //line
вместо полного пути от корневого узла, если вы хотите повлиять на все line
узлы во входном документе.
Добавьте -O
или --omit-decl
после edit
или , ed
чтобы отбросить <?xml ...>
декларацию в начале итогового документа.