Как добавить строку, которая не начинается с «

Как добавить строку, которая не начинается с «

У меня есть лог, содержащий строки 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 ...>декларацию в начале итогового документа.

Связанный контент