代码之家  ›  专栏  ›  技术社区  ›  Zacky112

从简单XML文件中提取数据

  •  38
  • Zacky112  · 技术社区  · 15 年前

    我有一个包含以下内容的XML文件:

    <?xml version="1.0" encoding="utf-8"?>
    <job xmlns="http://www.sample.com/">programming</job>
    

    我需要一种方法来提取 <job..> </job> 标签,在本例中为编程。这应该在Linux命令提示符下使用grep/sed/awk完成。

    9 回复  |  直到 9 年前
        1
  •  61
  •   amarillion    15 年前

    你真的吗? 不得不 只使用那些工具?它们不是为XML处理而设计的,尽管大多数情况下可以得到一些正常工作的东西,但是在边缘情况下,它会失败,如编码、换行等。

    我建议使用XML代码:

    xml_grep 'job' jobs.xml --text_only
    

    其输出:

    programming
    

    在ubuntu/debian上,xml-grep在xml-twig-tools包中。

        2
  •  12
  •   Vijay    15 年前
     grep '<job' file_name | cut -f2 -d">"|cut -f1 -d"<"
    
        3
  •  9
  •   lmxy    15 年前

    使用xmlstarlet:

    echo '<job xmlns="http://www.sample.com/">programming</job>' | \
       xmlstarlet sel -N var="http://www.sample.com/" -t -m "//var:job" -v '.'
    
        4
  •  9
  •   Sobrique    10 年前

    请不要使用基于行和regex的XML解析。这是个坏主意。您可以使用具有不同格式的语义相同的XML,并且regex和基于行的解析无法处理它。

    像一元标记和变量行包装之类的东西-这些片段“说”同样的话:

    <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>
    

    希望这能清楚地说明为什么创建一个基于regex/行的解析器是困难的?幸运的是,你不需要。许多脚本语言至少有一个,有时还有更多的解析器选项。

    正如之前的海报所暗示的那样- xml_grep 是可用的。这实际上是一个基于 XML::Twig Perl库。然而,它所做的是使用“xpath表达式”来查找某些内容,并区分文档结构、属性和“内容”。

    例如。:

    xml_grep 'job' jobs.xml --text_only
    

    然而,为了更好地回答问题,这里有几个基于源数据的“自己滚动”示例:

    第一种方式:

    使用 twig handlers 捕捉特定类型的元素并对其执行操作。这样做的好处是,它“按您的需要”解析XML,并允许您在飞行中修改它(如果需要)。这对于在处理大型文件时丢弃“已处理”的XML特别有用,使用 purge flush 以下内容:

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    use XML::Twig;
    
    XML::Twig->new(
        twig_handlers => {
            'job' => sub { print $_ ->text }
        }
        )->parse( <> );
    

    将使用 <> 接受输入(通过管道输入或通过命令行指定 ./myscript somefile.xml )然后处理它-每个 job 元素,它将提取并打印任何相关的文本。(你可能想要 print $_ -> text,"\n" 插入换行符)。

    因为它在“job”元素上匹配,所以它也将在嵌套的job元素上匹配:

    <job>programming
        <job>anotherjob</job>
    </job>
    

    将匹配两次,但某些输出也会打印两次。但是,你可以匹配 /job 如果你愿意的话。很有用-这可以让您(例如)打印和删除一个元素,或者复制和粘贴一个修改XML结构的元素。

    或者-先解析,然后根据结构“打印”:

    my $twig = XML::Twig->new( )->parse( <> );
    print $twig -> root -> text;
    

    作为 工作 是您的根元素,我们只需要打印它的文本。

    但我们可以更敏锐一点,寻找 工作 工作 并专门打印:

    my $twig = XML::Twig->new( )->parse( <> );
    print $twig -> findnodes('/job',0)->text;
    

    你可以使用 XML:小枝 S pretty_print 也可以重新格式化XML:

    XML::Twig->new( 'pretty_print' => 'indented_a' )->parse( <> ) -> print;
    

    有多种输出格式选项,但对于更简单的XML(如您的XML),大多数选项看起来非常相似。

        5
  •  8
  •   ghostdog74    15 年前

    只需使用锥子,不需要其他外部工具。如果您想要的标签出现在多行中,下面的代码就可以工作。

    $ 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
    
        6
  •  5
  •   13ren    15 年前

    假设同一行,来自stdin的输入:

    sed -ne '/<\/job>/ { s/<[^>]*>\(.*\)<\/job>/\1/; p }'
    

    笔记: -n 停止自动输出所有内容; -e 意味着它是一个一行程序(AOT脚本) /<\/job> 表现得像个grep; s 剥离openttag+属性和endtag; ; 是一个新的声明; p 印刷品; {} 使grep作为一个语句应用于这两个语句。

        7
  •  3
  •   vldbnc    9 年前

    使用 塞德 命令:

    例子:

    $ 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
    

    说明:

    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> 作为非贪婪的regex替代原因 <.*?> 不适用于SED
    G-替换所有内容,例如结束XML </xml_tag> 标签

        8
  •  0
  •   codaddict    15 年前

    怎么样:

    cat a.xml | grep '<job' | cut -d '>' -f 2 | cut -d '<' -f 1
    
        9
  •  0
  •   miku    9 年前

    演出有点晚了。

    xmlcutty 从XML中剪切节点:

    $ cat file.xml
    <?xml version="1.0" encoding="utf-8"?>
    <job xmlns="http://www.sample.com/">programming</job>
    <job xmlns="http://www.sample.com/">designing</job>
    <job xmlns="http://www.sample.com/">managing</job>
    <job xmlns="http://www.sample.com/">teaching</job>
    

    这个 path 参数命名要剪切的元素的路径。在这种情况下,由于我们对标签一点也不感兴趣,所以我们将标签重命名为 \n ,所以我们得到了一个很好的列表:

    $ xmlcutty -path /job -rename '\n' file.xml
    programming
    designing
    managing
    teaching
    

    注意,XML开头无效(没有根元素)。XMLCutty也可以处理稍微有点破损的XML。

    推荐文章