| Config-Context documentation | Contained in the Config-Context distribution. |
Config::Context::XMLSimple - Use XML-based config files with Config::Context
use Config::Context;
my $config_text = '
<opt>
<Location name="/users">
<title>User Area</title>
</Location>
<LocationMatch name="\.*(jpg|gif|png)$">
<image_file>1</image_file>
</LocationMatch>
</opt>
';
my $conf = Config::Context->new(
string => $config_text,
driver => 'XMLSimple',
match_sections => [
{
name => 'Location',
match_type => 'path',
},
{
name => 'LocationMatch',
match_type => 'regex',
},
],
);
my %config = $conf->context('/users/~mary/index.html');
use Data::Dumper;
print Dumper(\%config);
--------
$VAR1 = {
'title' => 'User Area',
'image_file' => undef,
};
my %config = $conf->context('/users/~biff/images/flaming_logo.gif');
print Dumper(\%config);
--------
$VAR1 = {
'title' => 'User Area',
'image_file' => 1,
};
This module uses XML::Simple to parse XML config files for
Config::Context. See the Config::Context docs for more
information.
By default, it is assumed that the RootName of your configuration
files is <opt>. For instance:
<opt>
<Location /users>
<title>Users Area</title>
</Location>
<opt>
If you change this to some other element, then you must specify the
RootName parameter in driver_options:
# Change the name of the root block to <Config>..</Config>
my $conf = Config::Context->new(
driver => 'XMLSimple',
driver_options => {
XMLSimple = > {
RootName => 'Config',
},
},
);
By default the options passed to XML::Simple are:
KeyAttr => [],
ForceArray => \@section_names,
...where @section_names is a list of the sections as defined in match_sections.
This makes for consistently formatted configurations that are similar to
those generated by the other drivers.
You can change this behaviour by passing a different value to
driver_params to new:
my $conf = Config::Context->new(
driver => 'XMLSimple',
driver_options => {
XMLSimple = > {
ForceArray => 1,
},
},
);
You include XML files within other XML files by using the XInclude
syntax. To include a file called other_config.xml you would use:
<opt>
<xi:include href="other_config.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
</opt>
Files included this way are included in the same scope. For instance:
# config.xml
<opt>
<Location /users>
<title>Users Area</title>
</Location>
<xi:include href="other_config.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<opt>
# other_config.xml
<opt>
<Location /users>
<title>Members Area</title>
</Location>
</opt>
In this example, the raw config will look like
{
'location' => {
'users' => {
'title' => 'Members Area',
}
}
}
And the config matching users will look like:
{
'title' => 'Members Area',
}
Note that the placement of the <xi:include> tag within a block
(e.g. top or bottom) doesn't matter. Contents are merged into the block
so that the included file has precedence.
my $driver = Config::Context::XMLSimple->new(
file => $config_file,
options => {
# ...
}
);
or:
my $driver = Config::Context::XMLSimple->new(
string => $config_string,
options => {
# ...
}
);
Returns a new driver object, using the provided options.
Returns the data structure for the parsed config.
Returns a list of all the config files read, including any config files included in the main file.
Returns the modules required to parse the config. In this case:
XML::Simple, XML::SAX and XML::Filter::XInclude.
The lower_case_names option is not supported used with this driver.
If you specify it, it will produce a warning.
Config::Context
CGI::Application::Plugin::Config::Context
XML::Simple
Copyright 2004-2005 Michael Graham, All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
| Config-Context documentation | Contained in the Config-Context distribution. |
package Config::Context::XMLSimple; use warnings; use strict; use Carp; use Cwd; use Hash::Merge ();
# This is a customized subclass of XInclude, which can remember # the names of all the files it has read in. my %Included_Files; { package XML::Filter::XInclude::RememberFiles; use vars '@ISA'; @ISA = qw(XML::Filter::XInclude); sub _include_xml_document { my $self = shift; my ($url) = @_; my $base = $self->{bases}[-1]; my $source = URI->new_abs($url, $base); $Included_Files{$source->as_string} = 1; $self->SUPER::_include_xml_document(@_); } }
sub new { my $proto = shift; my $class = ref $proto || $proto; my %args = @_; Config::Context->_require_prerequisite_modules($class); my %driver_opts = %{ $args{'options'}{'XMLSimple'} || {} }; # ForceArray for all section names # we use a regex for this, for case insensitivity # ForceArray => qr/^(?:(?:Location)|(?:LocationMatch))$/i my $match_sections = $args{'match_sections'} || []; my @force_array = map { $_->{'name'} } @$match_sections; my $self = {}; if ($args{'lower_case_names'}) { carp "Lower Case Names not supported with XML::Simple driver"; } $self->{'root_key'} = $driver_opts{'RootName'} || 'opt'; my $simple = XML::Simple->new(ForceArray => \@force_array, %driver_opts); my $filter = XML::Filter::XInclude::RememberFiles->new(Handler => $simple); my $parser = XML::SAX::ParserFactory->parser(Handler => $filter); $self->{'parser'} = $parser; if ($args{'string'}) { $self->{'string'} = $args{'string'}; } elsif($args{'file'}) { $self->{'file'} = $args{'file'}; } else { croak __PACKAGE__ . "->new(): one of 'file' or 'string' is required"; } bless $self, $class; return $self; }
sub parse { my $self = shift; %Included_Files = (); my $config; my $parser = $self->{'parser'}; if ($self->{'string'}) { $config = $parser->parse_string($self->{'string'}); } elsif($self->{'file'}) { $config = $parser->parse_uri($self->{'file'}); } # handle inclusion by recursively merging all keys named 'opt' into # the root name space my $rootkey = $self->{'root_name'} || 'opt'; while (grep { $_ eq $rootkey } keys %$config) { foreach my $key (keys %$config) { if ($key eq $rootkey) { my $sub_config = delete $config->{$key}; $config = Hash::Merge::merge($sub_config, $config); last; } } } $self->{'included_files'} = \%Included_Files; # Include the containing config file itself if ($self->{'file'}) { $self->{'included_files'}{Cwd::abs_path($self->{'file'})} = 1; } return %$config if wantarray; return $config; }
sub files { my $self = shift; $self->{'included_files'} ||= {}; my @included_files = keys %{$self->{'included_files'}}; return @included_files if wantarray; return \@included_files; }
sub config_modules { return qw( XML::Simple XML::SAX XML::Filter::XInclude ); }
1;