File Coverage

blib/lib/WWW/Sitemap/XML.pm
Criterion Covered Total %
statement 8 10 80.0
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 12 14 85.7


line stmt bran cond sub pod time code
1 5     5   416567 use strict;
  5         12  
  5         210  
2 5     5   28 use warnings;
  5         11  
  5         266  
3             package WWW::Sitemap::XML;
4             BEGIN {
5 5     5   168 $WWW::Sitemap::XML::AUTHORITY = 'cpan:AJGB';
6             }
7             {
8             $WWW::Sitemap::XML::VERSION = '1.121160';
9             }
10             #ABSTRACT: XML Sitemap protocol
11              
12 5     5   2948 use Moose;
  0            
  0            
13              
14             use WWW::Sitemap::XML::URL;
15             use XML::LibXML 1.70;
16             use Scalar::Util qw( blessed );
17              
18             use WWW::Sitemap::XML::Types qw( SitemapURL );
19              
20              
21             has '_rootcontainer' => (
22             is => 'ro',
23             traits => [qw( Array )],
24             isa => 'ArrayRef',
25             default => sub { [] },
26             handles => {
27             _add_entry => 'push',
28             _count_entries => 'count',
29             _entries => 'elements',
30             }
31             );
32              
33             has '_first_loc' => (
34             is => 'rw',
35             );
36              
37             has '_check_req_interface' => (
38             is => 'ro',
39             default => sub {
40             sub {
41             die 'object does not implement WWW::Sitemap::XML::URL::Interface'
42             unless is_SitemapURL($_[0]);
43             }
44             }
45             );
46              
47             has '_entry_class' => (
48             is => 'ro',
49             default => 'WWW::Sitemap::XML::URL'
50             );
51              
52             has '_root_ns' => (
53             is => 'ro',
54             default => sub {
55             {
56             'xmlns' => "http://www.sitemaps.org/schemas/sitemap/0.9",
57             'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance",
58             'xsi:schemaLocation' => join(' ',
59             'http://www.sitemaps.org/schemas/sitemap/0.9',
60             'http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd'
61             ),
62             }
63             },
64             );
65              
66             has '_root_elem' => (
67             is => 'ro',
68             default => 'urlset',
69             );
70              
71             sub _pre_check_add {
72             my ($self, $entry) = @_;
73              
74             $self->_check_req_interface->($entry);
75              
76             die "Single file cannot contain more then 50 000 entries"
77             if $self->_count_entries >= 50_000;
78              
79             my $loc = $entry->loc;
80              
81             die "URL cannot be longer then 2048 characters"
82             unless length $loc < 2048;
83              
84             my($scheme, $authority) = $loc =~ m|(?:([^:/?#]+):)?(?://([^/?#]*))?|;
85             my $new = "$scheme://$authority";
86             if ( $self->_count_entries ) {
87             my $first = $self->_first_loc;
88              
89             die "All URLs in same file should use the same protocol and reside on the "
90             ."same host: $first, not $new" unless $first eq $new;
91             } else {
92             $self->_first_loc( $new );
93             }
94             }
95              
96              
97             sub add {
98             my $self = shift;
99              
100             my $class = $self->_entry_class;
101              
102             my $arg = @_ == 1 && blessed $_[0] ?
103             shift @_ : $class->new(@_);
104              
105             $self->_pre_check_add($arg);
106              
107             $self->_add_entry( $arg );
108             }
109              
110              
111             sub urls { shift->_entries }
112              
113              
114             sub load {
115             my $self = shift;
116              
117             $self->add($_) for $self->read(@_);
118             }
119              
120              
121             sub read {
122             my ($self, %args) = @_;
123              
124             my @entries;
125             my $class = $self->_entry_class;
126              
127             my $xml = XML::LibXML->load_xml( %args );
128              
129             for my $url ( $xml->getDocumentElement->nonBlankChildNodes() ) {
130             push @entries,
131             $class->new(
132             map { $_->nodeName => $_->textContent } $url->nonBlankChildNodes
133             );
134             }
135              
136             return @entries;
137             }
138              
139              
140             sub write {
141             my ($self, $fh, $format) = @_;
142              
143             $format ||= 0;
144              
145             my $writer = 'toFH';
146             my $xml = $self->as_xml;
147              
148             unless ( ref $fh ) {
149             $writer = 'toFile';
150             if ( $fh =~ /\.gz$/i ) {
151             $xml->setCompression(8);
152             }
153             }
154              
155             $xml->$writer( $fh, $format );
156             }
157              
158              
159             sub as_xml {
160             my $self = shift;
161              
162             my $xml = XML::LibXML->createDocument('1.0','UTF-8');
163             my $root = $xml->createElement($self->_root_elem);
164              
165             while (my ($k, $v) = each %{ $self->_root_ns() } ) {
166             $root->setAttribute($k, $v);
167             };
168              
169             $root->appendChild($_) for
170             map {
171             my $xml = $_->as_xml;
172             blessed $xml ? $xml : XML::LibXML->load_xml(string => $xml)->documentElement()
173             } $self->_entries;
174              
175             $xml->setDocumentElement($root);
176              
177             return $xml;
178             }
179              
180              
181             __PACKAGE__->meta->make_immutable;
182              
183             1;
184              
185              
186             __END__
187             =pod
188              
189             =encoding utf-8
190              
191             =head1 NAME
192              
193             WWW::Sitemap::XML - XML Sitemap protocol
194              
195             =head1 VERSION
196              
197             version 1.121160
198              
199             =head1 SYNOPSIS
200              
201             use WWW::Sitemap::XML;
202              
203             my $map = WWW::Sitemap::XML->new();
204              
205             # add new url
206             $map->add( 'http://mywebsite.com/' );
207              
208             # or
209             $map->add(
210             loc => 'http://mywebsite.com/',
211             lastmod => '2010-11-22',
212             changefreq => 'monthly',
213             priority => 1.0,
214             );
215              
216             # or
217             $map->add(
218             WWW::Sitemap::XML::URL->new(
219             loc => 'http://mywebsite.com/',
220             lastmod => '2010-11-22',
221             changefreq => 'monthly',
222             priority => 1.0,
223             )
224             );
225              
226             # read URLs from existing sitemap.xml file
227             my @urls = $map->read( 'sitemap.xml' );
228              
229             # load urls from existing sitemap.xml file
230             $map->load( 'sitemap.xml' );
231              
232             # get XML::LibXML object
233             my $xml = $map->as_xml;
234              
235             print $xml->toString(1);
236              
237             # write to file
238             $map->write( 'sitemap.xml', my $pretty_print = 1 );
239              
240             # write compressed
241             $map->write( 'sitemap.xml.gz' );
242              
243             =head1 DESCRIPTION
244              
245             Read and write sitemap XML files as defined at L<http://www.sitemaps.org/>.
246              
247             =head1 METHODS
248              
249             =head2 add($url|%attrs)
250              
251             $map->add(
252             WWW::Sitemap::XML::URL->new(
253             loc => 'http://mywebsite.com/',
254             lastmod => '2010-11-22',
255             changefreq => 'monthly',
256             priority => 1.0,
257             )
258             );
259              
260             Add the C<$url> object representing single page in the sitemap.
261              
262             Accepts blessed objects implementing L<WWW::Sitemap::XML::URL::Interface>.
263              
264             Otherwise the arguments C<%attrs> are passed as-is to create new
265             L<WWW::Sitemap::XML::URL> object.
266              
267             $map->add(
268             loc => 'http://mywebsite.com/',
269             lastmod => '2010-11-22',
270             changefreq => 'monthly',
271             priority => 1.0,
272             );
273              
274             # single url argument
275             $map->add( 'http://mywebsite.com/' );
276              
277             # is same as
278             $map->add( loc => 'http://mywebsite.com/' );
279              
280             Performs basic validation of URLs added:
281              
282             =over
283              
284             =item * maximum of 50 000 URLs in single sitemap
285              
286             =item * URL no longer then 2048 characters
287              
288             =item * all URLs should use the same protocol and reside on same host
289              
290             =back
291              
292             =head2 urls
293              
294             my @urls = $map->urls;
295              
296             Returns a list of all URL objects added to sitemap.
297              
298             =head2 load(%sitemap_location)
299              
300             $map->load( location => $sitemap_file );
301              
302             It is a shortcut for:
303              
304             $map->add($_) for $map->read( location => $sitemap_file );
305              
306             Please see L<"read"> for details.
307              
308             =head2 read(%sitemap_location)
309              
310             # file or url to sitemap
311             my @urls = $map->read( location => $file_or_url );
312              
313             # file handle
314             my @urls = $map->read( IO => $fh );
315              
316             # XML string
317             my @urls = $map->read( string => $xml );
318              
319             Read the sitemap from file, URL, open file handle or string and return the list of
320             L<WWW::Sitemap::XML::URL> objects representing C<E<lt>urlE<gt>> elements.
321              
322             =head2 write($file, $format = 0)
323              
324             # write to file
325             $map->write( 'sitemap.xml', my $pretty_print = 1);
326              
327             # or
328             my $fh = IO::File->new();
329             $fh->open('sitemap.xml', 'w');
330             $map->write( $fh, my $pretty_print = 1);
331             $cfh->close;
332              
333             # write compressed
334             $map->write( 'sitemap.xml.gz' );
335              
336             Write XML sitemap to C<$file> - a file name or L<IO::Handle> object.
337              
338             If file names ends in C<.gz> then the output file will be compressed by
339             setting compression on XML object - please note that it requires I<libxml2> to
340             be compiled with I<zlib> support.
341              
342             Optional C<$format> is passed to C<toFH> or C<toFile> methods
343             (depending on the type of C<$file>, respectively for file handle and file name)
344             as described in L<XML::LibXML>.
345              
346             =head2 as_xml
347              
348             my $xml = $map->as_xml;
349              
350             # pretty print
351             print $xml->toString(1);
352              
353             # write compressed
354             $xml->setCompression(8);
355             $xml->toFile( 'sitemap.xml.gz' );
356              
357             Returns L<XML::LibXML::Document> object representing the sitemap in XML format.
358              
359             The C<E<lt>urlE<gt>> elements are built by calling I<as_xml> on all URL objects
360             added into sitemap.
361              
362             =head1 SEE ALSO
363              
364             Please see those modules/websites for more information related to this module.
365              
366             =over 4
367              
368             =item *
369              
370             L<WWW::SitemapIndex::XML>
371              
372             =item *
373              
374             L<http://www.sitemaps.org/>
375              
376             =item *
377              
378             L<Search::Sitemap>
379              
380             =back
381              
382             =head1 AUTHOR
383              
384             Alex J. G. BurzyÅ„ski <ajgb@cpan.org>
385              
386             =head1 COPYRIGHT AND LICENSE
387              
388             This software is copyright (c) 2010 by Alex J. G. BurzyÅ„ski <ajgb@cpan.org>.
389              
390             This is free software; you can redistribute it and/or modify it under
391             the same terms as the Perl 5 programming language system itself.
392              
393             =cut
394