Zac*_*112 40 xml bash awk grep sed
我有一个包含以下内容的XML文件:
<?xml version="1.0" encoding="utf-8"?>
<job xmlns="http://www.sample.com/">programming</job>
Run Code Online (Sandbox Code Playgroud)
我需要一种方法来提取<job..>
</job>
标签中的内容,在这种情况下是programmin.这应该在linux命令提示符下完成,使用grep/sed/awk.
ama*_*ion 63
你真的必须只使用那些工具吗?它们不是为XML处理而设计的,虽然它可以在大多数情况下获得正常工作的东西,但它会在边缘情况下失败,例如编码,换行等.
我推荐xml_grep:
xml_grep 'job' jobs.xml --text_only
Run Code Online (Sandbox Code Playgroud)
这给出了输出:
programming
Run Code Online (Sandbox Code Playgroud)
在ubuntu/debian上,xml_grep位于xml-twig-tools包中.
Vij*_*jay 12
grep '<job' file_name | cut -f2 -d">"|cut -f1 -d"<"
Run Code Online (Sandbox Code Playgroud)
小智 10
使用xmlstarlet:
echo '<job xmlns="http://www.sample.com/">programming</job>' | \
xmlstarlet sel -N var="http://www.sample.com/" -t -m "//var:job" -v '.'
Run Code Online (Sandbox Code Playgroud)
请不要在XML上使用基于行和正则表达式的解析.这是个坏主意.您可以使用具有不同格式的语义相同的XML,并且正则表达式和基于行的解析根本无法应对它.
像一元标签和可变线包装这样的东西 - 这些片段"说"同样的事情:
<root>
<sometag val1="fish" val2="carrot" val3="narf"></sometag>
</root>
<root>
<sometag
val1="fish"
val2="carrot"
val3="narf"></sometag>
</root>
<root
><sometag
val1="fish"
val2="carrot"
val3="narf"
></sometag></root>
<root><sometag val1="fish" val2="carrot" val3="narf"/></root>
Run Code Online (Sandbox Code Playgroud)
希望这清楚地说明为什么制作基于正则表达式/行的解析器很困难?幸运的是,你不需要.许多脚本语言至少有一个,有时更多的解析器选项.
正如之前的海报所暗示的那样 - xml_grep
是可用的.这实际上是一个基于XML::Twig
perl库的工具.然而它的作用是使用"xpath表达式"来查找内容,并区分文档结构,属性和"内容".
例如:
xml_grep 'job' jobs.xml --text_only
Run Code Online (Sandbox Code Playgroud)
然而,为了获得更好的答案,这里有几个基于源数据"自己动手"的例子:
第一种方式:
使用twig handlers
它捕获特定类型的元素并对其起作用.这样做的好处是它可以"随时"解析XML,并允许您在需要时在飞行中对其进行修改.当您使用purge
或使用大型文件时,这对于丢弃"已处理的"XML特别有用flush
:
#!/usr/bin/perl
use strict;
use warnings;
use XML::Twig;
XML::Twig->new(
twig_handlers => {
'job' => sub { print $_ ->text }
}
)->parse( <> );
Run Code Online (Sandbox Code Playgroud)
这将用于<>
获取输入(管道输入或通过命令行指定./myscript somefile.xml
)并处理它 - 每个job
元素,它将提取并打印任何相关的文本.(您可能想要print $_ -> text,"\n"
插入换行符).
因为它匹配'job'元素,所以它也匹配嵌套的job元素:
<job>programming
<job>anotherjob</job>
</job>
Run Code Online (Sandbox Code Playgroud)
将匹配两次,但也打印一些输出两次.但是,/job
如果您愿意,可以匹配.有用 - 这使您可以打印和删除元素,或复制并粘贴修改XML结构的元素.
或者 - 首先解析,然后根据结构"打印":
my $twig = XML::Twig->new( )->parse( <> );
print $twig -> root -> text;
Run Code Online (Sandbox Code Playgroud)
作为job
您的根元素,我们所需要做的就是打印它的文本.
但我们可以更挑剔,寻找job
或/job
打印具体而言:
my $twig = XML::Twig->new( )->parse( <> );
print $twig -> findnodes('/job',0)->text;
Run Code Online (Sandbox Code Playgroud)
您也可以使用XML::Twig
s pretty_print
选项重新格式化XML:
XML::Twig->new( 'pretty_print' => 'indented_a' )->parse( <> ) -> print;
Run Code Online (Sandbox Code Playgroud)
有各种各样的输出格式选项,但对于更简单的XML(和你的一样),大多数看起来非常相似.
只需使用awk,无需其他外部工具.如果您想要的标签出现在multitine中,则下面有效.
$ cat file
test
<job xmlns="http://www.sample.com/">programming</job>
<job xmlns="http://www.sample.com/">
programming</job>
$ awk -vRS="</job>" '{gsub(/.*<job.*>/,"");print}' file
programming
programming
Run Code Online (Sandbox Code Playgroud)
使用sed命令:
例子:
$ cat file.xml
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
$ cat file.xml | sed -ne '/<heading>/s#\s*<[^>]*>\s*##gp'
Reminder
Run Code Online (Sandbox Code Playgroud)
解释:
cat file.xml | sed -ne '/<pattern_to_find>/s#\s*<[^>]*>\s*##gp'
n
- 禁止打印所有行
e
- 脚本
/<pattern_to_find>/
- 查找包含指定模式的行,例如<heading>
接下来是替换部分s///p
,它删除除所需值之外的所有内容,其中/
替换#
为以提高可读性:
s#\s*<[^>]*>\s*##gp
\s*
- 如果存在则包含空格(最后相同)
<[^>]*>
表示<xml_tag>
非贪婪的正则表达式替代原因<.*?>
不适用于 sed
g - 替换所有内容,例如关闭 xml</xml_tag>
标记
假设相同的行,从stdin输入:
sed -ne '/<\/job>/ { s/<[^>]*>\(.*\)<\/job>/\1/; p }'
Run Code Online (Sandbox Code Playgroud)
注意:-n
停止自动输出所有内容; -e
意味着它是一个单行(aot a script)/<\/job>
就像一个grep; s
剥去opentag +属性和endtag; ;
是一个新的声明; p
打印; {}
使grep适用于两个语句,如同一个.