in reply to Re: XML Attribute vs Element
in thread XML Attribute vs Element

Thanks for the advice. The script has evolved again into a working one. Everything works without one xml tag in the script.

thank you all for helping me. Not only in this node.

#!/usr/bin/perl -- use strict; use warnings; use Cwd; use Win32::OLE; use XML::Simple; my $dir = cwd(); opendir(DIR, "."); my @file = grep(/\.xml$/,readdir(DIR)); closedir(DIR); use Data::Dumper; local $Data::Dumper::Indent=1; #print Dumper($doc); ################### #my %hash = ( # key1 => 'ArraySite', # key2 => 'IOPort', # key3 => 'AddressGroup', # key4 => 'LSS', # key5 => 'Array', # key6 => 'Rank', # key7 => 'ExtentPool', # key8 => 'Volume', # key9 => 'StorageEnclosure', # key10 => 'VolumeGroup', # ); # # for my $key ( keys %hash ) { # my $value = $hash{$key}; # print "$key => $value\n"; # } ############## my $xs1 = XML::Simple->new(); my $doc = $xs1->XMLin($file[0], keyattr=>[], ForceContent=>1, ForceArr +ay=>1); for my $sub1 ( sort keys %{ $doc } ){ my $count = scalar keys %{ $doc }; print "\n$sub1\t"; for (my $i=0; $i <= $count; $i++) { for my $sub2 ( sort keys %{ $doc->{$sub1}[$i] } ){ my $count2 = @{$doc->{$sub1}[$i]{$sub2}}; #print "\n\t\t".$count2."\t".$sub2; for (my $j=0; $j <= $count2; $j++) { for my $sub3 ( sort keys %{ $doc->{$sub1}[$i]{$sub2}[$ +j] } ){ my $count3 = @{$doc->{$sub1}[$i]{$sub2}[$j]{$sub3} +}; print "\n\t$sub2\t$sub3($count3)"; for (my $k=0; $k <= $count3; $k++) { print "\n"; for my $sub4 ( sort keys %{ $doc->{$sub1}[$i]{ +$sub2}[$j]{$sub3}[$k] } ){ print "\n\t\t\t$sub4 : "; print $doc->{$sub1}[$i]{$ +sub2}[$j]{$sub3}[$k]{$sub4}; } } } } } } }
XML
<A> <B> <C> <element type="k" name="p" online="yes"/> <element type="i" name="e" online="yes"/> </C> <D> <element type="kd" name="pd" online="no"/> <element type="id" name="ed" online="yes"/> <element type="yd" name="zd" online="no"/> </D> </B> <Z> <C> <element type="k" name="z" online="yes"/> <element type="t" name="p" online="yes"/> </C> <E> <element type="kd" name="pd" online="no"/> <element type="id" name="ed" online="yes"/> </E> </Z> </A>
But I could still use some help... When I add an attribute to lets say tag B my code fails all of a sudden ... Can someone tell me why / advise or point out a solution... The error I get is "Can't use string ("value of attribute") as an ARRAY ref while "strict refs""

Thanks so much !

Replies are listed 'Best First'.
Re^3: XML Attribute vs Element
by ig (Vicar) on Nov 06, 2008 at 22:09 UTC
    When I add an attribute to lets say tag B...

    You are getting the error message because XML::Simple creates a data structure with an array for your elements but a simple scalar value for your attribute.

    You can see this if you use Data::Dumper to dump $doc after loading your file.

    After changing your B tag to <B type="xxx"> your script produced the following error: Can't use string ("xxx") as an ARRAY ref while "strict refs" in use. Here is the structure produced by XMLin:

    If you look carefully at what has been created for your tag B, you will see that there are three elements in the contained hash, with keys D, C and type. The values of the first two (D and C) are references to arrays but the value of the third is a string. Your program uses all three as if they were references to arrays. Because you have used use strict; (which is a good thing) perl stops when it gets to the string and reports the error.

    You can either write your program to check whether a value is a reference or not, using ref or you can provide parameters to XML::Simple to make it load the elements and tags consistently. Which approach is better will depend on what you are doing. You may want to learn both methods so you can decide which is most appropriate.

      You can either write your program to check whether a value is a reference or not, using ref or you can provide parameters to XML::Simple to make it load the elements and tags consistently. Which approach is better will depend on what you are doing. You may want to learn both methods so you can decide which is most appropriate.

      I will create a check whether it is a reference or not. Will look into this right now and will keep you (guys) posted. Providing parameters to XML::Simple is not an option because I want to create a script that runs universal. Both on element depth and on attributes. So the reusability will be high.

      @ grandfather: thank you for the suggestion, but you use indent size = 4. This can be variable. I will write the complete script using XML::Simple cause it feels so simple :) (after a lot of coarsing by this perl newbie). This will also mean that the for loops for $Sub1 2, 3, 4 will need to be put in a loop aswell. Probably together with the 'ref' method

      Keeping you guys posted

      Sporti

      PS: For whom is interested, the excel part will be multiple worksheets with data from various tags and elements in a table style

Re^3: XML Attribute vs Element
by GrandFather (Saint) on Nov 06, 2008 at 22:16 UTC

    I'd use something simpler for parsing the XML than XML::Simple, like XML::Parser, although I don't know what you want the final output for so the rendering below may not suit you:

    use warnings; use strict; use XML::Parser; my $xmlStr = <<XML; <A> <B> <C> <element type="k" name="p" online="yes"/> <element type="i" name="e" online="yes"/> </C> <D> <element type="kd" name="pd" online="no"/> <element type="id" name="ed" online="yes"/> <element type="yd" name="zd" online="no"/> </D> </B> <Z> <C> <element type="k" name="z" online="yes"/> <element type="t" name="p" online="yes"/> </C> <E> <element type="kd" name="pd" online="no"/> <element type="id" name="ed" online="yes"/> </E> </Z> </A> XML use constant kIndentSize => 4; my $indent = ''; my $xs1 = XML::Parser->new ( Handlers => { Start => sub {start (\$indent, @_);}, End => sub {end (\$indent, @_);}, Char => sub {char (\$indent, @_);} }); $xs1->parse ($xmlStr); sub start { my ($indent, $expat, $element, %attr) = @_; print "$$indent$element\n"; $$indent .= ' ' x kIndentSize; print "$$indent$_ : $attr{$_}\n" for sort keys %attr; return; } sub end { my ($indent, $expat, $element) = @_; substr $$indent, -(kIndentSize), kIndentSize, ''; return; } sub char { my ($indent, $expat, $string) = @_; chomp $string; $string =~ s/^\s+|\s+$//g; return unless length $string; print "$$indent$string\n"; return; }

    Prints:

    A B C element name : p online : yes type : k element name : e online : yes type : i D element name : pd online : no type : kd element name : ed online : yes type : id element name : zd online : no type : yd Z C element name : z online : yes type : k element name : p online : yes type : t E element name : pd online : no type : kd element name : ed online : yes type : id

    Perl reduces RSI - it saves typing
Re^3: XML Attribute vs Element
by ig (Vicar) on Nov 06, 2008 at 22:29 UTC

    You should probably change

    my $count = scalar keys %{ $doc };

    to

    my $count = scalar @{ $doc->{$sub1} };

    And similarly for your other counts.

    Update: no, your other counts are fine. And you don't need the scalar as you are assigning to a scalar, so you can do as you have done for the other counts:

    my $count = @{ $doc->{$sub1} };
Re^3: XML Attribute vs Element
by ikegami (Patriarch) on Nov 06, 2008 at 21:09 UTC

    But I could still use some help... When I add an attribute to lets say tag B my code fails all of a sudden ..

    What code do you use to do that? I used

    # Add attribute "xxx" with value "yyy" to # the first (idx 0) "B" child of node $doc. $doc->{B}[0]{xxx} = 'yyy';