在Perl中,XML :: Simple无法解除引用Data :: Dumper解析的多维关联数组

时间:2015-07-21 13:16:37

标签: xml perl xml-parsing perl-module

以下是我要解析的xml文件:

<?xml version="1.0" encoding="UTF-8"?>

<topic id="yerus5" xmlns:ditaarch="http://dita.oasis-open.org/architecture/2005/">



<title/>
  <shortdesc/>
  <body>
<p><b>CCU_CNT_ADDR: (Address=0x004 Reset=32'h1)</b><table id="table_r5b_1xj_ts">
<tgroup cols="4">
  <colspec colnum="1" colname="col1"/>
  <colspec colnum="2" colname="col2"/>
  <colspec colnum="3" colname="col3"/>
  <colspec colnum="4" colname="col4"/>
  <tbody>
        <row>
          <entry>Field</entry>
          <entry>OFFSET</entry>
          <entry>R/W Access</entry>
          <entry>Description</entry>
        </row>
        <row>
          <entry>reg2sm_cnt</entry>
          <entry>15:0</entry>
          <entry>R/W</entry>
          <entry>Count Value to increment in the extenral memory at the specified location.
            Default Value of 1. A Count value of 0 will clear the counter value</entry>
        </row>
        <row>
          <entry>ccu2bus_endianess</entry>
          <entry>24</entry>
          <entry>R/W</entry>
          <entry>Endianess of the data structure bit</entry>
        </row>
        <row>
          <entry>ccu_lane_sel</entry>
          <entry>25</entry>
          <entry>R/W</entry>
          <entry>ccu_lane_sel bit. Indicates the lane selection bit of the 32-bit location to
            update</entry>
        </row>
        <row>
          <entry>ccu_rdinvalid</entry>
          <entry>26</entry>
          <entry>R/W</entry>
          <entry>ccu_rdinvalid bit. Indicates if the read value from the bus needs to be stored
            or not.</entry>
        </row>
      </tbody>
    </tgroup>
  </table></p>


</body>
</topic>

运行以下代码后:

#!/usr/bin/perl


# use module
use XML::Simple;
use Data::Dumper;

# create object
$xml = new XML::Simple(); #(KeyAttr=>[]);

# read XML file
$data = $xml->XMLin("test.xml");

# access XML data
print Dumper($data);



# dereference hash ref



    # foreach $b (@{$p->{b}})
    # {

# }
foreach $body (@{$data->{body}})
{
 foreach $p (@{$body->{p}})
 {
     foreach $table (@{$p->{table}})
     {

        foreach $tgroup (@{$table->{tgroup}})
        {

            foreach $tbody (@{$tgroup->{tbody}})
            {

                foreach $row (@{$tbody->{row}})
                {
                    foreach $entry ((@{$row->{entry}})->[3])
                    {
                    print $entry,"\n";
                    }

                }
            }
        }
    }
}

}

我收到此错误:不是ppfe.pl第28行的ARRAY参考。(在foreach $body (@{$data->{body}})

我想访问<entry></entry>的每个数据。以上代码仅访问“描述”列。怎么做?

参考上述问题,

我无法详细提取每个<b></b>文字的详细信息。以下是样本输出:

Name: CCU_CNT_ADDR: (Address=0x004 Reset=32'h1)
Field: reg2sm_cnt 
OFFSET: 15:0 
Access: R/W 
Description: Count Value to increment in the extenral memory at the specified location. Default Value of 1. A Count value of 0 will clear the counter value 
Filed: ccu2bus_endianess 
OFFSET: 24 
Access: R/W 
Description: Endianess of the data structure bit 
 .
 .
 .
 .
 .
 .
 .
Name: CCU_STAT_ADDR: (Address=0x008 Reset=32'h0) 
Field: fifo_cnt 
.
 .
 .
 .
 .
 .
 .

2 个答案:

答案 0 :(得分:2)

请勿使用XML::Simple

即使XML::Simple说'不要使用XML::Simple&#34;。

  

不鼓励在新代码中使用此模块。其他模块可用,提供更直接和一致的接口。

尝试这样的事情:

use strict;
use warnings;
use XML::Twig;

XML::Twig->new(
    'twig_handlers' => {
        'entry' => sub { print $_ ->text, "\n" }
    }
)->parsefile ('your_file.xml');

这将打印所有entry元素的文字内容,这似乎是您尝试做的事情?

XML::Twig有两个非常方便的机制 - 一个使用twig_handler来查找和打印符合规范的节点 - 这样可以随时使用&#39;这在处理大型XML时特别有用,或者如果要在处理之前编辑它。

但是,它还允许您处理&#39;之后的数据:

my $twig = XML::Twig->new( 'pretty_print' => 'indented_a' )->parsefile('your_xml_file');

foreach my $element ( $twig -> get_xpath ("//entry") )
{
    print $element ->text, "\n";
}

或者您可以像上面一样使用节点的完整路径:

$twig->root->get_xpath("body/p/table/tgroup/tbody/row/entry") )

回答你的问题:

  

以上代码仅用于访问&#39;说明&#39;柱。怎么做?

那是因为你这样做了:

foreach $entry ((@{$row->{entry}})->[3])

E.g。试图获取entry数组中的第4个元素,即Description

参考评论 - 我建议您转换您的条目&#39;到XML数据结构之外的哈希。

像这样:

use strict;
use warnings;
use XML::Twig;

use Data::Dumper;

my @headers;

my $column_to_show = 'Field';

sub process_row {
    my %entries;

    my ( $twig, $row ) = @_;
    my @row_entries = map { $_->text } $row->children;
    if (@headers) {
        @entries{@headers} = @row_entries;
        print $column_to_show, " => ", $entries{$column_to_show}, "\n";
    }
    else {
        @headers = @row_entries;
    }
}

my $twig = XML::Twig->new(
    'pretty_print' => 'indented_a',
    twig_handlers  => { 'row' => \&process_row }
)->parsefile ( 'your_file.xml' ); 

这是做什么的:

  • 触发每个row元素上的处理程序。
  • entry子元素(及其文本)提取到数组中。 @row_entries
  • 使用&#34;标题&#34;将其转换为哈希值的行。
  • 打印与特定键$column_to_show匹配的哈希值。

根据您是否正在使用数据而不是打印数据,您可以将其转换为数组或类似的哈希。

或者你可以打印$row_entries[3]而不是当然;)。

答案 1 :(得分:0)

使用适当的XML解析模块可以更快,更准确,允许您使用XPath表达式访问XML数据

这是使用[XML::Twig] [XML :: Twig]

的解决方案

我不确定您对<b> ... </b>粗体字段的含义,因为您显示的示例数据中只有一个,但我已经使用XPath //body/p/b访问了它并在输出的开头打印了它

输出的其余部分是我使用<entry>访问的每个<row>中的//table/tgroup/tbody/row元素的值。第一行的内容用作字段名称以标记后续值

use strict;
use warnings;
use 5.010;

use open qw/ :std :encoding(UTF-8) /;

use XML::Twig;
use List::Util qw/ max /;
use List::MoreUtils qw/ pairwise /;

my $twig = XML::Twig->new;
$twig->parsefile('topic.xml');

say $twig->findvalues('//body/p/b');
say '';

my (@fields, $size);
for my $row ( $twig->findnodes('//table/tgroup/tbody/row') ) {

  unless ( @fields ) {
    @fields = map "$_:", $row->findvalues('entry');
    $size = max map length, @fields;
    next;
  }

  my @values = $row->findvalues('entry');
  say for pairwise { sprintf '%-*s %s', $size, $a, $b } @fields, @values;
  say '---';
}

输出

CCU_CNT_ADDR: (Address=0x004 Reset=32'h1)

Field:       reg2sm_cnt
OFFSET:      15:0
R/W Access:  R/W
Description: Count Value to increment in the extenral memory at the specified location.
            Default Value of 1. A Count value of 0 will clear the counter value
---
Field:       ccu2bus_endianess
OFFSET:      24
R/W Access:  R/W
Description: Endianess of the data structure bit
---
Field:       ccu_lane_sel
OFFSET:      25
R/W Access:  R/W
Description: ccu_lane_sel bit. Indicates the lane selection bit of the 32-bit location to
            update
---
Field:       ccu_rdinvalid
OFFSET:      26
R/W Access:  R/W
Description: ccu_rdinvalid bit. Indicates if the read value from the bus needs to be stored
            or not.
---