【问题标题】:How to extract and transform XML into a Perl data structure如何提取 XML 并将其转换为 Perl 数据结构
【发布时间】:2011-12-15 02:00:23
【问题描述】:

我的文件夹中有 xml 文件,我需要从 xml 文件中提取一些信息并存储在哈希中。我的 xml 文件看起来像这样

<?xml version="1.0" encoding="UTF-8"?>
<Servicemodule xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<Service Id="478" Name="Pump Motor">
<Description>It delivers actual pump speed</Description>
<ServiceCustomers>
   <SW Service="SKRM" Path="/work/hr_service.xml"/>
</ServiceCustomers>
<ServiceSuppliers>
   <HW Type="s" Nr="12" Service="1" Path="/work/hardware.xml"/>
   <HW Type="v" Nr="2" Service="1" Path="/work/hardware.xml"/> 
   <HW Type="mt" Nr="1" Service="1" Path="/work/hardware.xml"/>
 </ServiceSuppliers>
 </Service>
 </Servicemodule>

我想将此信息保存在像服务 ID 这样的哈希中作为键,并将扩孔信息作为该键的哈希值数组。服务客户和供应商元素中的软件和硬件属性是哈希键(服务 ID)的值数组。这对专家来说很容易,但我是新手,所以这个问题困扰着我。 我试过这样

use strict;
use warnings;
use feature ':5.10';
use XML::Twig;
use File::Find;

my $num=0;
my %combeh;
my $dir="V:/Main/work";
find(\&wanted, $dir);
 sub wanted() {
    if ( -f and /(_service\.xml)$/) {# find all the files with a suffix of .xml                                          
 my $tweak_server =sub{
                my @bhi;                                                                                       
    my ($twig, $root) =@_;                                                                                     
    my $code=$root->first_child_text('Service Id');                                                                                 
    my $ser=$root->first_child('ServiceCustomers');                                                                                      
    my $ser_cnt=$root->first_child_text('SW');
     my $ser1=$root->first_child('ServiceSuppliers');                                                                                      
    my $ser1_cnt=$root->first_child_text('HW');                                                                                      
    if ($ser){                                                                                                                      
    push (@bhi, $ser->toString,$File::Find::name);                                                                                                                     
       $combeh{$code}=[@bhi];
         }
       if ($ser1){                                                                                                                     
    push (@bhi, $ser1->toString,$File::Find::name);                                                                                                                    
       $combeh{$code}=[@bhi];           
            };
        my $roots = { Service => 1 };
  my $handlers = { 'Servicemodule/Service' => $tweak_server,                                                                                                                                                                             
                       };
       my $twig = new XML::Twig(TwigRoots => $roots,                                                                                                                                                                                                           
                             TwigHandlers => $handlers,                                                                                                                                                                                                          
                               pretty_print  => 'indented'                                                                                                                                                                            
                               );
               $twig->parsefile($_);                                                                                      
                             }                       
                       }
               return (%combeh) ;
                }

我无法使用上面的脚本创建我想要的哈希。请帮助我编写脚本如何获取属性值并存储在这样的哈希中 输出这样的需求

 '478'=>[
          {
          Description='It delivers actual pump speed'
          }
         {
           Service='SKRM',
           Path='/work/hr_service.xml'
          }
          {
             Type='s'.
             Nr='12',
             Service='s',
             path='/work/hardware.xml'
           }

          {
             Type='v'.
             Nr='2',
             Service='s',
             path='/work/hardware.xml'
           }
          {
             Type='mt'.
             Nr='1',
             Service='1',
             path='/work/hardware.xml'
           }
         ...
          ...
          ....

请帮我解决这个问题。

提前致谢。

在你的建议下我试过这样

#!/usr/bin/perl
 use warnings;
 use strict;
 use XML::Simple;
 use Carp;
 use File::Find;
 use File::Spec::Functions qw( canonpath );     
 use Data::Dumper;

 my @ARGV ="C:/Main/work";die "Need directories\n" unless @ARGV;
 find(
  sub {
     return unless ( /(_service\.xml)$/ and -f );
     extract_information();
    return;
  },
 @ARGV
  );

sub extract_information {
         my $path= $_;

my $xml=XMLin($path);
   my $xml_services = $xml->{Service};  
   my %services;
   for my $xml_service (@$xml_services) {

    my %service = (
        description     => $xml_service->{Description},
        name            => $xml_service->{Name},
        id              => $xml_service->{Id},
    );

     $service{sw} = _maybe_list( $xml_service->{ServiceCustomers}{SW} );
    $service{hw} = _maybe_list( $xml_service->{ServiceSuppliers}{HW} );
    $service{sw} = _maybe_list( $xml_service->{ServiceSuppliers}{SW} );
     $services{ $service{id} } = \%service;
 }

 print Dumper \%services;

  }
 sub _maybe_list {
 my $maybe = shift;
 return ref $maybe eq 'ARRAY' ? $maybe : [$maybe];
 }

感谢您的回复,我是 XML::Simple 的新手,我研究了该模块并且理解您的脚本。但是,当我运行您的代码时,我在 for 循环行中收到类似“不是数组引用”的错误。我尝试了不同的方法来克服这个问题,但仍然是同样的错误。有时我在 ServiceSuppliers 中有 SW 和 HW 属性。因此,我又添加了一行与您的格式相同的行。我有一个问题您说“如果 XML 中有一个元素,它将不会被包装”,但有时在 ServiceCustomers 中我只有一个元素具有一些属性,如我在我的 xml 文件中显示的那样。可以吗?或者我该怎么办?你能帮我解决这些问题吗?

请任何人帮我解决这个错误。

【问题讨论】:

  • L7a 来自哪里?为什么在 XML 中设置了各种 Path 值,而在您的输出中设置了 ------
  • 请修正缩进,并删除隔行后的空行。

标签: xml perl


【解决方案1】:

如果 XML 文件不是太大,您可以使用 XML::Simple 更轻松地对其进行转换。

XML::Simple 的优点是操作 Perl 数据结构比 XML 方便得多。

缺点是它会消耗更多内存,因为它必须将整个 XML 文件加载到内存中。它对 XML 中的大小写也很敏感。

use strict;
use warnings;

use XML::Simple;
use Data::Dumper;

process_service_xml(shift);

sub process_service_xml {
    my $xml = XMLin(shift);

    # Illustrating what you've got after XML::Simple processes it.
    print "******* XML::Simple input ********\n";
    print Dumper $xml;
    print "**********************************\n";

    # Pull out the Services
    my $xml_services = $xml->{Service};

    # Iterate through each Service to transform them
    my %services;
    for my $xml_service (@$xml_services) {
        # Pull out the basic information
        my %service = (
            description     => $xml_service->{Description},
            name            => $xml_service->{Name},

            # Redundant with the key, but useful to keep all the data about the
            # service in one place.
            id              => $xml_service->{Id},
        );

        # Get SW and HW as their own attributes.
        # If there's a single element in the XML it won't be wrapped in
        # an array, so make sure each are a list.
        $service{sw} = _maybe_list( $xml_service->{ServiceCustomers}{SW} );
        $service{hw} = _maybe_list( $xml_service->{ServiceSuppliers}{HW} );

        # Store the service in the larger hash, keyed by the ID.
        $services{ $service{id} } = \%service;
    }

    # And here's what the information has been transformed into.
    print "******* Services ********\n";
    print Dumper \%services;
    print "*************************\n";    
}

sub _maybe_list {
    my $maybe = shift;
    return ref $maybe eq 'ARRAY' ? $maybe : [$maybe];
}

【讨论】:

  • 我在你的脚本中有小错误和小疑问,你能看看我编辑过的问题吗,因为我按照你说的那样尝试了,但是我遇到了小错误,我展示了我在你的建议后尝试的内容。请你帮忙解决这个问题。
  • 我正在寻求你的帮助,请帮助我。
  • @verendra 1) “不是数组引用”即将到来,因为 XML 文档没有服务条目,因此 $xml_services 为空。在这种情况下,您应该将其初始化为空数组 ref 或仅从例程返回。 2) 你额外的 SW 条目超过了之前的条目。使用push 附加到它。 3) _maybe_list 处理ServiceCustomersServiceSuppliers 只有一个条目的情况。您可以在第一个数据转储中看到它。我将留给您编写修复代码,这开始有点像“为我编写代码”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-09-26
  • 1970-01-01
  • 2013-01-14
  • 1970-01-01
  • 2021-02-25
  • 2015-02-05
  • 1970-01-01
相关资源
最近更新 更多