2

I'm trying to save HTTPs with IDs, like this one

https://hostname:9060/ers/config/networkdevice/1

in 'output.csv'. After that I want use these links in my get requests to get more Information from Management System about device.

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<ns3:searchResult total="3" xmlns:ns5="ers.ise.cisco.com" xmlns:ers-v2="ers-v2" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ns3="v2.ers.ise.cisco.com">
  <ns3:resources>
    <ns5:resource id="1" 
        name="Device1">
        <link rel="self" href="https://hostname:9060/ers/config/networkdevice/1"
        type="application/xml"/>
    </ns5:resource>
    <ns5:resource id="2" 
        name="Device2">
        <link rel="self" href="https://hostname:9060/ers/config/networkdevice/2"
        type="application/xml"/>
    </ns5:resource>
    <ns5:resource id="3" 
        name="Device3">
        <link rel="self" href="https://hostname:9060/ers/config/networkdevice/3"
        type="application/xml"/>
    </ns5:resources>
</ns3:resources>
</ns3:searchResult>

But after using my Perl Script, my file is empty.

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

#NOTE: Update this to contain my elements  in  CSV      
my @Fields = qw{id};

my $xml = XMLin('Get_All_Prime.xml', ForceArray => ['link']);

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

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

open(my $out, '>', 'output.csv') or die "Output: $!\n";
foreach my $link ( @{ $xml->{link} } ) { 
    print $out join ( ',', @{$link->{href} }{@Fields} ) . "\n";
}

I'm not sure, that I use the right tag

 ForceArray => ['link']

But what should I use in this case?

StayCalm
  • 145
  • 2
  • 13
  • 1
    XML::Parser, the default parser for XML::Simple, doesn't support namespaces. Avoid the [all-around bad](https://stackoverflow.com/questions/33267765/why-is-xmlsimple-discouraged) parser XML::Simple. I recommend XML::LibXML. – ikegami Jan 15 '18 at 17:38
  • Possible duplicate of [XML to CSV with nested and definite elements in Perl](https://stackoverflow.com/questions/48229571/xml-to-csv-with-nested-and-definite-elements-in-perl) – Matt Jacob Jan 15 '18 at 17:50
  • What's your desired output? – Sobrique Jan 16 '18 at 13:36

1 Answers1

6

The standard, excellent libraries for XML are XML::LibXML and XML::Twig.

Please do not use XML::Simple. Long ago its own documentation said that

The use of this module in new code is discouraged.

and long ago its own author wrote up a detailed tutorial for XML::LibXML. Heed the advice.

An example with XML::LibXML

use warnings;
use strict;
use feature 'say';

use XML::LibXML;

my $file = shift @ARGV || 'Get_All_Prime.xml'

my $reader = XML::LibXML->new();
my $doc = $reader->load_xml(location => $file, no_blanks => 1);

my $xpath = '//ns3:searchResult/ns3:resources/ns5:resource/link';

my @links;
foreach my $node ($doc->findnodes($xpath)) {
    push @links, $node->findvalue('./@href');
}
say for @links;

This finds the <link ...> element first, as an example; or you can go directly for 'href'

my $xpath = '//ns3:searchResult/ns3:resources/ns5:resource/link/@href';
foreach my $href ($doc->findnodes($xpath) {
    push @links, $href->to_literal;
}

The XML::LibXML is a complete library with full support for working with XML. See this post and this post for where to start with its extensive and structured documentation.


I'll go out on a limb and assume that the desired CSV output file has lines link_url,id

my $outfile = 'output.csv';
open my $fh_out, '>', $outfile or die "Can't open $outfile: $!";
say $fh_out 'url,id';  # header

my $xpath = '//ns3:searchResult/ns3:resources/ns5:resource/link';
my @links;
foreach my $node ($doc->findnodes($xpath)) {
    #say $node->findvalue('./@href'), ' => ', $node->findvalue('../@id');
    push @links, [ map { $node->findvalue($_) } qw(./@href ../@id) ];
}
say $fh_out join ',', @$_  for @links;

For more extensive work with CSV use Text::CSV, a "thin wrapper" for Text::CSV_XS.

zdim
  • 64,580
  • 5
  • 52
  • 81
  • 1
    @StayCalm I don't see what you need to extract from the link and how that should go into CSV, but I hope that the above may be good enough. If you do need more detail, or something on CSV, let me know (and please edit the question with that info). – zdim Jan 15 '18 at 19:55
  • @StayCalm Added what I guess the desired output is. Please edit the question with a clear statement on it. – zdim Jan 15 '18 at 20:48
  • I see result in shell, but my output file contains just Header without https links. And I have with warning: Can't use string ("https://hostname:9060/ers/conf"...) as an ARRAY ref while "strict refs" in use at `say $fh_out join ',', @$_ for @links;` – StayCalm Jan 16 '18 at 15:07
  • @StayCalm The last code snippet is copied out of a test script. The `@$_` derefences the `[ ... ]` for each of `@links`, producing the list that is joined with `,`. It shouldn't throw that warning, and it should work? (Note, if you use the first (full) script, you can't use the last line from the last snippet to write to file -- that's when it _would_ throw that warning.) – zdim Jan 16 '18 at 18:31
  • @StayCalm I see the edit to the question, thank you. To clarify: it says that you want the url ... is it only that, no id as a separate CSV field? (If that is so you don't need the last code snippet in this answer.) – zdim Jan 16 '18 at 18:36