【问题标题】:Having trouble with Perl script that converts XML to hash将 XML 转换为哈希的 Perl 脚本遇到问题
【发布时间】:2011-12-21 10:31:09
【问题描述】:

我有一个 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 信息。但我只需要打印数据节点元素请帮助我如何做到这一点。

【问题讨论】:

    标签: perl


    【解决方案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;
    

    请注意,要使其正常工作,我必须通过将其包含在 &lt;xml&gt; 标记中并添加一些缺失的空格来稍微清理一下您的 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'
                       ]
            };
    

    【讨论】:

      【解决方案2】:

      没有必要同时使用XML::SimpleXML::Fast。两者的表现基本相同。

      为相同的功能调用多个 XML 解析器会带来一些麻烦,包括不希望出现的行为、应该可以工作但不能正常工作的代码,以及由于同名的方法会互相影响而导致的调试问题脚趾。


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

      use strict;
      use warnings;
      use XML::Fast;
      
      my $data = xml2hash 'data.xml', array => [ 'student', 'semester' ];
      

      即使结构不完全是所需的结构,$data 也可以轻松进行后处理和调味(毕竟它是一种数据结构)。

      【讨论】:

      • 我需要为数据节点元素创建哈希,而不是为学生和学期。你能建议我如何创建哈希,以该名称和数字作为键和分支作为值。
      猜你喜欢
      • 2021-07-13
      • 2012-11-11
      • 1970-01-01
      • 2022-01-04
      • 2013-07-09
      • 2012-10-07
      • 1970-01-01
      • 1970-01-01
      • 2016-07-25
      相关资源
      最近更新 更多