我有一个来自 xmllint 和 egrep 的输出,我想打印两个相邻的字段。例如
(xmlinput) xmllint --format | egrep reference\|sourcefile
<reference>ItemX</reference>
<sourcefile>://filepath/blah/blah/</sourcefile>
<reference>ItemY</reference>
<sourcefile>://filepath/blah/blah/</sourcefile>
.
.
<reference>ItemW</reference>
<sourcefile>://filepath/blah/blah/</sourcefile>
有没有办法将引用和源文件元素彼此相邻输出?例如
(xmlinput) xmllint --format | egrep reference\|sourcefile
<reference>ItemX</reference><sourcefile>://filepath/blah/blah/</sourcefile>
<reference>ItemY</reference><sourcefile>://filepath/blah/blah/</sourcefile>
.
.
<reference>ItemW</reference><sourcefile>://filepath/blah/blah/</sourcefile>
答案1
[your command] | paste -d '' - -
将连接连续的行。
答案2
一旦开始使用grep
XML,您就会对输入做出假设,并且(几乎肯定)您将不再拥有有效的 XML 输出,因此有时这不是最好的方法。
也就是说,阻力最小的路径通常涉及grep
,因此取决于您的 XML(格式良好的最小示例会很有用),您应该能够使用xmllint
with --xpath
(xmllint
>= 2.7.7 以获得--xpath
支持),如下所示:
xmllint --xpath "//reference|//sourcefile" input.xml |
pcregrep -o "(<reference>.*?</sourcefile>)"
其中xmllint
使用提取元素X路径|
与您感兴趣的元素之一(作为逻辑“或”)匹配的表达式(//
以选择输入中任意位置的所有匹配元素)。 (非 XML 感知)pcregrep
(而不是egrep
)将每对元素与分组进行匹配,并每行输出每个匹配的组。这里需要注意的一点是正则表达式,.*?
它是 PCRE非贪婪匹配所以它匹配最低限度指示标签之间的文本量,而不是一次性整行(xmllint --xpath ...
将所有内容转储到一行)。
使用 grep 有点“作弊”,我们对输入进行假设,但xmllint
完成了大部分繁重的工作。这种方法可能会导致未来的解析问题,因为XML 不是“常规的”正则表达式并不是完成这项工作的最佳工具。
做到这一点的巧妙方法是XML小星:
xml select -t -m '//*' \
--if 'local-name()="reference"' -c . \
--elif 'local-name()="sourcefile"' -c . -o $'\n' input.xml
这会搜索所有元素 ( //*
),匹配时<reference>
将该节点复制到输出 ( -c .
),否则匹配时<sourcefile>
将该节点复制到带有额外换行输出 ( -o $'\n'
) 的输出。
答案3
只需将数据通过管道传输到perl -pe 'chop if /^<reference>/'