免费注册 查看新帖 |

Chinaunix

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

优化有酬劳,如何读取XML同名标签个数不确定里的内容? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-09-27 21:09 |只看该作者 |倒序浏览
我是一个初学者,还有很多不懂的地方,请赐教。
现在,我读取的方法是先判断同名标签的个数,判断后分为两种情况:一个或多个,多个的再给循环顺序分别读取内容,如果有二级标签,又要判断标签的个数,判断后再分为两种情况:一个或多个,如此往复。如果有两级标签,就要写四次代码,如果三级标签,就要有写八次代码,也就是2的n次方,太冗余了,请高手指教,想话费酬劳!例子如下:
这个XML里有同级同名标签<device>出现两次,而在一个<device>里<host>出现三次,我就要判断<device>的个数,以及<host>的个数,要写四次代码,请优化!
<?xml version="1.0" encoding="GBK"?>
<function funcname="gray_list" mode="predefined" no="no">
  <task_name>20130506113902_989513309</task_name>
  <device>
    <device_name>202.197.12.199</device_name>
    <interface_name>gei-0/2</interface_name>
    <commited_information_rate>5000</commited_information_rate>
    <host>
      <ip>192.168.1.1</ip>
      <mask>255.255.255.0</mask>
    </host>
    <host>
      <ip>192.168.45.115</ip>
      <mask>255.255.255.0</mask>
    </host>
    <host>
      <ip>192.168.54.112</ip>
      <mask>255.255.255.0</mask>
    </host>
  </device>
  <device>
    <device_name>202.197.12.200</device_name>
    <interface_name>gei-0/1</interface_name>
    <commited_information_rate>10000</commited_information_rate>
    <host>
      <ip>172.168.2.1</ip>
      <mask>255.255.255.0</mask>
    </host>
    <host>
      <ip>172.168.2.15</ip>
      <mask>255.255.255.0</mask>
    </host>
    <host>
      <ip>172.168.5.12</ip>
      <mask>255.255.255.0</mask>
    </host>
  </device>  
</function>

求职 : 软件工程师
论坛徽章:
3
程序设计版块每日发帖之星
日期:2015-10-07 06:20:00程序设计版块每日发帖之星
日期:2015-12-13 06:20:00程序设计版块每日发帖之星
日期:2016-05-05 06:20:00
2 [报告]
发表于 2013-09-27 23:17 |只看该作者
本帖最后由 104359176 于 2013-09-27 23:21 编辑
  1. #!perl

  2. use 5.010;
  3. use XML::Simple qw(XMLin XMLout);
  4. use YAML qw(Dump);

  5. my @lines = <DATA>;
  6. my $text = join '', @lines;
  7. my $xml_data = XMLin($text);

  8. show_keys($xml_data);

  9. sub show_keys {
  10.         my ($data, $meta) = @_;
  11.         if (defined $meta) {
  12.                 $meta = "$meta -> ";
  13.         }
  14.         else {
  15.                 $meta = '';
  16.         }
  17.         # return if (ref($data) ne ref([]));
  18.         foreach my $key (keys $data) {
  19.                 my $value = $data->{$key};
  20.                 if (ref($value) eq ref([])) {
  21.                         my $values_amount = scalar @$value;
  22.                         say "Tag:<$meta $key> occur $values_amount times";
  23.                         foreach my $n (@$value) {
  24.                                 show_keys($n, $key);
  25.                         }
  26.                 }
  27.         }
  28. }

  29. __DATA__
  30. <function funcname="gray_list" mode="predefined" no="no">
  31.   <task_name>20130506113902_989513309</task_name>
  32.   <device>
  33.     <device_name>202.197.12.199</device_name>
  34.     <interface_name>gei-0/2</interface_name>
  35.     <commited_information_rate>5000</commited_information_rate>
  36.     <host>
  37.       <ip>192.168.1.1</ip>
  38.       <mask>255.255.255.0</mask>
  39.     </host>
  40.     <host>
  41.       <ip>192.168.45.115</ip>
  42.       <mask>255.255.255.0</mask>
  43.     </host>
  44.     <host>
  45.       <ip>192.168.54.112</ip>
  46.       <mask>255.255.255.0</mask>
  47.     </host>
  48.   </device>
  49.   <device>
  50.     <device_name>202.197.12.200</device_name>
  51.     <interface_name>gei-0/1</interface_name>
  52.     <commited_information_rate>10000</commited_information_rate>
  53.     <host>
  54.       <ip>172.168.2.1</ip>
  55.       <mask>255.255.255.0</mask>
  56.     </host>
  57.     <host>
  58.       <ip>172.168.2.15</ip>
  59.       <mask>255.255.255.0</mask>
  60.     </host>
  61.     <host>
  62.       <ip>172.168.5.12</ip>
  63.       <mask>255.255.255.0</mask>
  64.     </host>
  65.   </device>  
  66. </function>
复制代码
---------------------------------output------------------------------------
C:\WINDOWS\system32\cmd.exe /c perl Parse-xml.pl
Tag:< device> occur 2 times
Tag:<device ->  host> occur 3 times
Tag:<device ->  host> occur 3 times
Hit any key to close this window...

论坛徽章:
0
3 [报告]
发表于 2013-09-28 00:27 |只看该作者
回复 2# 104359176


    首先感谢你的耐心指导,我可能还没有完全表达出我的意图,我想要的是取出键值,而不是统计出现几次,如:
情形一:
    <device>
    <device_name>202.197.12.199</device_name>
    <interface_name>gei-0/2</interface_name>
    <commited_information_rate>5000</commited_information_rate>
    <host>
      <ip>192.168.1.1</ip>
      <mask>255.255.255.0</mask>
    </host>   
  </device>
我想要的是202.197.12.199, gei-0/2, 5000, 192.168.1.1, 255.255.255.0

情形二:
<device>
    <device_name>202.197.12.199</device_name>
    <interface_name>gei-0/2</interface_name>
    <commited_information_rate>5000</commited_information_rate>
    <host>
      <ip>192.168.1.1</ip>
      <mask>255.255.255.0</mask>
    </host>
    <host>
      <ip>192.168.45.115</ip>
      <mask>255.255.255.0</mask>
    </host>
    <host>
      <ip>192.168.54.112</ip>
      <mask>255.255.255.0</mask>
    </host>
  </device>
我想要的是202.197.12.199, gei-0/2, 5000, 192.168.1.1, 255.255.255.0,192.168.45.115, 255.255.255.0,192.168.54.112, 255.255.255.0

情形三:
<device>
    <device_name>202.197.12.199</device_name>
    <interface_name>gei-0/2</interface_name>
    <commited_information_rate>5000</commited_information_rate>
    <host>
      <ip>192.168.1.1</ip>
      <mask>255.255.255.0</mask>
    </host>   
  </device><device>
    <device_name>202.197.12.200</device_name>
    <interface_name>gei-0/1</interface_name>
    <commited_information_rate>10000</commited_information_rate>
    <host>
      <ip>192.168.2.1</ip>
      <mask>255.255.255.0</mask>
    </host>  
  </device>
我想要的是202.197.12.199, gei-02, 5000, 192.168.1.1, 255.255.255.0,202.197.12.200, gei-0/1, 10000, 192.168.2.1, 255.255.255.0

情形四:
<device>
    <device_name>202.197.12.199</device_name>
    <interface_name>gei-0/2</interface_name>
    <commited_information_rate>5000</commited_information_rate>
    <host>
      <ip>192.168.1.1</ip>
      <mask>255.255.255.0</mask>
    </host>
    <host>
      <ip>192.168.45.115</ip>
      <mask>255.255.255.0</mask>
    </host>
    <host>
      <ip>192.168.54.112</ip>
      <mask>255.255.255.0</mask>
    </host>
  </device>
<device>
    <device_name>202.197.12.199</device_name>
    <interface_name>gei-0/1</interface_name>
    <commited_information_rate>10000</commited_information_rate>
    <host>
      <ip>192.168.2.1</ip>
      <mask>255.255.255.0</mask>
    </host>
    <host>
      <ip>192.168.25.115</ip>
      <mask>255.255.255.0</mask>
    </host>
    <host>
      <ip>192.168.24.112</ip>
      <mask>255.255.255.0</mask>
    </host>
  </device>
我想要的是202.197.12.199, gei-0/2, 5000, 192.168.1.1, 255.255.255.0,192.168.45.115, 255.255.255.0,192.168.54.112, 255.255.255.0
              202.197.12.199, gei-0/1, 10000, 192.168.2.1, 255.255.255.0,192.168.25.115, 255.255.255.0,192.168.24.112, 255.255.255.0


感谢再次指导,为盼!

论坛徽章:
0
4 [报告]
发表于 2013-09-28 02:22 |只看该作者
这不就是读取XML文件内容么?话费how much?
楼上已经提供模块了,自己遍历读吧

求职 : 软件工程师
论坛徽章:
3
程序设计版块每日发帖之星
日期:2015-10-07 06:20:00程序设计版块每日发帖之星
日期:2015-12-13 06:20:00程序设计版块每日发帖之星
日期:2016-05-05 06:20:00
5 [报告]
发表于 2013-09-28 09:59 |只看该作者
本帖最后由 104359176 于 2013-09-28 10:02 编辑

回复 3# capfsxl

这个模块是将 XML 保存成数组的哈希,哈希的键值没有固定顺序,不能按照楼主的要求顺序输出结果。如果想按照文本出现的顺序来解析值,就要自己做一个解析器。

使用递归,和深度没有关系,就不用代码去按照深度写了。



   

论坛徽章:
0
6 [报告]
发表于 2013-09-28 12:31 |只看该作者
把酬劳给二楼吧,修改一下就可用了!当然,给我也可以

论坛徽章:
0
7 [报告]
发表于 2013-09-28 12:45 |只看该作者
回复 5# 104359176

理解与深度没关系,但我生成的XML文档中,不确定有几个同名标签,例如我再简化一下:

1.只有一个<device>标签时,从外部输入的值只能为1:
__DATA__
  <device>
    <device_name>192.168.1.1</device_name>
  </device>  

解:
#!/usr/bin/perl
use strict;
use XML::Simple qw(XMLin);
my $device_num = $ARGV[0];       #$device_num =1
my @lines = <DATA>;
my $text = join '', @lines;
my $xml_data = XMLin($text);
my $device_name = $xml_data->{device}->{device_name};

my $config = <<END;
system-view
ip router $device_name
undo shutdown
return
END

print $config;

输出结果为:
system-view
ip router 192.168.1.1
undo shutdown
return


2.有两个及以上<device>标签时,从外部会有一个输入值为第几个<device>,1或2或3或更多,但不能大于<device>标签个数:
__DATA__
  <device>
    <device_name>192.168.2.1</device_name>
  </device>  
  <device>
    <device_name>192.168.3.1</device_name>
  </device>  
  <device>
    <device_name>192.168.4.1</device_name>
  </device>

解:
#!/usr/bin/perl
use strict;
use XML::Simple qw(XMLin);
my $device_num = $ARGV[0];       #$device_num =1或2或3
my @lines = <DATA>;
my $text = join '', @lines;
my $xml_data = XMLin($text);
my $device_name = $xml_data->{device}[$device_num-1]->{device_name};

my $config = <<END;
system-view
ip router $device_name
undo shutdown
return
END

print $config;

当外部输入的$device_num =1时
输出结果为:
system-view
ip router 192.168.2.1
undo shutdown
return

当外部输入的$device_num =2时
输出结果为:
system-view
ip router 192.168.3.1
undo shutdown
return

当外部输入的$device_num =3时
输出结果为:
system-view
ip router 192.168.4.1
undo shutdown
return

3.当<device>标签不确定时,或一个,或多个,就是将1和2两种情况合并:
我目前做的就是要加一个判断语句。想优化此方案!!!

解:
#!/usr/bin/perl
use strict;
use XML::Simple qw(XMLin);
my $device_num = $ARGV[0];       #$device_num =1
my @lines = <DATA>;
my $text = join '', @lines;
my $xml_data = XMLin($text);
my $device_list  = $xml_data->{device};
my $device_times = ref ($device_list) eq ref ([]) ? scalar(@$device_list) : 1;
   if ($device_times == 1 ){

my $device_name = $device_list->{device_name};

my $config = <<END;
system-view
ip router $device_name
undo shutdown
return
END

print $config;

                                     }else
                                     {
my $device_name = $xml_data->{device}[$device_num-1]->{device_name};

my $config = <<END;
system-view
ip router $device_name
undo shutdown
return
END

print $config;
                                      }



我就想优化的是第三种情况,能不能不判断标签个数,上面第二种情况包括不了第一种情况,如果光用第二种表达式的话,且xml文档中只有一个标签时,会报错,说没有数组,如何解决???请高手赐教!!!









论坛徽章:
0
8 [报告]
发表于 2013-09-28 13:01 |只看该作者
回复 6# iamlimeng

烦请高手看7楼的说明,盼解!
   

论坛徽章:
0
9 [报告]
发表于 2013-09-28 13:01 |只看该作者
回复 4# onepublic


    烦请看7楼说明,盼解!

求职 : 软件工程师
论坛徽章:
3
程序设计版块每日发帖之星
日期:2015-10-07 06:20:00程序设计版块每日发帖之星
日期:2015-12-13 06:20:00程序设计版块每日发帖之星
日期:2016-05-05 06:20:00
10 [报告]
发表于 2013-09-28 13:07 |只看该作者
回复 9# capfsxl

标签一样部分的是以数组的形式保存在数据结构中的,不一样的是用普通的字符串保存。

如果遇到数组,就展开,如果不是数组,就按值来输出。做一个判断 ref()

   
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP