免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 6084 | 回复: 9
打印 上一主题 下一主题

使用XML::Simple读取XML文件问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-09-06 10:40 |只看该作者 |倒序浏览
有这样一个XML文件(book.xml):

<?xml version="1.0" encoding="utf-8"?>
<books>

  <book>
    <name>perl</name>
    <cn>Learning Perl </cn>
    <date>2006-01</date>
  </book>

  <book>
    <name>shell</name>
    <cn>Bash Shell </cn>
    <date>2006-02</date>
  </book>

</books>

代码:

  1. #!/usr/bin/perl -w

  2. use strict;
  3. use XML::Simple;

  4. my $xmlfile    = "book.xml";
  5. my $config = eval { XMLin($xmlfile) };

  6. ## 这个 XML 文件中不止一条记录,所以可以使用
  7. ## $config->{"book"}->{<keyattr>}来访问对应记录的数据,比如

  8. ## 要获取书籍 perl 相关信息,可以使用
  9. print $config->{"book"}->{"perl"}{"cn"} . "\n";  
  10. print $config->{"book"}->{"perl"}{"date"} . "\n";

  11. ### 这里的 keyattr 就是 name 属性
  12. ### 上面语句将打印 Learning Perl 和 2006-01

  13. ## 但是,如果只有一条记录,也就是说将上面文件中
  14. #  <book>
  15. #   <name>shell</name>
  16. #   <cn>Bash Shell </cn>
  17. #   <date>2006-02</date>
  18. #  </book>
  19. ## 删除,那么要获取里面的数据,则无需指定 keyattr,即通过
  20. ## $config->{"book"}{<attr>}来访问对应记录的数据,比如

  21. print $config->{"book"}{"cn"};
  22. print $config->{"book"}{"date"};

  23. ## 不知道有没有办法强制即使只有一条记录时,也通过到 keyattr 的引用来访问数据,即
  24. ## print $config->{"book"}->{"perl"}{"cn"} 和
  25. ## print $config->{"book"}{"cn"} 输出一样的结果
复制代码


因为一条记录和多条记录的数据处理方式不同,不论在获取记录信息还是添加,删除新记录,
每次遇到这种情况都需要分开处理,非常的不方便。

不知道各位有何妙策?请多多指教,感激不尽!

论坛徽章:
0
2 [报告]
发表于 2006-09-06 11:01 |只看该作者
那就始终按照多条记录处理贝

论坛徽章:
0
3 [报告]
发表于 2006-09-06 11:07 |只看该作者
谢谢回复!

我也想到了这点,但是总有那么一种感觉:似乎有更好的办法来解决这个问题。

论坛徽章:
0
4 [报告]
发表于 2006-09-06 17:36 |只看该作者

回复 3楼 coolend 的帖子

Hi,

using Data::Dumper to study (or research :-)) the data structure.
read more about => perldoc perllol, perldoc perldsc

For example to manuplate the complex data structure:

  1. use strict;
  2. use XML::Simple;
  3. use Data::Dumper;

  4. my $config = eval { XMLin('book.xml') };
  5. print Dumper($config), "\n";

  6. my $bk = $config->{'book'};
  7. # how many books:
  8. print "total books: ", scalar keys %$bk, "\n";

  9. # get book name only;
  10. print "$_\n" foreach sort keys %$bk;

  11. # get first book's record only, but the bookname is unknown.
  12. my $bk_1 = (sort keys %$bk) [0];
  13. print "book 1: $bk_1\n";
  14. print "cn   : " . $bk->{$bk_1}->{cn} . "\n";
  15. print "date : " . $bk->{$bk_1}->{date} . "\n";
复制代码


regards, ulmer

论坛徽章:
0
5 [报告]
发表于 2006-09-06 20:05 |只看该作者
找到一个似乎更好的办法:

将单条记录的访问方式转换成多条记录的访问方式,即:


  1. use XML::Simple;
  2. use Data::Dumper;

  3. my $config = eval { XMLin("book.xml") };
  4. die "ERROR: $@" if ($@);

  5. foreach my $chunk (keys(%{ $config })) {

  6.     foreach (keys(%{ $config->{ $chunk } })) {

  7.         ### 如果含有多条记录,即元素是 HASH 引用,不做转换,跳到下一个
  8.         last if (ref($config->{ $chunk }->{ $_ }) eq "HASH");

  9.         ### 否则当只有一条记录处理,转换在这里进行
  10.         my $name = delete ($config->{ $chunk }->{"name"});
  11.         my $hashref = $config->{ $chunk };
  12.         $config->{ $chunk } = { $name => $hashref };
  13.         last;
  14.     }
  15. }

  16. print Dumper ($config);
复制代码


未转换前,数据结构为:

  1.     {
  2.         'book' => {
  3.                     'date' => '2006-01',
  4.                     'cn' => 'Learning Perl ',
  5.                     'name' => 'perl'
  6.                   }
  7.     };
复制代码


转换之后,数据结构为:

  1.     {
  2.           'book' => {
  3.                     'perl' => {
  4.                               'date' => '2006-01',
  5.                               'cn' => 'Learning Perl '
  6.                             }
  7.                      }
  8.     };
复制代码


这样,不管是多条记录还是单条记录,都可以通过
$config->{"book"}->{<keyattr>}{<attribute>} 来访问了

比如 print $config->{"book"}->{"perl"}{"cn"} 将输出 Learnning Perl

[ 本帖最后由 coolend 于 2006-9-6 20:14 编辑 ]

论坛徽章:
0
6 [报告]
发表于 2006-09-06 21:23 |只看该作者
原帖由 coolend 于 2006-9-6 20:05 发表
找到一个似乎更好的办法:

将单条记录的访问方式转换成多条记录的访问方式,即:

[code]
use XML::Simple;
use Data::Dumper;

my $config = eval { XMLin("book.xml") };
die "ERROR: ...


simplest way:
$bk = $config->{book};
# is one book record?
if (exists $bk->{name}) {
    print 'book: '. $bk->{name}, ', cn: '. $bk->{cn}. ', date; '. $bk->{date}. "\n";
} else {
    # process mutli-records
}

论坛徽章:
0
7 [报告]
发表于 2006-09-06 22:54 |只看该作者
Thanks, ulmer !

我的意思是想写一个通用的函数,不仅仅是读取数据,还有新增或修改都以统一的方式来进行,而不仅仅是输出。因为添加记录时,当前没有记录,只有一条记录或多条记录的情况都不一样,同样,删除时也不尽相同。

经过这样转换后,不管是读取/添加/新增,处理方式都一样,简化了操作。比如

打印: print $config->{"book"}->{"perl"}{"cn"} ;

增加: $config->{"book"}->{"newbook"}{"cn"} = "This is a New book"
       $config->{"book"}->{"newbook"}{"date"} = "2006-09"

删除: delete($config->{"book"}->{"newbook"});

这样操作完成后,再用 XMLOut 即可保存新的数据,如下:

  1. open FILE,">$xmlfile" || die "ERR: Cannot write xml file ! \n";
  2. print FILE XMLout($config, noattr => 1, rootName => "books",
  3.                   xmldecl => '<?xml version="1.0" encoding="utf-8"?>');
  4. close (FILE);
复制代码

论坛徽章:
0
8 [报告]
发表于 2006-09-06 23:58 |只看该作者
原帖由 coolend 于 2006-9-6 22:54 发表
Thanks, ulmer !

我的意思是想写一个通用的函数,...


Ok!
After reading perldoc XML::Simple, this module provides an option "ForceArray => 1"
in XMLin(XML_FILE, OPTIONS). It will parse same data structure and this method is more safe then above.
Try it:
[qoute]
$config = XMLin('book.xml', ForceArray => 1);
print Dumper $config;
[/quote]  

you will see no matter how many book's records (one or more then one),
the dumped data structure always same.

regards, ulmer

论坛徽章:
0
9 [报告]
发表于 2006-09-07 08:45 |只看该作者
ForceArray => 1 是强制某个元素的值为数组(即使是单个值),比如 author 属性有2个值

<author>ulmer</author>
<author>muddyboot</author>

那么 $config->{"book"}{"newbook"}{"author} = [ "ulmer","muddyboot" ];

如果只有一个值,则为:
$config->{"book"}{"newbook"}{"author"} = "ulmer";

但设置ForceArray 后,将变成:
$config->{"book"}{"newbook"}{"author"} = [ "ulmer" ];

论坛徽章:
0
10 [报告]
发表于 2006-09-07 16:16 |只看该作者
原帖由 coolend 于 2006-9-7 08:45 发表
ForceArray => 1 是强制某个元素的值为数组(即使是单个值),比如 author 属性有2个值
...


Yes! this is best way to keep SAME DATA STRUTURE from  a xml file and treat the record(s)
always as multi-list!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP