通过查找密钥从文件中删除多行

时间:2015-03-13 13:15:57

标签: python perl shell

假设我在文件中有以下行(不要将其视为XML文件):

<AVP code="123" name="abcd">
    <type>
        <high/>
    </type>
</AVP>
<AVP code="234" name="ukbkj">
    <type>
      <enum/>
    <type>
       <enum name="erdf"/>
 </AVP>

我想从(例如)AVP代码123中删除匹配/ AVP,以便删除AVP 123的所有数据。我怎样才能做到这一点? 这是输出应该是什么样子。我想保存到文件,而不是打印到标准输出。

<AVP code="234" name="ukbkj">
    <type>
       <enum/>
    <type>
       <enum name="erdf"/>
 </AVP>

4 个答案:

答案 0 :(得分:1)

通过perl。

$ perl -0777pe 's/<AVP code="123".*?<\/AVP> *\n//sg' file
<AVP code="234" name="ukbkj">
<type>
<enum\>
<type>
<enum\>
<AVP code>

通过python。

import re
with open('file') as f:
    m = f.read()
    splt = re.findall(r'(?s)<AVP\s+code="\d+".*?</AVP>', m)
    for i in splt:
        if '<AVP code="123"' not in i:
            print(i, end="")

答案 1 :(得分:0)

如果您的输入是XML,它看起来像这样:

<?xml version="1.0"?>
<root>
    <AVP code="123" name="abcd">
        <type>
            <high/>
        </type>
    </AVP>
    <AVP code="234" name="ukbkj">
        <type>
          <enum/>
        </type>
        <type>
           <enum/>
        </type>
     </AVP>
</root>

您可以使用此XSLT删除所有AVP元素。

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 <xsl:output omit-xml-declaration="no"/>

    <xsl:template match="node()|@*">
      <xsl:copy>
         <xsl:apply-templates select="node()|@*"/>
      </xsl:copy>
    </xsl:template>

    <xsl:template match="AVP[@code='123']" />
</xsl:stylesheet>

使用Python应用它:

import lxml.etree as ET

dom = ET.parse("avp.xml")
xslt = ET.parse("avp.xslt")
transform = ET.XSLT(xslt)
newdom = transform(dom)
with open("avp-out.xml", "wb") as o:
    o.write(ET.tostring(newdom, pretty_print=True))

avp-out.xml中的输出:

<root>

    <AVP code="234" name="ukbkj">
        <type>
          <enum/>
        </type>
        <type>
           <enum/>
        </type>
     </AVP>
</root>

答案 2 :(得分:0)

更合适的方法是使用XML解析库,XML::LibXML是一个很好的解析库。请注意,您当前的示例是有效的XML:

use strict; 
use warnings; 

use XML::LibXML;

my $xml_filename = $ARGV[0];
die "Missing name of xml file to parse"
   unless $xml_filename;
open(my $xml_file, '<', $xml_filename) 
   or die "Error opening XML file: $!";

my $dom = XML::LibXML->load_xml(IO => $xml_file);
foreach my $node ( $dom->findnodes('/root/AVP') ) {
   $node->unbindNode()
      if $node->getAttribute('code') == 123;
}

open(my $out_fh, '>', "${xml_filename}.out") 
   or die "Unable to open outfile: $!";
binmode $out_fh;    

# write XML tree to file
$dom->toFH($out_fh);
close($out_fh);

答案 3 :(得分:0)

使用XML::Twig - 复制Lutz Horn提到的固定XML:

#!/usr/bin/perl

use strict;
use warnings;

use XML::Twig;

sub delete_if_code_123 {
    my ( $twig, $AVP ) = @_;
    if ( $AVP->att('code') eq "123" ) {
        $AVP->delete;
    }
}

my $twig = XML::Twig->new(
    pretty_print  => 'indented',
    twig_handlers => { 'AVP' => \&delete_if_code_123 },
);

$twig ->parse( \*DATA );

$twig -> print;


__DATA__
<?xml version="1.0"?>
<root>
    <AVP code="123" name="abcd">
        <type>
            <high/>
        </type>
    </AVP>
    <AVP code="234" name="ukbkj">
        <type>
          <enum/>
        </type>
        <type>
           <enum/>
        </type>
     </AVP>
</root>