Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

Re: how to get attribute values and store in a hash.

by kennethk (Abbot)
on Dec 09, 2011 at 19:05 UTC ( [id://942719]=note: print w/replies, xml ) Need Help??


in reply to how to get attribute values and store in a hash.

Please read How do I post a question effectively?. In particular, the code has significant complications that are unnecessary for the aspect which is providing you issues (finding files which are unlike to exist on a monk's drive, importing several unused modules) and fails to pass a basic compilation check (perl -c, see -c). Some other issues:
  1. Line 22 needs to be corrected - you have a syntax error in omitting a comma from your list assignment, and you likely meant to copy the contents of the argument array (@_) and not the default input variable ($_). That should read my ($path, $hash) = @_;. Of course, you call that function with no arguments, so that is likely not going to work very well for you.

  2. Your posted XML is not well-formed. You have an opening Servicelist tag but no closing one.

  3. You are interacting with your references incorrectly on lines 35 & 36. Read perlreftut for an intro to interacting with references.

  4. Single quotes do not interpolate whereas double quotes do, so on line 36 you likely mean "$elem2"; this is for your purposes a no-op since it should already be a string, so it would be better written as $elem2.

  5. Your Service element does not contain the attribute Id, and your Customermodules and Suppliermodules elements do not have Service attributes. It might do some good to review the difference between an element and an attribute -- see XML#Key_terminology.

This is an example script that takes the XML you have provided (modified to be well-formed) and extracts a list of type and nr attributes from the Hardwaremodule elements in Suppliermodules from the Service tags. It should hopefully give you an idea how to proceed, particularly when read with the documentation of XML::LibXML::Reader.

#!/usr/bin/perl use warnings; use strict; use XML::LibXML; use XML::LibXML::Reader; use Data::Dumper; my $hash_ref; my $reader = XML::LibXML::Reader->new( IO => *DATA ); while ( $reader->nextElement( 'Service' )) { my $number = $reader->getAttribute( 'Num'); $reader->nextElement( 'Suppliermodules' ); while ( $reader->nextElement( 'Hardwaremodule' )) { my $module = {}; $module->{type} = $reader->getAttribute('Type'); $module->{nr} = $reader->getAttribute('Nr'); push @{$hash_ref->{$number}}, $module; } } print Dumper $hash_ref; __DATA__ <?xml version="1.0" encoding="UTF-8"?> <Servicelist xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi +:noNamespaceSchemaLocation="file:///files/service.xsd"> <Service Num="B7a" Name="temperature sensor"> <Des>It delivers actual temperature in the form ov Volts</Des> <Customermodules> <Softwaremodule Service="ADC" Path="/main/ADCservice.xml"/> </Customermodules> <Suppliermodules> <Softwaremodule Service="input" Path="/main/inputservice.xml"/> <Softwaremodule Service="signal" Path="/main/signalservice.xml"/> <Hardwaremodule Type="engine" Nr="18" Servicenum="1" Path="/main/e +ngineservice.xml"/> <Hardwaremodule Type="motor" Nr="7" Servicenum="1" Path="/main/mo +torservice.xml"/> <Hardwaremodule Type="supply" Nr="1" Servicenum="1" Path="/main/sup +plyservice.xml"/> </Suppliermodules> </Service> </Servicelist>

Replies are listed 'Best First'.
Re^2: how to get attribute values and store in a hash.
by veerubiji (Sexton) on Dec 13, 2011 at 16:02 UTC

    Hi, I am sorry for my mistakes. Thanks for your suggestion. I tried as you said but still problem is there, I am showing what I tried as below

    #!/usr/bin/perl use warnings; use strict; use Carp; use File::Find; use File::Spec::Functions qw( canonpath ); use XML::LibXML::Reader; use Data::Dumper; my @ARGV ="c:/main/folder"; die "Need directories\n" unless @ARGV; my $Number; my %hash; find( sub { my $file = $_; # my $path = canonpath $File::Find::name; my $path =$_; return unless -f $path; return unless $file =~ /(_service\.xml)$/; extract_information($path, \%hash); return; }, @ARGV ); sub extract_information { my( $path, $hash)=@_; my $ret = open my $xmlin, '<', $path; unless ($ret) { carp "Cannot open '$path': $!"; return; } my $reader = XML::LibXML::Reader->new(IO => $xmlin); unless ($reader) { carp "Cannot create reader using '$path'"; return; } while ( $reader->nextElement( 'Service' )) { my $Number = $reader->getAttribute( 'num'); $reader->nextElement( 'Suppliermodules' ); while ( $reader->nextElement( 'Hardwaremodule' )) { my $module = {}; $module->{type} = $reader->getAttribute('Type'); $module->{nr} = $reader->getAttribute('Nr'); push @{$hash->{$Number}}, $module; } while ( $reader->nextElement( 'softwaremodule' )) { my $module1 = {}; $module1->{service} = $reader->getAttribute('Service'); push @{$hash->{$Number}}, $module1; } $reader->nextElement( 'customermodules' ); while ( $reader->nextElement( 'softwaremodule' )) { my $module2 = {}; $module2->{cusservice} = $reader->getAttribute('Service'); push @{$hash->{$Number}}, $module2; } } close $xmlin or carp "Cannot close '$path': $!"; return; } print Dumper \%hash;

    I tried with find(\&wanted, @directories); to search directives But I have some difficulties with that so I fallowed my procedure.What I want to do is I need to create hash with service num as the key and and all information of software module and hardware module attributes in customer and supplier module elements are array of values for that key. here I have two elements customer and supplier modules so I think array of values in a hash value.So finally after running this script I need to look my hash like (Service num attribute as the key and remaining information as the array of values for that key. so I have all service nums as the keys and its information is array of values.) I tried like that in the above script but it doesn't give any errors.I am not getting exact output, it giving some element attributes and some service num's only.I am new to perl, I am not able to produce what I want, please help me with that. If any typing errors is there please excuse me.

    My output like this

    'B7a'=>[ { Service='ADC', path='....' } { Type='engine', Nr='18', Servicenum='1', path='....' } { Type='motor', Nr='7', Servicenum='1', path='....' } { Type='supply', Nr='1', Servicenum='1', path='....' } { Service='input', path='----' } { Service='signal', path='----' } ].....................

    Thanks in advance.

      If you read How do I post a question effectively?, why are you still posting code that uses File::Find? I do not get your result because I do not have a c:/main/folder directory on my computer. Your issue is with parsing XML, so all your example should include is code to parse XML. You have almost 100 posts - seriously, you should know better by now. I've already given you a template for just working on your parsing logic.

      You have now provided an expected output, so I can modify my previous code to replicate your specified output, except of course that your quoted path's do not correspond to the paths in your XML and the order is different because your spec does not respect the order of the source document.

      #!/usr/bin/perl use warnings; use strict; use XML::LibXML::Reader; use Data::Dumper; my $hash_ref; my $reader = XML::LibXML::Reader->new( IO => *DATA ); while ( $reader->nextElement( 'Service' )) { my $number = $reader->getAttribute( 'Num'); $hash_ref->{$number} = []; $reader->read; while (1) { if ( $reader->localName eq 'Customermodules' or $reader->localName eq 'Suppliermodules') { $reader->read; while (1) { if ($reader->localName eq 'Softwaremodule') { my $module = {}; $module->{Service} = $reader->getAttribute('Servic +e'); $module->{path} = $reader->getAttribute('Path'); push @{$hash_ref->{$number}}, $module; } elsif ($reader->localName eq 'Hardwaremodule') { my $module = {}; $module->{Type} = $reader->getAttribute('Type'); $module->{Nr} = $reader->getAttribute('Nr'); $module->{Servicenum} = $reader->getAttribute('Ser +vicenum'); $module->{path} = $reader->getAttribute('Path'); push @{$hash_ref->{$number}}, $module; } $reader->nextSibling() > 0 or last; } } $reader->nextSibling() > 0 or last; } } $reader->finish; print Dumper $hash_ref; __DATA__ <?xml version="1.0" encoding="UTF-8"?> <Servicelist xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi +:noNamespaceSchemaLocation="file:///files/service.xsd"> <Service Num="B7a" Name="temperature sensor"> <Des>It delivers actual temperature in the form ov Volts</Des> <Customermodules> <Softwaremodule Service="ADC" Path="/main/ADCservice.xml"/> </Customermodules> <Suppliermodules> <Softwaremodule Service="input" Path="/main/inputservice.xml"/> <Softwaremodule Service="signal" Path="/main/signalservice.xml"/> <Hardwaremodule Type="engine" Nr="18" Servicenum="1" Path="/main/e +ngineservice.xml"/> <Hardwaremodule Type="motor" Nr="7" Servicenum="1" Path="/main/mo +torservice.xml"/> <Hardwaremodule Type="supply" Nr="1" Servicenum="1" Path="/main/sup +plyservice.xml"/> </Suppliermodules> </Service> </Servicelist>

      outputs

      $VAR1 = { 'B7a' => [ { 'path' => '/main/ADCservice.xml', 'Service' => 'ADC' }, { 'path' => '/main/inputservice.xml', 'Service' => 'input' }, { 'path' => '/main/signalservice.xml', 'Service' => 'signal' }, { 'Type' => 'engine', 'Servicenum' => '1', 'path' => '/main/engineservice.xml', 'Nr' => '18' }, { 'Type' => 'motor', 'Servicenum' => '1', 'path' => '/main/motorservice.xml', 'Nr' => '7' }, { 'Type' => 'supply', 'Servicenum' => '1', 'path' => '/main/supplyservice.xml', 'Nr' => '1' } ] };

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://942719]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others imbibing at the Monastery: (2)
As of 2024-04-20 01:53 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found