【问题标题】:perl one liner grabbing all the "keys" out of an xml fileperl 一个班轮从 xml 文件中抓取所有“键”
【发布时间】:2011-09-17 16:56:22
【问题描述】:

我正在尝试删除 XML 文件中位于标签 和 之间的所有行。

作为第一次解决问题,我得到了一个正则表达式,它将匹配文件中的第一个键块,但它不会继续匹配文件中的其他块。我尝试将“/g”添加到正则表达式中,并且尝试使用“-0777”一次吞下整个文件,这两种技巧都没有任何区别。下面是 perl 单行:

perl -00 -ne 'print $1 if /(\s+\<KEYS\>\n\s+.*?\n\s+\<\/KEYS\>)/s' someFile.xml

我得到这个输出:

  <KEYS>
    <KEY name="cone_id" type="long" nativeType="number(17)"/>
    <KEY name="bar_id" type="long" nativeType="number(32)"/>
    <KEY name="foo_type" type="int" nativeType="number(3)"/>
  </KEYS>

如上所述,文件中有更多块(将近 5000 行长),但 perl 代码不会与其余部分混淆。

有什么建议吗?

【问题讨论】:

  • 是的,我认为有人会建议这样做,但我根本不关心 xml 结构。我只是剥离了恰​​好是 xml 的文本块。如果这是简单的古英语并且标签只是单词,我会遇到同样的问题。问题是围绕整个事情抛出另一个循环,所以它只是在文件中进行时重复正则表达式。

标签: regex perl


【解决方案1】:

您的单线将通过进行两项更改来满足您的需求:

  1. if 更改为while
  2. g 选项添加到您的正则表达式:/.../gs

另外,感兴趣的开始标签和结束标签本身似乎位于不同的行上。如果是这样,flip-flop operator 可能会很方便:

perl -ne 'print if m{<KEYS>} .. m{</KEYS>}' DATA_FILE

【讨论】:

  • 谢谢,成功了。这就是触发器运算符的提示
【解决方案2】:

我不完全确定您所说的“剥离所有线条”是什么意思。如果您想打印所有 KEYS 元素而不打印其他元素,那么您就可以了:

perl -MXML::Simple -e 'print XMLout((XMLin(join "", <>))->{KEYS})' data.xml    

或:

use XML::Simple;
my $xml = XMLin(join '', <DATA>); 
print XMLout($xml->{KEYS});

__DATA__
<root>
  <KEYS>
    <KEY name="cone_id" type="long" nativeType="number(17)"/>
    <KEY name="bar_id" type="long" nativeType="number(32)"/>
    <KEY name="foo_type" type="int" nativeType="number(3)"/>
  </KEYS>
  <NOTKEYS1>
    <KEY name="cone_id" type="long" nativeType="number(17)"/>
    <KEY name="bar_id" type="long" nativeType="number(32)"/>
    <KEY name="foo_type" type="int" nativeType="number(3)"/>
  </NOTKEYS1>
  <NOTKEYS2>
    <KEY name="cone_id" type="long" nativeType="number(17)"/>
    <KEY name="bar_id" type="long" nativeType="number(32)"/>
    <KEY name="foo_type" type="int" nativeType="number(3)"/>
  </NOTKEYS2>
  <KEYS>
    <KEY name="cone_id" type="long" nativeType="number(17)"/>
    <KEY name="bar_id" type="long" nativeType="number(32)"/>
    <KEY name="foo_type" type="int" nativeType="number(3)"/>
  </KEYS>
</root>

即使你根本不关心结构,这也比正则表达式更容易推理,不是吗?

无论如何,这是一个正则表达式版本:

perl -e '$a = join "", <>; print $a =~ m/(\s+\<KEYS\>\n\s+.*?\n\s+\<\/KEYS\>)/sg' data.xml

【讨论】:

    【解决方案3】:

    如果 XML 格式正确,您可以在App::xml_grep2 中使用xml_grepXML::Twigxml_grep2,在App::xml_grep2 中:

    xml_grep -v KEYS to_strip.xml
    xml_grep2 -v '//KEYS' to_strip.xml
    

    第一个基于 XML::Twig 并以流模式工作,第二个基于 XML::LibXML 并在开始 grep 之前将整个文档加载到内存中,但它应该更快(我没有' t 对它进行基准测试)。

    它们都不是 Perl 单行,但它们都是用 Perl 编写的,所以我希望你可以接受 ;--)

    【讨论】:

    • 虽然不完全是我的想法,但我确实很欣赏 XML::Twig 和 App::sml_grep2 的链接。它们看起来很方便。
    【解决方案4】:

    你必须使用 perl 吗?如果没有,请尝试 sed:

    sed -i".backup" 's/<KEYS>([^<]*)<\/KEYS>/\1/g' somefile.xml
    

    【讨论】:

      【解决方案5】:
      perl -MXML::LibXML -e'
         my $doc = XML::LibXML->new->parse_file($ARGV[0]);
         $_->parentNode->removeChild($_)
            for $doc->documentElement->findnodes("//KEYS");
         $doc->toFile($ARGV[1], 0);
      ' infile outfile
      

      为了便于阅读,我添加了换行符。如果你真的是一个真正的单行,你可以删除它们,尽管它也适用于换行符。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-10
        • 2013-05-12
        • 1970-01-01
        • 2020-12-27
        • 2019-03-27
        相关资源
        最近更新 更多