如何使用grep基于属性使用perl解析xml文件

时间:2018-03-19 21:12:29

标签: xml perl grep xml-twig

我是 perl 的新手并且一直在努力。我有一个具有以下结构的xml文件,但有数千个条目:

的test.xml

<msms_pipeline_analysis>
    <spectrum_query spectrum="H_TPP08.04885.04885.2" start_scan="4885" end_scan="48887">
        <search_result>
          <search_hit calc_neutral_pep_mass="2348.060995306391" hit_rank="1">
          </search_hit>
        </search_result>
    </spectrum_query>
    <spectrum_query spectrum="L_TPP08.05765.04785.2" start_scan="4885" end_scan="48856">
        <search_result>
          <search_hit calc_neutral_pep_mass="2348.060995306391" hit_rank="1">
          </search_hit>
        </search_result>        
    </spectrum_query>
    <spectrum_query spectrum="L_TPP10.87945.3485.2" start_scan="4885" end_scan="4885">
        <search_result>
          <search_hit calc_neutral_pep_mass="2348.060995306391" hit_rank="1">
          </search_hit>
        </search_result>        
    </spectrum_query>
</msms_pipeline_analysis>

我需要解析/删除“spectrum_query”节点 包含属性“spectrum”此示例中的字符串 “TPP08”即实际上它在第一个下划线和第一个点之间(后面我想要TPP09,TPP10等子集),例如。

H_的 TPP08 .04885.04885.2

并保留文件及其结构。

通过搜索,我提出了许多解决方案,这些解决方案旨在删除满足属性的节点。就我而言,此类解决方案可以删除相关节点:

#!/urs/bin/env perl
use strict;
use warnings;
use XML::Twig;

my $twig = XML::Twig -> new ('pretty_print' => 'indented' ) -> parsefile ( 'test.xml' ); 
foreach my $element ( $twig -> get_xpath('spectrum_query[@spectrum="H_TPP08.04885.04885.2"]') ) {
   $element -> delete;
}

$twig -> print; 

open XML, ">output.xml";
print XML $twig->toString();
close XML;

删除第一个节点。但只有特定的一个,而真正的文件有数千个条目。此外,我想保持符合标准的那些,因为反过来我必须为不包含频谱TPP08的每个其他条目运行脚本(例如TPP09,TPP10等) 。

至于确定字符串,到目前为止我已经来了这个

$string = qw(H_TPP08.05164.05164.2);
my ($substring2) = $string =~ m:.*_(.+?)?\.:;
print "$substring2\n";

哪个输出 TPP08 我想要的是什么,因为我需要用H_TPP08.XXXX或L_TPP08.XXXX保存节点

到目前为止,我还没有发现是否有办法在R中使用“!”来做负面子集。 grep,并在属性上的字符串匹配中包含grep,这样就可以解析了。对于我最有可能阅读的内容,我需要使用所有条目的属性字符串创建一个数组

my @array = map { $tag -> att('spectrum') } $twig -> get_xpath('//spectrum_query');

然后在grep之后依次评估每个条目并将其与匹配的字符串进行比较,然后只保持节点满足该条目。但是我无法用我的基本知识来解决这个问题。

任何帮助都将非常感谢!感谢

3 个答案:

答案 0 :(得分:0)

use strict;
use warnings;

use XML::Twig;

my $xml = <<'EOF';
<msms_pipeline_analysis>
  <spectrum_query spectrum="H_TPP08.04885.04885.2" start_scan="4885" end_scan="48887">
    <search_result>
      <search_hit calc_neutral_pep_mass="2348.060995306391" hit_rank="1">
      </search_hit>
    </search_result>
  </spectrum_query>
  <spectrum_query spectrum="L_TPP08.05765.04785.2" start_scan="4885" end_scan="48856">
    <search_result>
      <search_hit calc_neutral_pep_mass="2348.060995306391" hit_rank="1">
      </search_hit>
    </search_result>
  </spectrum_query>
  <spectrum_query spectrum="L_TPP10.87945.3485.2" start_scan="4885" end_scan="4885">
    <search_result>
      <search_hit calc_neutral_pep_mass="2348.060995306391" hit_rank="1">
      </search_hit>
    </search_result>
  </spectrum_query>
</msms_pipeline_analysis>
EOF

my $twig = XML::Twig->new(pretty_print => 'indented')->parse($xml);

for my $element ($twig->get_xpath('/msms_pipeline_analysis/spectrum_query')) {
    next if $element->att('spectrum') =~ /TPP08/;
    $element->delete;
}

$twig->print;

输出:

<msms_pipeline_analysis>
  <spectrum_query end_scan="48887" spectrum="H_TPP08.04885.04885.2" start_scan="4885">
    <search_result>
      <search_hit calc_neutral_pep_mass="2348.060995306391" hit_rank="1"></search_hit>
    </search_result>
  </spectrum_query>
  <spectrum_query end_scan="48856" spectrum="L_TPP08.05765.04785.2" start_scan="4885">
    <search_result>
      <search_hit calc_neutral_pep_mass="2348.060995306391" hit_rank="1"></search_hit>
    </search_result>
  </spectrum_query>
</msms_pipeline_analysis>

答案 1 :(得分:0)

您可以在属性

上使用带有正则表达式的get_xpath
foreach my $element ( $twig -> get_xpath('spectrum_query[@spectrum =~ /^(?!\w_TPP08\.)/]') ) {
   $element -> delete;
}

或者您可以检查每个节点的属性匹配:

foreach my $element ( $twig -> get_xpath('spectrum_query[@spectrum]') ) {
  if ($element->att('spectrum')!~ m/^\w_TPP08\./) {
    $element -> delete;
  }
}

答案 2 :(得分:0)

执行此操作的最“琐碎”方式是在输出其余内容时浏览文件并丢弃您不想要的元素。

  • 使用twig_roots来匹配正确的spectrum_query元素,并对它们不执行任何操作,从而有效地丢弃它们,
  • 使用twig_print_outside_roots
  • 让XML的其余部分按原样输出

这将非常节省内存,因为内存中几乎没有任何内容。

#!/usr/bin/env perl

use strict;
use warnings;

use autodie qw(open);

use XML::Twig;

my $target = 'TPP08';
my $input  = 'test.xml';
my $output = 'output.xml';
open( my $out, '>:utf8', $output);

XML::Twig->new( twig_roots          => { qq{spectrum_query[\@spectrum=~/^[^_]*_$target\./]} => 1, },
                twig_print_outside_roots => $out,
              )
         ->parsefile( $input);

请注意,每个丢弃的元素都会在输出中产生一个空行,白色空间管理很棘手。如果重要,您可以使用grep -v或使用xml_pp删除那些。