2

次の形式の XML ファイルがあります。

<testsuite name="Conformance">
 <testsuite name="Manageability">
  <testsuite name="MIBs">
   <testcase internalid="1" name="name1">...</testcase>
   <testcase internalid="2" name="name2">...</testcase>
  </testsuite>
 </testsuite>
</testsuite>

Perl のXML::Simpleを使用して、テストケースとそのパスのリストを取得しようとしています。この場合、結果は次のようになります。

Conformance/Manageability/MIBs
    name1
    name2

XML::Simple でこれを行うことはできますか? もしそうなら、呼び出しはどのようになりますか?

私の現在のスクリプト:

use strict;
use warnings;
use Data::Dumper;
#use XML::Twig;
use XML::Simple;

my $file = 'test.xml';

my $ref = XMLin($file);

print Dumper($ref);

いくつか試してみましたが、必要なものが得られないようです。返されたデータ構造を解析して必要なものを取得する方が簡単ですか?

4

4 に答える 4

2

XML::Twig を試したので、ここに解決策があります。が見つかると、testcaseそれが の最初のものかどうかをチェックしtestsuite、そうであれば、要素の祖先を使用してパスを出力します。次に、テスト ケースの名前を出力します。

2 注: aは、前の兄弟testcaseがない場合は最初のものであり、要素の祖先を内側の要素 (要素の親) から外側の要素 (ルート) に返すため、この場合は逆にする必要があります。リストを使用して、それらを目的の順序で取得します。testcaseancestors

ほら:

#!/usr/bin/perl

use strict;
use warnings;

use XML::Twig;

XML::Twig->new( twig_handlers => { testcase => \&test_case })
         ->parse( \*DATA);

sub test_case
  { my( $t, $test_case)= @_;
    if( ! $test_case->prev_sibling( 'testcase'))
      { # first test case, output the "path"
        print join( '/', map { $_->att( 'name') } reverse $test_case->ancestors( 'testsuite')), "\n";
      }
    print "    ", $test_case->att( 'name'),"\n";
  }

__DATA__
<testsuite name="Conformance">
 <testsuite name="Manageability">
  <testsuite name="MIBs">
   <testcase internalid="1" name="name1">...</testcase>
   <testcase internalid="2" name="name2">...</testcase>
  </testsuite>
 </testsuite>
</testsuite>
于 2012-04-05T07:55:17.897 に答える
2

を使用していXML::Simpleますか?そのモジュールの作成者の意見を聞いてください。

ただし、XML::Simple を使用しないことをお勧めします (知っておく必要があります - 私が書きました)。私は個人的に XML::LibXML を使用しています。

ソース: RE: XML::Simple によって生成された未知のデータ セットへのアクセスに関するヘルプ

自分に有利に働き、適切な方法を学びましょう。これは、ほとんどの場合、XML::LibXML. これは、PHP、Python、Ruby でも使用されている C ライブラリです。非常に UNIX と WINDOWS でコンパイルします。ポータブル。速い。標準 API。行く道。

于 2012-04-04T21:37:04.783 に答える
2

ここでは、再帰が最適です。

use strict;
use warnings;
use XML::LibXML qw( );

sub visit_testsuite {
   my ($testsuite_node, $parent_path) = @_;

   my $name = $testsuite_node->getAttribute('name');
   my $path = defined($parent_path) ? "$parent_path/$name" : $name;

   my @testcase_nodes = $testsuite_node->findnodes('testcase');
   if (@testcase_nodes) {
      print("$path\n");
      for my $testcase_node (@testcase_nodes) {
         printf("   %s\n", $testcase_node->getAttribute('name'));
      }
      print("\n");
   }

   for my $testsuite_child ($testsuite_node->findnodes('testsuite')) {
      visit_testsuite($testsuite_child, $path);
   }
}


my $doc  = XML::LibXML->load_xml( IO => \*DATA );
my $root = $doc->documentElement();

visit_testsuite($root);

__DATA__

<testsuite name="Conformance">
 <testsuite name="Manageability">
  <testsuite name="MIBs">
   <testcase internalid="1" name="name1">...</testcase>
   <testcase internalid="2" name="name2">...</testcase>
  </testsuite>
 </testsuite>
</testsuite>

ルートノードは実際にはノードであってはなりませんが、testsuiteそれはあなたが言ったものです。

于 2012-04-04T22:16:48.283 に答える
0

XML::Simple最も単純なケースを除いて、ほとんどすべての場合、「すべてをできるだけ単純にするのではなく、できるだけ単純にする」に違反しています。

testcase初めてあなたの要件を誤解したように見えるので、別の方法がありますが、最初にすべてのノードを見つけてから親までさかのぼるため、@ikegamiのソリューションよりもはるかに悪い結果になると思います。

#!/usr/bin/env perl

use strict; use warnings;
use XML::XPath;
use XML::XPath::XMLParser;

my $xp = XML::XPath->new(ioref => \*DATA);

my $nodeset = $xp->find('//testcase');

my %cases;

foreach my $node ($nodeset->get_nodelist) {
    my $current = $node;
    my @parents;

    while (defined(my $parent = $current->getParentNode)) {
        my $name = $parent->getAttribute('name');
        last unless defined $name;
        push @parents, $name;
        $current = $parent;
    }

    my $path = join('/', '', reverse @parents);

    push @{ $cases{ $path } }, $node->getAttribute('name');
}

for my $path (sort keys %cases) {
    print "$path\n";
    for my $case (sort @{ $cases{$path} }) {
        print "\t$case\n";
    }
}


__DATA__
<testsuite name="Conformance">
 <testsuite name="Manageability">
  <testsuite name="MIBs">
   <testcase internalid="1" name="name1">...</testcase>
   <testcase internalid="2" name="name2">...</testcase>
  </testsuite>
 </testsuite>
 <testsuite name="Yabadabadoo">
  <testsuite name="Da da da">
   <testcase internalid="1" name="name1">...</testcase>
   <testcase internalid="2" name="name2">...</testcase>
  </testsuite>
 </testsuite>
</testsuite>

出力:

/適合性/管理性/MIB
        名前1
        名前2
/コンフォーマンス/ヤバダバドゥ/ダダダ
        名前1
        名前2
于 2012-04-04T21:27:03.477 に答える