From: Grant M. <gr...@us...> - 2007-01-25 10:21:17
|
Update of /cvsroot/perl-xml/xml-simple/lib/XML In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv7898/lib/XML Modified Files: Simple.pm Log Message: - refactor XMLin() to use new public methods parse_string, parse_file and parse_fh - begin documentation of hook methods Index: Simple.pm =================================================================== RCS file: /cvsroot/perl-xml/xml-simple/lib/XML/Simple.pm,v retrieving revision 1.34 retrieving revision 1.35 diff -u -d -r1.34 -r1.35 --- Simple.pm 30 Oct 2006 08:28:13 -0000 1.34 +++ Simple.pm 25 Jan 2007 10:21:14 -0000 1.35 @@ -148,6 +148,7 @@ return $self; } + ############################################################################## # Sub/Method: XMLin() # @@ -162,88 +163,158 @@ sub XMLin { my $self = &_get_object; # note, @_ is passed implicitly - my $string = shift; + my $target = shift; - $self->handle_options('in', @_); + # Work out whether to parse a string, a file or a filehandle - # If no XML or filename supplied, look for scriptname.xml in script directory + if(not defined $target) { + return $self->parse_file(undef, @_); + } - unless(defined($string)) { - - # Translate scriptname[.suffix] to scriptname.xml + elsif($target eq '-') { + local($/) = undef; + $target = <STDIN>; + return $self->parse_string(\$target, @_); + } - require File::Basename; + elsif(my $type = ref($target)) { + if($type eq 'SCALAR') { + return $self->parse_string($target, @_); + } + else { + return $self->parse_fh($target, @_); + } + } - my($ScriptName, $ScriptDir, $Extension) = - File::Basename::fileparse($0, '\.[^\.]+'); + elsif($target =~ m{<.*?>}s) { + return $self->parse_string(\$target, @_); + } - $string = $ScriptName . '.xml'; + else { + return $self->parse_file($target, @_); + } +} - # Add script directory to searchpath - - if($ScriptDir) { - unshift(@{$self->{opt}->{searchpath}}, $ScriptDir); - } - } - +############################################################################## +# Sub/Method: parse_file() +# +# Same as XMLin, but only parses from a named file. +# - # Are we parsing from a file? If so, is there a valid cache available? +sub parse_file { + my $self = &_get_object; # note, @_ is passed implicitly - my($filename, $scheme); - unless($string =~ m{<.*?>}s or ref($string) or $string eq '-') { + my $filename = shift; - require File::Basename; - require File::Spec; + $self->handle_options('in', @_); - $filename = $self->find_xml_file($string, @{$self->{opt}->{searchpath}}); + $filename = $self->default_config_file if not defined $filename; - if($self->{opt}->{cache}) { - foreach $scheme (@{$self->{opt}->{cache}}) { - my $method = 'cache_read_' . $scheme; - my $opt = $self->$method($filename); - return($opt) if($opt); - } + $filename = $self->find_xml_file($filename, @{$self->{opt}->{searchpath}}); + + # Check cache for previous parse + + if($self->{opt}->{cache}) { + foreach my $scheme (@{$self->{opt}->{cache}}) { + my $method = 'cache_read_' . $scheme; + my $opt = $self->$method($filename); + return($opt) if($opt); } } - else { - delete($self->{opt}->{cache}); - if($string eq '-') { - # Read from standard input - local($/) = undef; - $string = <STDIN>; - } + my $ref = $self->build_simple_tree($filename, undef); + + if($self->{opt}->{cache}) { + my $method = 'cache_write_' . $self->{opt}->{cache}->[0]; + $self->$method($ref, $filename); } + return $ref; +} - # Parsing is required, so let's get on with it - my $tree = $self->build_tree($filename, ref($string) ? $string : \$string); - undef($string); +############################################################################## +# Sub/Method: parse_fh() +# +# Same as XMLin, but only parses from a filehandle. +# - # Now work some magic on the resulting parse tree +sub parse_fh { + my $self = &_get_object; # note, @_ is passed implicitly - my($ref); - if($self->{opt}->{keeproot}) { - $ref = $self->collapse({}, @$tree); - } - else { - $ref = $self->collapse(@{$tree->[1]}); - } + my $fh = shift; + croak "Can't use " . (defined $fh ? qq{string ("$fh")} : 'undef') . + " as a filehandle" unless ref $fh; - if($self->{opt}->{cache}) { - my $method = 'cache_write_' . $self->{opt}->{cache}->[0]; - $self->$method($ref, $filename); + $self->handle_options('in', @_); + + return $self->build_simple_tree(undef, $fh); +} + + +############################################################################## +# Sub/Method: parse_string() +# +# Same as XMLin, but only parses from a string or a reference to a string. +# + +sub parse_string { + my $self = &_get_object; # note, @_ is passed implicitly + + my $string = shift; + + $self->handle_options('in', @_); + + return $self->build_simple_tree(undef, ref $string ? $string : \$string); +} + + +############################################################################## +# Method: default_config_file() +# +# Returns the name of the XML file to parse if no filename (or XML string) +# was provided. +# + +sub default_config_file { + my $self = shift; + + require File::Basename; + + my($basename, $script_dir, $ext) = File::Basename::fileparse($0, '\.[^\.]+'); + + # Add script directory to searchpath + + if($script_dir) { + unshift(@{$self->{opt}->{searchpath}}, $script_dir); } - return($ref); + return $basename . '.xml'; } ############################################################################## -#Method: build_tree() +# Method: build_simple_tree() +# +# Builds a 'tree' data structure as provided by XML::Parser and then +# 'simplifies' it as specified by the various options in effect. +# + +sub build_simple_tree { + my $self = shift; + + my $tree = $self->build_tree(@_); + + return $self->{opt}->{keeproot} + ? $self->collapse({}, @$tree) + : $self->collapse(@{$tree->[1]}); +} + + +############################################################################## +# Method: build_tree() # # This routine will be called if there is no suitable pre-parsed tree in a # cache. It parses the XML and returns an XML::Parser 'Tree' style data @@ -846,8 +917,10 @@ my @search_path = @_; - my($filename, $filedir) = - File::Basename::fileparse($file); + require File::Basename; + require File::Spec; + + my($filename, $filedir) = File::Basename::fileparse($file); if($filename ne $file) { # Ignore searchpath if dir component return($file) if(-e $file); @@ -2671,6 +2744,51 @@ called as C<xml_in()> or C<xml_out()>. The method names are aliased so the only difference is the aesthetics. +=head2 Parsing Methods + +You can explicitly call one of the following methods rather than rely on the +C<xml_in()> method automatically determining whether the target to be parsed is +a string, a file or a filehandle: + +=over 4 + +=item parse_string + +Works exactly like the C<xml_in()> method but assumes the first argument is +a string of XML (or a reference to a scalar containing a string of XML). + +=item parse_file + +Works exactly like the C<xml_in()> method but assumes the first argument is +the name of a file containing XML. + +=item parse_fh + +Works exactly like the C<xml_in()> method but assumes the first argument is +a filehandle which can be read to get XML. + +=back + +=head2 Hook Methods + +You can make your own class which inherits from XML::Simple and overrides +certain behaviour. The following methods may provide useful 'hooks' upon which +to hang your modified behaviour. You may find other undocumented places by +examining the source, but those methods may change in future releases. + +=over 4 + +=item default_config_file + +Calculates and returns the name of the file which should be parsed if no +filename is passed to C<XMLin()> (default: C<$0.xml>). + +=item TODO + +more here + +=back + =head1 STRICT MODE If you import the B<XML::Simple> routines like this: |