我有一个包含 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 ...>