Config-XPath
view release on metacpan or search on metacpan
lib/Config/XPath.pm view on Meta::CPAN
# You may distribute under the terms of either the GNU General Public License
# or the Artistic License (the same terms as Perl itself)
#
# (C) Paul Evans, 2005-2010 -- leonerd@leonerd.org.uk
package Config::XPath;
use strict;
use warnings;
use Exporter 'import';
our @EXPORT = qw(
get_service_config
get_config_string
get_config_attrs
get_config_list
get_config_map
get_sub_config
get_sub_config_list
read_default_config
);
our $VERSION = '0.16';
use XML::XPath;
use Carp;
use Scalar::Util qw( weaken );
=head1 NAME
C<Config::XPath> - retrieve configuration data from XML files by using XPath
=head1 SYNOPSIS
use Config::XPath;
my $conf = Config::XPath->new( filename => 'addressbook.xml' );
## Basic data retrieval
my $bob_phone = $conf->get_string( '//user[@name="bob"]/@phone' );
my %jim_details = $conf->get_attrs( '//user[@name="jim"]' );
my @everyone_with_fax = $conf->get_list( '//user[@fax]' );
print " $_ has a fax\n" for @everyone_with_fax;
my $phone_map = $conf->get_map( '//user', '@name', '@phone' );
print " $_ has a phone: $phone_map->{$_}\n" for sort keys %$phone_map;
## Subconfigurations
my $james_config = $conf->get_sub( '//user[@name="james"]' );
my $james_phone = $james_config->get_string( '@phone' );
foreach my $user_config ( $conf->get_sub_list( '//user[@email]' ) ) {
my $town = $user_config->get_string( 'address/town' );
print "Someone in $town has an email account\n";
}
=head1 DESCRIPTION
This module provides easy access to configuration data stored in an XML file.
Configuration is retrieved using XPath keys; various methods exist to
convert the result to a variety of convenient forms.
If the methods are called as static functions (as opposed to as object
methods) then they access data stored in the default configuration file
(details given below).
=cut
=head2 Subconfigurations
By default, the XPath context is at the root node of the XML document. If some
other context is required, then a subconfiguration object can be used. This is
a child C<Config::XPath> object, built from an XPath query on the parent.
Whatever node the query matches becomes the context for the new object. The
methods C<get_sub()> and C<get_sub_list()> perform this task; the former
returning a single child, and the latter returning a list of all matches.
=cut
=head1 CONSTRUCTOR
=head2 $conf = Config::XPath->new( %args )
lib/Config/XPath.pm view on Meta::CPAN
=cut
sub new
{
my $class = shift;
my %args;
# Cope with now-deprecated constructor form
if( @_ == 1 ) {
carp 'Use of '.__PACKAGE__.'->new( $file ) is deprecated; use ->new( filename => $file ) instead';
%args = ( filename => $_[0] );
}
else {
%args = @_;
}
my $self = bless {
}, $class;
my $parser = $self->{parser} = delete $args{parser};
if( defined $args{filename} ) {
$self->{filename} = $args{filename};
$self->_reload_file;
}
elsif( defined $args{xml} ) {
my $xp = XML::XPath->new(
xml => $args{xml},
defined $parser ? ( parser => $parser ) : (),
);
croak "Cannot parse string" unless $xp;
$self->{xp} = $xp;
}
elsif( defined $args{ioref} ) {
my $xp = XML::XPath->new(
ioref => $args{ioref},
defined $parser ? ( parser => $parser ) : (),
);
croak "Cannot parse XML from ioref" unless $xp;
$self->{xp} = $xp;
}
else {
croak "Expected 'filename', 'xml', 'parser' or 'ioref' argument";
}
return $self;
}
# Internal-only constructor
sub newContext
{
my $class = shift;
my ( $parent, $context ) = @_;
my $self = {
parent => $parent,
context => $context
};
weaken( $self->{parent} );
return bless $self, $class;
}
sub find
{
my $self = shift;
my ( $path, %args ) = @_;
my $toplevel = $self;
$toplevel = $toplevel->{parent} while !exists $toplevel->{xp};
my $xp = $toplevel->{xp};
my $context = $args{context} || $self->{context};
if ( defined $context ) {
return $xp->find( $path, $context );
}
else {
return $xp->find( $path );
}
}
sub get_config_nodes
{
my $self = shift;
my ( $path ) = @_;
my $nodeset = $self->find( $path );
unless( $nodeset->isa( "XML::XPath::NodeSet" ) ) {
croak "Expected result to be a nodeset at '$path'";
}
return $nodeset->get_nodelist;
}
sub get_config_node
{
my $self = shift;
my ( $path ) = @_;
my @nodes = $self->get_config_nodes( $path );
if ( scalar @nodes == 0 ) {
croak "No config found at '$path'";
}
if ( scalar @nodes > 1 ) {
croak "Found more than one node at '$path'";
}
return shift @nodes;
}
sub get_node_attrs($)
# Get a hash of the attributes, putting the node name in "+"
{
my ( $node ) = @_;
( run in 1.335 second using v1.01-cache-2.11-cpan-39bf76dae61 )