如何使用 grep 基于属性用 perl 解析 xml 文件
How to parse xml file with perl based on attribute using grep
我是 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>
我需要 parse/delete "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 之后的每个条目并将其与匹配的字符串进行比较,然后只保留满足该条件的节点。但是我无法用我的基本 perl 知识来解决这个问题。
任何帮助将不胜感激!谢谢
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>
您可以在属性上使用 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;
}
}
最 "twiggish" 的方法是遍历文件并丢弃不需要的元素,同时输出其余元素。
- 使用
twig_roots
匹配正确的 spectrum_query
元素,不对它们做任何事情,有效地丢弃它们,
- 让 XML 的其余部分按原样输出,使用
twig_print_outside_roots
这将非常节省内存,因为几乎没有任何内容会保留在内存中。
#!/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);
请注意,每个丢弃的元素都会在输出中产生一个空行,白色 space 管理很棘手。如果重要,您可以使用 grep -v
或使用 xml_pp
.
摆脱那些
我是 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>
我需要 parse/delete "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 之后的每个条目并将其与匹配的字符串进行比较,然后只保留满足该条件的节点。但是我无法用我的基本 perl 知识来解决这个问题。
任何帮助将不胜感激!谢谢
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>
您可以在属性上使用 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;
}
}
最 "twiggish" 的方法是遍历文件并丢弃不需要的元素,同时输出其余元素。
- 使用
twig_roots
匹配正确的spectrum_query
元素,不对它们做任何事情,有效地丢弃它们, - 让 XML 的其余部分按原样输出,使用
twig_print_outside_roots
这将非常节省内存,因为几乎没有任何内容会保留在内存中。
#!/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);
请注意,每个丢弃的元素都会在输出中产生一个空行,白色 space 管理很棘手。如果重要,您可以使用 grep -v
或使用 xml_pp
.