在使用将XML转换为哈希的Perl脚本时遇到问题

时间:2011-11-03 18:07:54

标签: perl

我有一个Perl脚本将下面的XML文件转换为哈希:

<university>
   <name>svu</name>
  <location>ravru</location>
 <branch>
  <electronics>
 <student name="xxx" number="12">
 <semester number="1"subjects="7" rank="2"/>
 </student>
 <student name="xxx" number="15">
 <semester number="1" subjects="7" rank="10"/>
 <semester number="2" subjects="4" rank="1"/>
  </student>
   <student name="xxx" number="16">
   <semester number="1"subjects="7" rank="2"/>
  <semester number="2"subjects="4" rank="2"/>
   </student>
</electronics>
  </branch>
   </university>.
          . 
          .
          .
          .
          .
<data>
  <student name="msr" number="1" branch="computers" />
   <student name="ksr" number="2" branch="electronics" />
  <student name="lsr" number="3" branch="EEE" />
  <student name="csr" number="4" branch="IT" />
   <student name="msr" number="5" branch="MEC" />
  <student name="ssr" number="6" branch="computers" />
  <student name="msr" number="1" branch="CIV" />
  .............................
   ..............................
    .....................
 </data>

如何为数据元素创建哈希表,名称和数字作为键,分支是该哈希值。我需要这个,因为有些学生名字相同,有些学生的编号相同。

通过使用此哈希密钥,我必须在大学节点中搜索学生,如果找到并打印每个学生的分支名称。

我在XML::Simple中编写了一些脚本,但无法创建哈希值。

 #!/usr/bin/perl
 use warnings;
 use strict;
 use Data::Dumper; 
 use XML::Simple;

 my $xml = new XML::Simple;
 my $data = $xml->XMLin("data.xml", forcearray => [ 'student' , 'semister' ],
                                    KeyAttr    => { student  => "+Name"  } );

 print Dumper($data);

通过使用数据转储器我打印孔xml信息。但我只需要打印数据节点元素,请帮我解决这个问题。

2 个答案:

答案 0 :(得分:1)

无需一起使用XML::SimpleXML::Fast。两者的表现基本相同。

为相同的功能调用多个XML解析器会以不良行为的形式引发麻烦,代码应该可以工作但不会和调试会让你牵着你的手,因为同名的方法正在相互踩踏脚趾。


对于这种情况,我会坚持使用XML::Fast

use strict;
use warnings;
use XML::Fast;

my $data = xml2hash 'data.xml', array => [ 'student', 'semester' ];

即使结构不完全是理想结构,$data也可以很容易地进行后处理和调味(毕竟它是一种数据结构)。

答案 1 :(得分:1)

我可能会编写自己的XML::Parser处理程序,将属性组合成键值(如果XML::Simple支持的话,我在文档中找不到它)。这个例子可以帮助你入门:

#!/usr/bin/perl
use strict;
use warnings;
use XML::Parser;
use Data::Dumper;

my %hash;

sub tag_start { my ($expat, $tagname) = (shift, shift);
    # attributes are now in @_
    my %a = grep { $_=$_=>shift } @_; # attribute hash for this tag
    my $context = join('/',$expat->context()) || '';

    if ($context eq 'xml/data') {
        if ($tagname eq 'student') {
            push @{($hash{"$a{name}:$a{number}"}||=[])}, $a{branch};
        }
    } elsif ($context eq ...) {
        ...
    }
}
my $p = new XML::Parser(Handlers => { Start=>\&tag_start });
$p->parsefile('file.xml');
print Dumper \%hash;

请注意,要实现此功能,我必须将XML封装在<xml>标记中并添加一些缺少的空格来清理XML:

<xml>
    <university>
        <name>svu</name>
        <location>ravru</location>
        <branch>
            <electronics>
                <student name="xxx" number="12">
                    <semester number="1" subjects="7" rank="2"/>
                </student>
                <student name="xxx" number="15">
                    <semester number="1" subjects="7" rank="10"/>
                    <semester number="2" subjects="4" rank="1"/>
                </student>
                <student name="xxx" number="16">
                    <semester number="1" subjects="7" rank="2"/>
                    <semester number="2" subjects="4" rank="2"/>
                </student>
            </electronics>
        </branch>
    </university>
    <data>
        <student name="msr" number="1" branch="computers" />
        <student name="ksr" number="2" branch="electronics" />
        <student name="lsr" number="3" branch="EEE" />
        <student name="csr" number="4" branch="IT" />
        <student name="msr" number="5" branch="MEC" />
        <student name="ssr" number="6" branch="computers" />
        <student name="msr" number="1" branch="CIV" />
    </data>
</xml>

结果:

$VAR1 = {
          'ksr:2' => [
                     'electronics'
                   ],
          'msr:1' => [
                     'computers',
                     'CIV'
                   ],
          'csr:4' => [
                     'IT'
                   ],
          'ssr:6' => [
                     'computers'
                   ],
          'msr:5' => [
                     'MEC'
                   ],
          'lsr:3' => [
                     'EEE'
                   ]
        };