Sporti69 has asked for the wisdom of the Perl Monks concerning the following question:

Hi all,
I wrote a script using the XML Simple module.
It prints out all the xml without any word that is also in the xml, so a fully looped printout.

Now I wonder how do I make a difference between an Attribute and a Genuine Tag without mentioning that element or tag LITERALLY in the code

And my 2nd question: how do I reach the value of that attribute? My Script and XML work fine. Untill he parses an attribute.
Please run it, just put those 2 files in 1 folder, doesn't matter where.
Big Thanks

Sporti

Replies are listed 'Best First'.
Re: XML Attribute vs Element
by pjotrik (Friar) on Nov 06, 2008 at 15:12 UTC
    If you want a simple value to be processed as an element, make it an array reference.
    #!/usr/bin/perl use warnings; use strict; use XML::Simple; my $data = { e => ['element value'], a => 'attribute value' }; print XMLout($data, RootName => 'root'); __DATA__ <root a="attribute value"> <e>element value</e> </root>
      I added some code so I can get the values of the attributes.
      I haven't used your code, I bumped into something else.
      All works, but why do my attributes + their values within <element> get printed out in double

      -Script
      -XML
      We're getting somewhere

Re: XML Attribute vs Element
by GrandFather (Saint) on Nov 06, 2008 at 20:00 UTC

    Please do not link off site code. Include it in your node (in readmore tags if it is large). Off site links are prone to breakage and PerlMonks nodes are read by people for years after their initial posting. So, if at all possible keep your node self contained.

    Also note that </br> on its own is not valid HTML or XHTML. You can use <br /> for XHTML, but this is more an HTML site so use <br>, or better still, don't use break tags at all!


    Perl reduces RSI - it saves typing
      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 !

        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.

        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

        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} };

        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';
Re: XML Attribute vs Element
by Jenda (Abbot) on Nov 06, 2008 at 20:23 UTC
      XML's that needs to be parsed to Excell. The XML file above only needs attributes in the not deepest tags. (A,B,C ..)
      In the real XML every tag has attributes. Not only the <element> ones.

      Unfortunately the code fails if I add attributes to the outer tags. It's a nice script, because in contrary to every script i've seen so far, is this one without words that are in the XML. No A, B, C, D, ... element, type, ... Thanks to my imagination and the help of perlmonks

      How does one solve this in a good way? Some kind of check weather it has nested elements or it is parsing an attribute...

        Show me the actual XML and tell me how do you want to store it in the sheet. If you do not want the attributes from the other tags to get in the way you may use XML::Rules instead and instruct it to skip them. But to tell the truth your boasting about no "words that are in the XML" doesn't make much sense to me.

Re: XML Attribute vs Element
by xinelo (Initiate) on Nov 24, 2008 at 09:19 UTC
    Hi, I had the same doubt about generating attributes for an element and the reply by pjotrik sorted it out... partially.

    I still wonder what I can do to generate an attribute for e rather than for the root element.

    That is, I would like my data to look like
    <root> <e a="attribute value">element value</e> </root>
    rather than
    <root a="attribute value"> <e>element value</e> </root>
    Any ideas? I am sure it's simple but I'm inexperienced...

    Thanks a lot!
    xinelo