Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

need help using XML::Simple::XMLOut() and XML::Simple::XMLin()

Posted on 2005-04-23
12
Medium Priority
?
1,996 Views
Last Modified: 2013-11-19
Hello,

  I am a complete newbie when it comes to this. I would like to use XML::Simple to write a hash table to an .xml file. For me, this is best explained by examples:

the hash table is $self inside sub new():

------------------------------------------------
sub new {
      my $type = shift;
      my $class = ref ($type) || $type;
      
      my @players =();
      
      #my $refPlayers = shift;
      my $bjRules = shift;
      
      my $dealer = new BJDealer($bjRules);
      my $self = {players => \@players,
                        current_player => undef,
                        rules => $bjRules,
                        dealer => $dealer,
                        deck => undef
                     };
      
      bless($self,$class);
      return $self;
}
-----------------------------------------------------------


I try to convert using this subroutine I wrote:

-----------------------------------------------------------

sub perl_to_xml {
  my $self = shift;
 
  my $path = "c:\\testXMLOUT.xml";
  open my $fh, '>:encoding(iso-8859-1)', $path or die "open($path): $!";
  XMLout($self, OutputFile => $fh);

  return 1;
}

-----------------------------------------------------------


However, when I run the following test script:

-----------------------------------------------------------
# code fragment:
my $simul = new BJSimulation();

$simul->perl_to_xml();
-----------------------------------------------------------


I get the following error message:
Can't locate object method "print" via package "IO::Handle" at c:/Perl/site/lib/XML/Simple.pm line 540.



I'm not even sure how to diagnose the error message. I am unaccustom to seeing error messages generated by a PERL internal like IO::Handle.


Any advice would be greatly appreciated! I want to start with getting XMLOut working, and then turn to XMLIn.

Thanks!
0
Comment
Question by:sapbucket
  • 8
  • 4
12 Comments
 
LVL 85

Expert Comment

by:ozo
ID: 13851436
# I will try to see if I can find out why you are getting the error, but meanwhile you could do it this way insead:

  print $fh XMLout($self);
0
 
LVL 85

Accepted Solution

by:
ozo earned 2000 total points
ID: 13851459
#To get rid of the error
use IO::Handle;
0
 
LVL 3

Author Comment

by:sapbucket
ID: 13851813
that made it work.

i get an error when trying to open it with the Windows XP XML editor. The xml has tags that are numeric (0..number_hands), which it doesn't like. But, this seems somewhat odd to me because the source of the tags is an anonymous array nested in a hash table. Should be very common for anonymous hashes and arrays to be converted to xml, however, in this case it is generating non-XML-editor conforming xml.

(error message)
The XML page cannot be displayed
Cannot view XML input using XSL style sheet. Please correct the error and then click the Refresh button, or try again later.
--------------------------------------------------------------------------------
A name was started with an invalid character. Error processing resource 'file:///C:/testXMLOUT.xml'. Line 6, Position 8
      <0>3S</0>
-------^


in notepad it looks like this:
<opt>
  <current_player></current_player>
  <dealer current_hand="0" number_hands="1" upcard="3S">
    <bank></bank>
    <hands name="table">
      <0>3S</0>
      <0>2S</0>
    </hands>
    <rules doubleAfterPairSplit="1" doublingNumCards="0" doublingRules="2" earlySurrender="0" hitSplitAce="1" insurance="1" lateSurrender="1" natural="2" numDecks="1" penetration="100" resplitAce="1" resplitPairs="1" soft17="0" softDoubling="1" splitAce="1" splitPairs="1" ties="0" />
  </dealer>
  <deck numDecks="1" penetration="100">
    <deck>5H</deck>
    <deck>1C</deck>
    <deck>10D</deck>
    <deck>11C</deck>
    <deck>5D</deck>
    <deck>6H</deck>
    <deck>11S</deck>
    <deck>2H</deck>
    <deck>13C</deck>
    <deck>10H</deck>
    <deck>10C</deck>
    <deck>9S</deck>
    <deck>7S</deck>
    <deck>12C</deck>
    <deck>12D</deck>
    <deck>6S</deck>
    <deck>3D</deck>
    <deck>1D</deck>
    <deck>13S</deck>
    <deck>9H</deck>
    <deck>5C</deck>
    <deck>7D</deck>
    <deck>8D</deck>
    <deck>13D</deck>
    <deck>9D</deck>
    <deck>8C</deck>
    <deck>4C</deck>
    <deck>11D</deck>
    <deck>6D</deck>
    <deck>2D</deck>
    <deck>4S</deck>
    <deck>4H</deck>
    <deck>8S</deck>
    <deck>1H</deck>
    <deck>8H</deck>
    <deck>7H</deck>
    <deck>5S</deck>
    <deck>12H</deck>
    <deck>2C</deck>
    <deck>7C</deck>
    <deck>6C</deck>
    <deck>3H</deck>
    <deck>3C</deck>
    <deck>13H</deck>
    <deck>1S</deck>
    <deck>4D</deck>
    <holeCard></holeCard>
  </deck>
  <players bank="1000" buyin="1000" current_hand="0" number_hands="1" player_id="player 1">
    <hands name="table">
      <0>11H</0>
      <0>10S</0>
    </hands>
  </players>
  <players bank="500" buyin="500" current_hand="0" number_hands="1" player_id="player 2">
    <hands name="table">
      <0>12S</0>
      <0>9C</0>
    </hands>
  </players>
  <rules doubleAfterPairSplit="1" doublingNumCards="0" doublingRules="2" earlySurrender="0" hitSplitAce="1" insurance="1" lateSurrender="1" natural="2" numDecks="1" penetration="100" resplitAce="1" resplitPairs="1" soft17="0" softDoubling="1" splitAce="1" splitPairs="1" ties="0" />
</opt>
 


and the anonymous hash "object" is derived from perldoc perlreftut (a hash with anonymous arrays references (CITIES) for the values and scalars for the keys (COUNTRIES)):
package Hashtable;
use strict;

sub new {
      my $type = shift;
      my $class = ref($type) || $type;
      
      my $self={ table=>{}};
      
      bless ($self, $class);
      return ($self);
}



I think I know the solution. If you have a hash using keys that are equal to (0..number_of_keys_in_hash), than you should just use an array. But, dang it. I have all that code already written and it works great! I could convert '1' to "one" and '2' to "two", etc. Or use the $player_id as the key instead of '1','2','3', etc. And then I could have a lookup-hash that uses the $player_id as a key to find the value ('1','2','3').  That would be a subroutine called lookup_player_index().

I didn't think it would be so picky.

Any ideas on that?


0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 85

Expert Comment

by:ozo
ID: 13851906
XMLout($hashref) should produce conforming XML when $hashref was created by XMLin() from conforming XML,
but as you've seen, not all possible hash keys are valid XML tags.

If you want to start with an arbitrary Perl data structure,

use XML::Dumper;
print $fh pl2xml( $self );
#should produce valid XML that can be converted back with xml2pl(pl2xml( $self ));
0
 
LVL 3

Author Comment

by:sapbucket
ID: 13852022
yes that worked good for viewing the xml. That tagging system is not what my DataSet expects, unfortunately. XML::Simple was more on par with the type of XML i want to use.

I have been looking at xml books. It would seem that I should take greater care in the design of my hashtables so that the xml is structured better (and does not use invalid characters). I really am a newb at this!
0
 
LVL 3

Author Comment

by:sapbucket
ID: 13873607
Do you know how to link the XML to a VB.NET database by any chance?
0
 
LVL 3

Author Comment

by:sapbucket
ID: 13881359
OK, I figured out how to link XML to a VB.NET dataset.

It turns out that the Xml I am generating () is not compliant with W3C schema standards.

I am curious to know what people are doing with the xml generated by XML::Simple. From my point of view, it generates "garbage" xml because it is malformed (non compliant).

I wonder if there is a proper way to construct a hash so that the XML generated by XML::Simple is W3C compliant? Or maybe there is a way of setting options in XML::Simple to make it more compliant? Or maybe there is a better module than XML::Simple?

What would a "W3C Compliant" hash look like (I know, we must extend our thought here). Could there be a proper idiom for hash design that would create perfect, W3C compliant xml? What would be the algorithm for constucting such a hash? I think it would be *incredibly* useful! For me, the useful application would be that I can develop my applications using a console and perl (all text based), and when I am ready to link it to a GUI interface (like VB.NET or ASP.NET - programs that do not "glue" well with Perl). I can simply perl2xml each object hash and link the generated xml to a dataset. Since each object contains all of the data\content for that object within the hash (blessed hash reference, whatever) I get a perfect xml description of the current state of each object. As click_events occur and what not, the xml acts as a storage for next state and current state information/content to be passed between Perl and .NEt. Sound good to you? I like it because it skips the whole server/client model, AND I don't have to write any SQL statements OR deal with silly OS environment variables (so it would be platform independent too). I guess this is what XML has promised all along - I just can't make it practical with Perl yet because I can't generate compliant XML.

Any thoughts experts? I do not want to re-invent the wheel here. Maybe XML::Simple *does* create perfect, W3C compliant xml, and it is the programmer (me) that needs some re-work. Sharing your thoughts on proper hash design (in terms of XML generation) would benefit me the best.

Thanks!
0
 
LVL 85

Expert Comment

by:ozo
ID: 13890353
perldoc XML::Simple
says:
       Caveats

       Some care is required in creating data structures which will be passed
       to "XMLout()".  Hash keys from the data structure will be encoded as
       either XML element names or attribute names.  Therefore, you should use
       hash key names which conform to the relatively strict XML naming rules:

       Names in XML must begin with a letter.  The remaining characters may be
       letters, digits, hyphens (-), underscores (_) or full stops (.).  It is
       also allowable to include one colon (:) in an element name but this
       should only be used when working with namespaces (XML::Simple can only
       usefully work with namespaces when teamed with a SAX Parser).

       You can use other punctuation characters in hash values (just not in
       hash keys) however XML::Simple does not support dumping binary data.

       If you break these rules, the current implementation of "XMLout()" will
       simply emit non-compliant XML which will be rejected if you try to read
       it back in.  (A later version of XML::Simple might take a more proac-
       tive approach).

       Note also that although you can nest hashes and arrays to arbitrary
       levels, circular data structures are not supported and will cause
       "XMLout()" to die.

       If you wish to 'round-trip' arbitrary data structures from Perl to XML
       and back to Perl, then you should probably disable array folding (using
       the KeyAttr option) both with "XMLout()" and with "XMLin()".  If you
       still don't get the expected results, you may prefer to use XML::Dumper
       which is designed for exactly that purpose.

       Refer to "WHERE TO FROM HERE?" if "XMLout()" is too simple for your
       needs.
0
 
LVL 3

Author Comment

by:sapbucket
ID: 13891716
I read that too. There should be more caveats tho. The actual (strict,compliant) method of nesting hashes and arrays should of been addressed. He makes mention of array folding, which is a good start, but should have followed up with examples.

I've got a meeting tomorrow with a guy who wrote a book on XML and VB.NET. It should lead me up to the proper idiom. I'll post here when I figure it out.

Not all of us (or should I say, none of us!) can program like you ozo. You are a rare bird indeed!
0
 
LVL 3

Author Comment

by:sapbucket
ID: 14003642
OK, this is the wrong path to take.

I am trying to have a Perl application talk to a .NET application via XML. I think better would be to use Tie::DBI or something similar. I'm going to post another question, similar intent, but completely different design pattern.

sapbucket
0
 
LVL 3

Author Comment

by:sapbucket
ID: 14099666
Thanks for the help ozo, I am giving up on xml and focusing on using relational databases (MySql) instead. Couldn't get things to work at all using xml.
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Preface This is the third article about the EE Collaborative Login Project. A Better Website Login System (http://www.experts-exchange.com/A_2902.html) introduces the Login System and shows how to implement a login page. The EE Collaborative Logi…
I found this questions asking how to do this in many different forums, so I will describe here how to implement a solution using PHP and AJAX. The logical flow for the problem should be: Write an event handler for the first drop down box to get …
The viewer will receive an overview of the basics of CSS showing inline styles. In the head tags set up your style tags: (CODE) Reference the nav tag and set your properties.: (CODE) Set the reference for the UL element and styles for it to ensu…
The viewer will the learn the benefit of plain text editors and code an HTML5 based template for use in further tutorials.
Suggested Courses

810 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question