在 Perl 中,XML::Simple 无法取消引用由 Data::Dumper 解析的多维关联数组
In Perl, XML::Simple is not able to dereference multi dimensional associative array parsed by Data::Dumper
以下是我要解析的 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";
}
}
}
}
}
}
}
我收到此错误:第 28 行 ppfe.pl 不是 ARRAY 引用。(在 foreach $body (@{$data->{body}})
)
我想访问 <entry></entry>
的每个数据。上面的代码只是访问 'Description' 列。怎么做?
参考上述问题,
我无法提取每个 <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
.
.
.
.
.
.
.
不要使用 XML::Simple
。
连XML::Simple
都说"don't use XML::Simple
".
The use of this module in new code is discouraged. Other modules are available which provide more straightforward and consistent interfaces.
试试这样:
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
来查找和打印匹配规范的节点 - 这有效 'as you go' 这在处理大 XML,或者如果你想在处理之前编辑它。
但是,它还允许您 'handle' 之后的数据:
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") )
虽然回答你的问题:
Above code only is only accessing the 'Description' column. How to do that?
那是因为你这样做了:
foreach $entry ((@{$row->{entry}})->[3])
例如尝试获取 entry
数组中的第 4 个元素,即 Description
。
参考评论 - 我建议您将 'entries' 转换为 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
。
- 使用 "header" 行将其转换为散列。
- 打印与特定键匹配的散列值
$column_to_show
。
根据您对数据的处理是否多于打印数据,您可以将其转换为数组散列或类似内容。
或者您可以只打印 $row_entries[3]
而不是当然 ;)。
使用适当的 XML 解析模块总是更快更准确,它允许您使用 XPath 表达式XML 访问 XML 数据
这是一个使用 [XML::Twig
][XML::Twig]
的解决方案
我不确定您在 <b>
...</b>
中的 粗体 字段是什么意思,因为示例数据中只有一个你展示了,但我已经使用 XPath //body/p/b
访问了它并在输出
的开头打印了它
输出的其余部分是我使用 //table/tgroup/tbody/row
访问的每个 <row>
中的 <entry>
元素的值。第一行的内容作为字段名来标注后面的值
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.
---
以下是我要解析的 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";
}
}
}
}
}
}
}
我收到此错误:第 28 行 ppfe.pl 不是 ARRAY 引用。(在 foreach $body (@{$data->{body}})
)
我想访问 <entry></entry>
的每个数据。上面的代码只是访问 'Description' 列。怎么做?
参考上述问题,
我无法提取每个 <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
.
.
.
.
.
.
.
不要使用 XML::Simple
。
连XML::Simple
都说"don't use XML::Simple
".
The use of this module in new code is discouraged. Other modules are available which provide more straightforward and consistent interfaces.
试试这样:
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
来查找和打印匹配规范的节点 - 这有效 'as you go' 这在处理大 XML,或者如果你想在处理之前编辑它。
但是,它还允许您 'handle' 之后的数据:
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") )
虽然回答你的问题:
Above code only is only accessing the 'Description' column. How to do that?
那是因为你这样做了:
foreach $entry ((@{$row->{entry}})->[3])
例如尝试获取 entry
数组中的第 4 个元素,即 Description
。
参考评论 - 我建议您将 'entries' 转换为 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
。 - 使用 "header" 行将其转换为散列。
- 打印与特定键匹配的散列值
$column_to_show
。
根据您对数据的处理是否多于打印数据,您可以将其转换为数组散列或类似内容。
或者您可以只打印 $row_entries[3]
而不是当然 ;)。
使用适当的 XML 解析模块总是更快更准确,它允许您使用 XPath 表达式XML 访问 XML 数据
这是一个使用 [XML::Twig
][XML::Twig]
我不确定您在 <b>
...</b>
中的 粗体 字段是什么意思,因为示例数据中只有一个你展示了,但我已经使用 XPath //body/p/b
访问了它并在输出
输出的其余部分是我使用 //table/tgroup/tbody/row
访问的每个 <row>
中的 <entry>
元素的值。第一行的内容作为字段名来标注后面的值
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.
---