从简单的XML文件中提取数据

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包中.

  • sudo apt-get install xml-twig-tools (4认同)

Vij*_*jay 12

 grep '<job' file_name | cut -f2 -d">"|cut -f1 -d"<"
Run Code Online (Sandbox Code Playgroud)

  • 格式良好的XML可以通过大约十几种方式使其失败. (7认同)

小智 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)

  • 有许多不同的工具使用标准的XPath表示法从XML中提取信息 - "xmlstarlet"只是一个.其他包括`xmllint`,`xpath`等.请参阅http://stackoverflow.com/questions/15461737/how-to-execute-xpath-one-liners-from-shell (4认同)

Sob*_*que 9

请不要在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::Twigperl库的工具.然而它的作用是使用"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::Twigs pretty_print选项重新格式化XML:

XML::Twig->new( 'pretty_print' => 'indented_a' )->parse( <> ) -> print;
Run Code Online (Sandbox Code Playgroud)

有各种各样的输出格式选项,但对于更简单的XML(和你的一样),大多数看起来非常相似.


gho*_*g74 8

只需使用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)


vld*_*bnc 6

使用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>标记


13r*_*ren 5

假设相同的行,从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适用于两个语句,如同一个.