XML to CSV with nested and definite elements in Perl

元气小坏坏 提交于 2020-01-06 06:04:01

问题


I need to convert my xml file to csv Format. But I in csv file I need not all Information fron the XML, just 2 elements (IP Address and id from device).

 #!/usr/bin/perl
 use strict;
 use warnings;
 use Data::Dumper;
 use XML::Simple;

  #Elements, that I want see in my csv
  my @Fields = qw{id, ipAddress};

  open(my $out, '>', 'output.csv') or die "Output: $!\n";
  print $out join(',', @Fields) . "\n";

  my $xml = XMLin('input.xml', ForceArray => ['entity']);
  foreach my $entity (@{$xml->{entity}}) {
  no warnings;
  print $out join(',', map{$_->{content}} @{$entity}{@Fields}) . "\n";

Input.xml


      <?xml version="1.0" ?>
          <queryResponse last="41" first="0" count="42" type="Devices" responseType="listEntityInstances" requestUrl="https://hostname/webacs/api/v1/data/Devices?.full=true" rootUrl="https://hostname/webacs/api/v1/data">
             <entity dtoType="devicesDTO" type="Devices" url="https://hostname/webacs/api/v1/data/Devices/20">
               <devicesDTO displayName="20" id="20">
               <clearedAlarms>1</clearedAlarms>
               <collectionDetail>&lt;status&gt;&lt;general code="SUCCESS"/&gt;&lt;/status&gt;</collectionDetail>
               <collectionTime>2017-03-30T09:47:07.606+02:00</collectionTime>
               <creationTime>2016-02-29T17:32:13.116+01:00</creationTime>
               <ipAddress>1.1.1.1</ipAddress>
               <location> </location>
               <majorAlarms>0</majorAlarms>
                <softwareType>IOS</softwareType>
                <softwareVersion>12.2(55)SE9</softwareVersion>
                <warningAlarms>0</warningAlarms>
             </devicesDTO>
          </entity>
          <entity dtoType="devicesDTO" type="Devices" url="https://hostname/webacs/api/v1/data/Devices/21">
               <devicesDTO displayName="21" id="21">
               <clearedAlarms>1</clearedAlarms>
               <collectionDetail>&lt;status&gt;&lt;general code="SUCCESS"/&gt;&lt;/status&gt;</collectionDetail>
               <collectionTime>2017-03-30T09:47:07.606+02:00</collectionTime>
               <creationTime>2016-02-29T17:32:13.116+01:00</creationTime>
               <ipAddress>2.2.2.2</ipAddress>
               <location> </location>
               <majorAlarms>0</majorAlarms>
                <softwareType>IOS</softwareType>
                <softwareVersion>12.2(55)SE9</softwareVersion>
                <warningAlarms>0</warningAlarms>
             </devicesDTO>
          </entity>
        </queryResponse> 

As result I have

 id, ipAddress
 ,
 ,

I am not sure that:

     my $xml = XMLin('input.xml', ForceArray => ['entity']);
     foreach my $entity (@{$xml->{entity}})

is right in my case. Should I do it with tag entity?


回答1:


When dealing with XML::Simple, it's always a good idea to use Data::Dumper first to look at the data structure.

foreach my $entity ( @{ $xml->{entity} } ) {
    print Dumper $entity;

This will show you:

$VAR1 = {
          'url' => 'https://hostname/webacs/api/v1/data/Devices/20',
          'type' => 'Devices',
          'dtoType' => 'devicesDTO',
          'devicesDTO' => {
                          'displayName' => '20',
                          'creationTime' => '2016-02-29T17:32:13.116+01:00',
                          'warningAlarms' => '0',
                          'ipAddress' => '1.1.1.1',
                          'clearedAlarms' => '1',
                          'majorAlarms' => '0',
                          'collectionDetail' => '<status><general code="SUCCESS"/></status>',
                          'location' => {},
                          'collectionTime' => '2017-03-30T09:47:07.606+02:00',
                          'softwareType' => 'IOS',
                          'id' => '20',
                          'softwareVersion' => '12.2(55)SE9'
                        }
        };

So it's quite clear that your @Fields are in the wrong place. Those keys are not in $entity directly, but rather in $entity->{devicesDTO}.

There is also no need to use $_->{content} with the map. In fact, there are no content keys in that data structure.

foreach my $entity ( @{ $xml->{entity} } ) {
    print join( ',', @{ $entity->{devicesDTO} }{@Fields} ) . "\n";
}

This will produce the output

id,ipAddress
20,1.1.1.1
21,2.2.2.2

Note that you have a stray comma in your qw{} that you don't need. The idea of qw is that you do not need to use commas. You should also decide if you want your variables to have lower case letters or not. Mixing that is bad style, and the convention in Perl is to use snake case.

my @fields = qw{id ipAddress};


来源:https://stackoverflow.com/questions/48229571/xml-to-csv-with-nested-and-definite-elements-in-perl

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!