Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much

XML with wxPerl

by SuperCruncher (Pilgrim)
on Mar 21, 2002 at 17:55 UTC ( #153366=perlquestion: print w/replies, xml ) Need Help??
SuperCruncher has asked for the wisdom of the Perl Monks concerning the following question:

As mentioned in one of my recent nodes, WxPerl woes -- putting a Tree into a ScrolledWindow, I am writing my final year project using wxPerl. I have been struggling, but thanks to help from Jouke and the wxPerl mailing list, I've been making progress. Anyway, the program is an MP3 organiser--it stores information on various "volumes" (parts of a user's collection - a volume can be either a drive on fixed media or removable media, and possibly remote locations). These volumes are stored as XML files, using a DTD that I have created. A sample document is presented below:

<?xml version="1.0" encoding="utf-8"?> <volume device="cdrom" date="2002-02-10" start="d:/" name="Test"> <directory name="Singles"> <file encoding="CBR" stereo="jointstereo" bitrate="192" format="MP +3" name="Metallica - Wherever I May Roam.mp3" size="500000"> <artist>Metallica</artist> <title>Wherever I May Roam</title> <duration>230</duration> <album>Metallica</album> <reldate>1991</reldate> <label>Elektra</label> </file> <file encoding="CBR" stereo="jointstereo" bitrate="192" format="MP +3" name="Linkin Park - In the End.mp3" size="5000000"> <artist>Linkin Park</artist> <title>In The End</title> <duration>250</duration> <album>Hybrid Theory</album> <reldate>1999</reldate> <label>Sony</label> </file> <cover file="front.jpg" format="JPEG" width="100" height="200" side="front"/> <cover file="back.jpg" format="JPEG" width="100" height="200" side="back"/> </directory> <directory name="Cheesy Tunes"> <directory name="Super Cheesy Tunes"> <file encoding="CBR" bitrate="192" name="Village People - YMCA.mp3 +"> </file> </directory> </directory> </volume>
A few points: directories can contain unlimited directory and file tags. The artist, title etc. tags can exist only inside 'file' tags.

The final application is intended to look something like this screenshot, i.e. a tree with an entry for each volume and each of its subdirectories (recursively). Note in the screenshot that 'Test' and 'Test' are 2 different volumes. When the user clicks on a particular directory, the contents of that directory (whether they are files or more directories) should be displayed in the right-hand pane.

I have implemented this in a rather 'hacked' and far from perfect fashion. In the constructor for my frame, I call a function in package main which sets global variables (using our) in main to store a reference to the tree object and to the current "ID" (the ID is used to denote where an entry into the tree should be inserted), i.e.

our (@stack, @directory, %file); our ($treeId, $treeRef, $treeRoot, $lastXMLElement); sub describeTreeObject { ($treeRef, $treeId) = @_; $treeRoot = $treeId; }
I can create the actual tree (with volumes and directories) fine. I used a 'stack' approach, keeping the ID of the next entry to be inserted at the top of the stack, and popping it off whenever an end tag for 'directory' is encountered. (The stack is then cleared before starting another volume.)

The problem is storing data on the files and linking this to what volume they are on, and what the 'properties' of the volume are. The hack I have used is as follows:

  1. When a 'file' tag is encountered, its attributes are stored in a global hash, %file.
  2. When any character data is encountered, it is inserted into the %file hash using the value of the last XML tag started as they key.
  3. When the end of a 'file' tag is encountered, a 'narrower scoped' version of the %file hash is created using my, and a reference to it is pushed onto a public array, @directory.
  4. When the end of a 'directory' tag is encountered, the @directory array is copied and a scalar reference to it is set as the tree item's data. (So, in other words, the data for the 'Singles' entry in the screenshot would contain an array reference to an array of hash refs, each contain element of which would contain a hash describing the file.)
  5. When the user 'activates' an item in the tree, that item's data is inserted into the wxListCtrl opposite.
The problems with this approach are:
  • Data on volumes is not stored anywhere. (Should be easily accessible.)
  • Directories and files are not distinguished between (in the final version, I hope to have a different icon for directories and files).
  • Directories are not included in the list, i.e. if I have a directory called 'Foo' that includes directories 'Bar' and 'Baz' and also 3 files, the 3 files will be displayed, but directories 'Bar' and 'Baz' will not be. The desired behaviour is that when a directory is selected in the tree, its subdirectories will be displayed in the wxListCtrl, and the same for volumes.
Anyone got any suggestions for how to go about doing this? (I am using XML::Parser by the way).

Also, if you've read this far, thanks--I know this is a long posting, but I felt it was important to explain the situation as clearly as possible and include all relevant information.

Replies are listed 'Best First'.
Re: XML with wxPerl
by paulbort (Hermit) on Mar 21, 2002 at 21:43 UTC
    Much as I hate to say it, it looks to me like all the problems you're having are coming from your data structure. Since you have a tree of data, would it make more sense to store it in a tree structure? Start with an array of volumes, with each entry in the array being the complete path and name of the XML file for that volume. Then add a hash where the keys are the XML file names, and the values are pointers to more hashes of hashes that contain the XML data.

    Once you can load and save the XML files from the hashes (which won't be that bad with a little recursion) the display should be straightforward, because it mirrors the data structure.

    If you can get a copy of "Mastering Algorithms with Perl" it has great stuff on data structures and examples of how they work.
Re: XML with wxPerl
by o(o_o)o (Scribe) on Mar 21, 2002 at 20:20 UTC
    I cant really help you coz i'm a novice, but i only have 1 idea... who happens when you want something to be in 2 directories? ie.. Linkin Park - In the End would be in "singles" and also in "Linkin Park/The album name that i don't know/"

    just thought it would be something to think about! hope u get someone who knows stuff to help u out :)

    when this is done i'd like to have it on my computer! sounds like it's gonna be a lot better than other mp3 collector things i've seen around...

    i would slit my wrists for you
Re: XML with wxPerl
by elwarren (Curate) on Mar 21, 2002 at 22:55 UTC
    I've not used wxPerl yet, but I think it's pretty funny that you used Metallica for your mp3 example!

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://153366]
Approved by root
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (3)
As of 2018-01-20 09:44 GMT
Find Nodes?
    Voting Booth?
    How did you see in the new year?

    Results (226 votes). Check out past polls.