# # Graph::Reader::XML - perl class for reading directed graphs from XML # package Graph::Reader::XML; $Graph::Reader::XML::VERSION = '2.10'; use 5.006; use strict; use warnings; use parent 'Graph::Reader'; use Carp; use XML::Parser; #======================================================================= # # _init() # # initialisation private method, invoked by the constructor. # First call the superclass initialiser, then create an # instance of XML::Parser, which does most of the work for us. # #======================================================================= sub _init { my $self = shift; $self->SUPER::_init(); #------------------------------------------------------------------- # use closures to associate the $self reference with the handler # function which will get invoked by the XML::Parser #------------------------------------------------------------------- $self->{PARSER} = XML::Parser->new(Handlers => { Start => sub { handle_start($self, @_); }, End => sub { handle_end($self, @_); }, }); } #======================================================================= # # _read_graph # # private method where the business is done. Just invoke the # parse method on the XML::Parser instance. The real business is # done in the handle_start() and handle_end() "methods", which # are invoked by the XML parser. # #======================================================================= sub _read_graph { my $self = shift; my $graph = shift; my $FILE = shift; $self->{CONTEXT} = []; $self->{GRAPH} = $graph; $self->{PARSER}->parse($FILE); return 1; } #======================================================================= # # handle_start # # XML parser handler for the start of an element. # #======================================================================= sub handle_start { my ($self, $p, $el, %attr) = @_; my $graph = $self->{GRAPH}; if ($el eq 'attribute') { if (exists $attr{name} && exists $attr{value}) { $self->set_attribute($attr{name}, $attr{value}); } else { carp "attribute should have name and value - ignoring\n"; } } elsif ($el eq 'node') { $graph->add_vertex($attr{id}); push(@{$self->{CONTEXT}}, [$el, $attr{id}]); } elsif ($el eq 'edge') { $graph->add_edge($attr{from}, $attr{to}); push(@{$self->{CONTEXT}}, [$el, $attr{from}, $attr{to}]); } elsif ($el eq 'graph') { push(@{$self->{CONTEXT}}, [$el]); } else { carp "unknown element \"$el\"\n"; } } #======================================================================= # # handle_end # # XML parser handler for the end of an element. # #======================================================================= sub handle_end { my ($self, $p, $el) = @_; if ($el eq 'node' || $el eq 'edge' || $el eq 'graph') { pop(@{$self->{CONTEXT}}); } } #======================================================================= # # set_attribute # # Performs the actual setting of an attribute. Looks at the saved # context to determine what we're setting an attribute of, and sets # it on the Graph instance. # #======================================================================= sub set_attribute { my ($self, $name, $value) = @_; if (@{$self->{CONTEXT}} == 0) { carp "attribute element with no context - ignoring!\n"; return; } my $graph = $self->{GRAPH}; my ($el, @args) = @{ (@{$self->{CONTEXT}})[-1] }; if ($el eq 'node') { $graph->set_vertex_attribute($args[0], $name, $value); } elsif ($el eq 'edge') { $graph->set_edge_attribute($args[0], $args[1], $name, $value); } elsif ($el eq 'graph') { $graph->set_graph_attribute($name, $value); } else { carp "unexpected context for attribute\n"; } } 1; =head1 NAME Graph::Reader::XML - class for reading a Graph instance from XML =head1 SYNOPSIS use Graph::Reader::XML; use Graph; $reader = Graph::Reader::XML->new(); $graph = $reader->read_graph('mygraph.xml'); =head1 DESCRIPTION B<Graph::Reader::XML> is a perl class used to read a directed graph stored as XML, and return an instance of the B<Graph> class. The XML format is designed to support the Graph classes: it can be used to represent a single graph with a collection of nodes, and edges between those nodes. The graph, nodes, and edges can all have attributes specified, B<Graph::Reader::XML> is a subclass of B<Graph::Reader>, which defines the generic interface for Graph reader classes. =head1 METHODS =head2 new() Constructor - generate a new reader instance. $reader = Graph::Reader::XML->new(); This doesn't take any arguments. =head2 read_graph() Read a graph from a file: $graph = $reader->read_graph( $file ); The C<$file> argument can be either a filename or a filehandle of a previously opened file. =head1 KNOWN BUGS Attribute values must be scalar. If they're not, well, you're on your own. =head1 SEE ALSO =over 4 =item Graph::Reader The base class for B<Graph::Reader::XML>. =item Graph::Writer::XML Used to serialise a Graph instance as XML. =item Graph Jarkko Hietaniemi's classes for representing directed graphs. =back =head1 REPOSITORY L<https://github.com/neilb/Graph-ReadWrite> =head1 AUTHOR Neil Bowers E<lt>neil@bowers.comE<gt> =head1 COPYRIGHT Copyright (c) 2001-2012, Neil Bowers. All rights reserved. Copyright (c) 2001, Canon Research Centre Europe. All rights reserved. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut