有没有办法从文件中获取(很多)值来使用xmlstarlet过滤大的xml?

时间:2013-10-08 09:55:38

标签: xml xmlstarlet blast

大家。 我正在尝试过滤一个大的xml文件(来自BLAST),以便只保留由我从文件定义的<Interaction>值列表定义的一些<Iteration_iter-num>个节点。这是一个简化的例子(真正的Blast.xml有超过80000次迭代):

<?xml version="1.0"?>
<!DOCTYPE BlastOutput PUBLIC "-//NCBI//NCBI BlastOutput/EN" "http://www.ncbi.nlm.nih.gov/dtd/NCBI_BlastOutput.dtd">
<BlastOutput>
  <BlastOutput_program>blastx</BlastOutput_program>
   <BlastOutput_iterations>
    <Iteration>
      <Iteration_iter-num>3037</Iteration_iter-num>
      <Iteration_query-ID>Query_3037</Iteration_query-ID>

    </Iteration>
    <Iteration>
      <Iteration_iter-num>5673</Iteration_iter-num>
      <Iteration_query-ID>Query_5673</Iteration_query-ID>

    </Iteration>
    <Iteration>
      <Iteration_iter-num>11397</Iteration_iter-num>
      <Iteration_query-ID>Query_11397</Iteration_query-ID>

    </Iteration>
    <Iteration>
      <Iteration_iter-num>15739</Iteration_iter-num>
      <Iteration_query-ID>Query_15739</Iteration_query-ID>
    </Iteration>
  </BlastOutput_iterations>
</BlastOutput>

我有一个要保留的迭代文件(保存为keep_iter):

5673
11397

对于这种低规模问题,我设法使用xmlstarlet进行过滤,首先创建一个文件版本来存储用于比较的字符串(保存为过滤器):

Iteration_iter-num!=5673 and Iteration_iter-num!=11397

这可以作为魅力:

cat Blast.xml | xmlstarlet ed -d "/BlastOutput/BlastOutput_iterations/Iteration[`cat filter`]" > finalBlast.xml

基本上,我删除了不在过滤器文件中的所有迭代节点 获得:

   <?xml version="1.0"?>
<!DOCTYPE BlastOutput PUBLIC "-//NCBI//NCBI BlastOutput/EN" "http://www.ncbi.nlm.nih.gov/dtd/NCBI_BlastOutput.dtd">
<BlastOutput>
  <BlastOutput_program>blastx</BlastOutput_program>
   <BlastOutput_iterations>
    <Iteration>
      <Iteration_iter-num>5673</Iteration_iter-num>
      <Iteration_query-ID>Query_5673</Iteration_query-ID>

    </Iteration>
    <Iteration>
      <Iteration_iter-num>11397</Iteration_iter-num>
      <Iteration_query-ID>Query_11397</Iteration_query-ID>

    </Iteration>
  </BlastOutput_iterations>
</BlastOutput>

问题是我确实有一个带有20000个值的keep_iter文件来过滤。当我创建过滤器文件并运行上面的xmlstarlet命令时,参数显然太长了。

有关过滤此类Blast.xml文件的建议,只保留那些迭代编号列在keep_iter文件中的迭代节点(具有20k值)?我想保留原始的xml结构。

1 个答案:

答案 0 :(得分:0)

对于像这样的大型文件,我会考虑使用更流式的方法,例如使用类似Perl的XML::Twig

#!/usr/bin/env perl

use XML::Twig;

my %keep = ();
open(KEEP, "keep_iter") or die "Couldn't open keep_iter";
while(<KEEP>) {
  chomp;
  $keep{$_} = 1;
}
close(KEEP);

my $t = XML::Twig->new(
  twig_roots => { 'Iteration' => \&process_iter },
  twig_print_outside_roots => 1,
  keep_spaces => 1,
);

$t->parsefile('Blast.xml');

sub process_iter {
  my ($t, $iter) = @_;
  if($keep{$iter->first_child_text('Iteration_iter-num')}) {
    $t->flush; # if it was in keep_iter, keep it
  } else {
    $t->purge; # otherwise don't
  }
}