line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package OpenGuides::RDF; |
2
|
|
|
|
|
|
|
|
3
|
2
|
|
|
2
|
|
2814
|
use strict; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
111
|
|
4
|
|
|
|
|
|
|
|
5
|
2
|
|
|
2
|
|
14
|
use OpenGuides::Utils; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
76
|
|
6
|
|
|
|
|
|
|
|
7
|
2
|
|
|
2
|
|
13
|
use vars qw( $VERSION ); |
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
153
|
|
8
|
|
|
|
|
|
|
$VERSION = '0.15'; |
9
|
|
|
|
|
|
|
|
10
|
2
|
|
|
2
|
|
14
|
use Time::Piece; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
20
|
|
11
|
2
|
|
|
2
|
|
182
|
use URI::Escape; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
191
|
|
12
|
2
|
|
|
2
|
|
18
|
use Carp 'croak'; |
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
157
|
|
13
|
2
|
|
|
2
|
|
17
|
use HTML::Entities qw( encode_entities_numeric ); |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
161
|
|
14
|
2
|
|
|
2
|
|
15
|
use Template; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
2752
|
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
sub new { |
17
|
2
|
|
|
2
|
1
|
17
|
my ($class, @args) = @_; |
18
|
2
|
|
|
|
|
5
|
my $self = {}; |
19
|
2
|
|
|
|
|
5
|
bless $self, $class; |
20
|
2
|
|
|
|
|
8
|
$self->_init(@args); |
21
|
|
|
|
|
|
|
} |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
sub _init { |
24
|
2
|
|
|
2
|
|
7
|
my ($self, %args) = @_; |
25
|
|
|
|
|
|
|
|
26
|
2
|
|
|
|
|
5
|
my $wiki = $args{wiki}; |
27
|
|
|
|
|
|
|
|
28
|
2
|
50
|
33
|
|
|
26
|
unless ( $wiki && UNIVERSAL::isa( $wiki, "Wiki::Toolkit" ) ) { |
29
|
0
|
|
|
|
|
0
|
croak "No Wiki::Toolkit object supplied."; |
30
|
|
|
|
|
|
|
} |
31
|
2
|
|
|
|
|
10
|
$self->{wiki} = $wiki; |
32
|
|
|
|
|
|
|
|
33
|
2
|
|
|
|
|
4
|
my $config = $args{config}; |
34
|
|
|
|
|
|
|
|
35
|
2
|
50
|
33
|
|
|
18
|
unless ( $config && UNIVERSAL::isa( $config, "OpenGuides::Config" ) ) { |
36
|
0
|
|
|
|
|
0
|
croak "No OpenGuides::Config object supplied."; |
37
|
|
|
|
|
|
|
} |
38
|
2
|
|
|
|
|
5
|
$self->{config} = $config; |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
$self->{make_node_url} = sub { |
41
|
12
|
|
|
12
|
|
25
|
my ($node_name, $version) = @_; |
42
|
|
|
|
|
|
|
|
43
|
12
|
|
|
|
|
32
|
my $config = $self->{config}; |
44
|
|
|
|
|
|
|
|
45
|
12
|
|
|
|
|
49
|
my $node_url = $config->script_url . uri_escape($config->script_name) . '?'; |
46
|
12
|
100
|
|
|
|
351
|
$node_url .= 'id=' if defined $version; |
47
|
12
|
|
|
|
|
49
|
$node_url .= uri_escape($self->{wiki}->formatter->node_name_to_node_param($node_name)); |
48
|
12
|
100
|
|
|
|
503
|
$node_url .= ';version=' . uri_escape($version) if defined $version; |
49
|
|
|
|
|
|
|
|
50
|
12
|
|
|
|
|
85
|
$node_url; |
51
|
2
|
|
|
|
|
15
|
}; |
52
|
2
|
|
|
|
|
10
|
$self->{site_name} = $config->site_name; |
53
|
2
|
|
100
|
|
|
26
|
$self->{default_city} = $config->default_city || ""; |
54
|
2
|
|
100
|
|
|
27
|
$self->{default_country} = $config->default_country || ""; |
55
|
2
|
|
50
|
|
|
28
|
$self->{site_description} = $config->site_desc || ""; |
56
|
2
|
|
|
|
|
27
|
$self->{og_version} = $args{og_version}; |
57
|
|
|
|
|
|
|
|
58
|
2
|
|
|
|
|
8
|
$self; |
59
|
|
|
|
|
|
|
} |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
sub emit_rdfxml { |
62
|
6
|
|
|
6
|
1
|
186378
|
my ($self, %args) = @_; |
63
|
|
|
|
|
|
|
|
64
|
6
|
|
|
|
|
16
|
my $node_name = $args{node}; |
65
|
6
|
|
|
|
|
14
|
my $config = $self->{config}; |
66
|
6
|
|
|
|
|
11
|
my $wiki = $self->{wiki}; |
67
|
6
|
|
|
|
|
25
|
my $formatter = $wiki->formatter; |
68
|
|
|
|
|
|
|
|
69
|
6
|
|
|
|
|
52
|
my %node_data = $wiki->retrieve_node( $node_name ); |
70
|
6
|
|
|
|
|
10042
|
my %metadata = %{ $node_data{metadata} }; |
|
6
|
|
|
|
|
67
|
|
71
|
6
|
|
|
|
|
63
|
my %tt_vars = ( |
72
|
|
|
|
|
|
|
node_name => $node_name, |
73
|
|
|
|
|
|
|
version => $node_data{version}, |
74
|
|
|
|
|
|
|
site_name => $self->{site_name}, |
75
|
|
|
|
|
|
|
site_desc => $self->{site_description}, |
76
|
|
|
|
|
|
|
og_version => $self->{og_version}, |
77
|
|
|
|
|
|
|
config => $config, |
78
|
|
|
|
|
|
|
); |
79
|
|
|
|
|
|
|
|
80
|
6
|
|
|
|
|
44
|
my %defaults = ( |
81
|
|
|
|
|
|
|
city => $self->{default_city}, |
82
|
|
|
|
|
|
|
country => $self->{default_country}, |
83
|
|
|
|
|
|
|
); |
84
|
|
|
|
|
|
|
|
85
|
6
|
|
|
|
|
23
|
foreach my $var ( qw( phone fax website opening_hours_text address |
86
|
|
|
|
|
|
|
postcode city country latitude longitude |
87
|
|
|
|
|
|
|
os_x os_y map_link summary node_image ) ) { |
88
|
90
|
|
100
|
|
|
458
|
my $val = $metadata{$var}[0] || $defaults{$var} || ""; |
89
|
90
|
|
|
|
|
158
|
$tt_vars{$var} = $val; |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
|
92
|
6
|
50
|
|
|
|
12
|
my @cats = @{ $metadata{category} || [] }; |
|
6
|
|
|
|
|
42
|
|
93
|
6
|
|
|
|
|
17
|
@cats = map { { name => $_ } } @cats; |
|
0
|
|
|
|
|
0
|
|
94
|
6
|
|
|
|
|
17
|
$tt_vars{categories} = \@cats; |
95
|
|
|
|
|
|
|
|
96
|
6
|
100
|
|
|
|
13
|
my @locs = @{ $metadata{locale} || [] }; |
|
6
|
|
|
|
|
36
|
|
97
|
4
|
|
|
|
|
100
|
@locs = map { |
98
|
6
|
|
|
|
|
16
|
{ |
99
|
|
|
|
|
|
|
name => $_, |
100
|
|
|
|
|
|
|
id => $formatter->node_name_to_node_param( $_ ), |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
} @locs; |
103
|
6
|
|
|
|
|
62
|
$tt_vars{locales} = \@locs; |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
# Check for geospatialness and define container object as appropriate. |
106
|
6
|
|
|
|
|
10
|
my $is_geospatial; |
107
|
6
|
|
|
|
|
19
|
foreach my $var ( qw( os_x os_y latitude longitude address postcode |
108
|
|
|
|
|
|
|
opening_hours_text map_link ) ) { |
109
|
48
|
100
|
|
|
|
109
|
$is_geospatial = 1 if $tt_vars{$var}; |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
|
112
|
6
|
100
|
|
|
|
23
|
$is_geospatial = 1 if scalar @locs; |
113
|
|
|
|
|
|
|
|
114
|
6
|
100
|
|
|
|
28
|
$tt_vars{obj_type} = $is_geospatial ? "geo:SpatialThing" |
115
|
|
|
|
|
|
|
: "rdf:Description"; |
116
|
6
|
|
|
|
|
15
|
$tt_vars{is_geospatial} = $is_geospatial; |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
# Fix up lat and long. |
119
|
6
|
|
|
|
|
11
|
eval { |
120
|
6
|
|
|
|
|
72
|
@tt_vars{ qw( wgs84_long wgs84_lat ) } = |
121
|
|
|
|
|
|
|
OpenGuides::Utils->get_wgs84_coords( |
122
|
|
|
|
|
|
|
longitude => $tt_vars{longitude}, |
123
|
|
|
|
|
|
|
latitude => $tt_vars{latitude}, |
124
|
|
|
|
|
|
|
config => $config ); |
125
|
|
|
|
|
|
|
}; |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
# Timestamp of last edited. |
128
|
6
|
|
|
|
|
12
|
my $timestamp = $node_data{last_modified}; |
129
|
6
|
100
|
|
|
|
20
|
if ( $timestamp ) { |
130
|
|
|
|
|
|
|
# Make a Time::Piece object in order to canonicalise time. I think. |
131
|
5
|
|
|
|
|
14
|
my $timestamp_fmt = $Wiki::Toolkit::Store::Database::timestamp_fmt; |
132
|
5
|
|
|
|
|
59
|
my $time = Time::Piece->strptime($timestamp, $timestamp_fmt); |
133
|
5
|
|
|
|
|
215
|
$tt_vars{timestamp} = $time->strftime("%Y-%m-%dT%H:%M:%S"); |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
|
136
|
6
|
|
|
|
|
282
|
$tt_vars{node_uri} = $self->{make_node_url}->( $node_name ); |
137
|
6
|
|
|
|
|
22
|
$tt_vars{node_uri_with_version} |
138
|
|
|
|
|
|
|
= $self->{make_node_url}->( $node_name, |
139
|
|
|
|
|
|
|
$tt_vars{version} ); |
140
|
|
|
|
|
|
|
|
141
|
6
|
|
|
|
|
53
|
my $redirect = OpenGuides::Utils->detect_redirect( content => |
142
|
|
|
|
|
|
|
$node_data{content} ); |
143
|
6
|
100
|
|
|
|
20
|
if ( $redirect ) { |
144
|
1
|
|
|
|
|
5
|
$tt_vars{redirect} = $config->script_url . $config->script_name |
145
|
|
|
|
|
|
|
. "?id=" |
146
|
|
|
|
|
|
|
. $formatter->node_name_to_node_param( $redirect ) |
147
|
|
|
|
|
|
|
. ";format=rdf#obj"; |
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
# Escape stuff! |
151
|
6
|
|
|
|
|
84
|
foreach my $var ( keys %tt_vars ) { |
152
|
180
|
100
|
|
|
|
1258
|
if ( $tt_vars{$var} ) { |
153
|
100
|
|
|
|
|
199
|
$tt_vars{$var} = encode_entities_numeric( $tt_vars{$var} ); |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
6
|
|
|
|
|
84
|
my @revisions = $wiki->list_node_all_versions( |
158
|
|
|
|
|
|
|
name => $node_name, |
159
|
|
|
|
|
|
|
with_content => 0, |
160
|
|
|
|
|
|
|
with_metadata => 1, |
161
|
|
|
|
|
|
|
); |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
# We want all users who have edited the page listed as contributors, |
164
|
|
|
|
|
|
|
# but only once each |
165
|
6
|
|
|
|
|
5355
|
foreach my $rev ( @revisions ) { |
166
|
7
|
|
|
|
|
85
|
my $username = $rev->{metadata}{username}; |
167
|
7
|
100
|
66
|
|
|
145
|
next unless defined $username && length $username; |
168
|
|
|
|
|
|
|
|
169
|
6
|
|
|
|
|
11
|
my $user_id = $username; |
170
|
6
|
|
|
|
|
20
|
$user_id =~ s/\s+/_/g; |
171
|
|
|
|
|
|
|
|
172
|
6
|
|
50
|
|
|
50
|
$tt_vars{contributors}{$username} ||= |
173
|
|
|
|
|
|
|
{ |
174
|
|
|
|
|
|
|
username => encode_entities_numeric($username), |
175
|
|
|
|
|
|
|
user_id => encode_entities_numeric($user_id), |
176
|
|
|
|
|
|
|
}; |
177
|
|
|
|
|
|
|
} |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
# OK, we've set all our template variables; now process the template. |
180
|
6
|
|
|
|
|
136
|
my $template_path = $config->template_path; |
181
|
6
|
|
50
|
|
|
82
|
my $custom_template_path = $config->custom_template_path || ""; |
182
|
6
|
|
|
|
|
118
|
my $tt = Template->new( { |
183
|
|
|
|
|
|
|
INCLUDE_PATH => "$custom_template_path:$template_path" } ); |
184
|
|
|
|
|
|
|
|
185
|
6
|
|
|
|
|
3166
|
$tt_vars{full_cgi_url} = $config->script_url . $config->script_name; |
186
|
|
|
|
|
|
|
|
187
|
6
|
|
|
|
|
65
|
my $rdf; |
188
|
6
|
|
|
|
|
31
|
$tt->process( "node_rdf.tt", \%tt_vars, \$rdf ); |
189
|
6
|
|
33
|
|
|
684
|
$rdf ||= "ERROR: " . $tt->error; |
190
|
6
|
|
|
|
|
62
|
return $rdf; |
191
|
|
|
|
|
|
|
} |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
=head1 NAME |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
OpenGuides::RDF - An OpenGuides plugin to output RDF/XML. |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
=head1 DESCRIPTION |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
Does all the RDF stuff for OpenGuides. Distributed and installed as |
200
|
|
|
|
|
|
|
part of the OpenGuides project, not intended for independent |
201
|
|
|
|
|
|
|
installation. This documentation is probably only useful to OpenGuides |
202
|
|
|
|
|
|
|
developers. |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
=head1 SYNOPSIS |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
use Wiki::Toolkit; |
207
|
|
|
|
|
|
|
use OpenGuides::Config; |
208
|
|
|
|
|
|
|
use OpenGuides::RDF; |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
my $wiki = Wiki::Toolkit->new( ... ); |
211
|
|
|
|
|
|
|
my $config = OpenGuides::Config->new( file => "wiki.conf" ); |
212
|
|
|
|
|
|
|
my $rdf_writer = OpenGuides::RDF->new( wiki => $wiki, |
213
|
|
|
|
|
|
|
config => $config ); |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
# RDF version of a node. |
216
|
|
|
|
|
|
|
print "Content-Type: application/rdf+xml\n\n"; |
217
|
|
|
|
|
|
|
print $rdf_writer->emit_rdfxml( node => "Masala Zone, N1 0NU" ); |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
=head1 METHODS |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
=over 4 |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
=item B |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
my $rdf_writer = OpenGuides::RDF->new( wiki => $wiki, |
226
|
|
|
|
|
|
|
config => $config ); |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
C must be a L object and C must be an |
229
|
|
|
|
|
|
|
L object. Both arguments mandatory. |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
=item B |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
$wiki->write_node( "Masala Zone, N1 0NU", |
235
|
|
|
|
|
|
|
"Quick and tasty Indian food", |
236
|
|
|
|
|
|
|
$checksum, |
237
|
|
|
|
|
|
|
{ comment => "New page", |
238
|
|
|
|
|
|
|
username => "Kake", |
239
|
|
|
|
|
|
|
locale => "Islington" } |
240
|
|
|
|
|
|
|
); |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
print "Content-Type: application/rdf+xml\n\n"; |
243
|
|
|
|
|
|
|
print $rdf_writer->emit_rdfxml( node => "Masala Zone, N1 0NU" ); |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
B Some of the fields emitted by the RDF/XML generator are taken |
246
|
|
|
|
|
|
|
from the node metadata. The form of this metadata is I mandated |
247
|
|
|
|
|
|
|
by L. Your wiki application should make sure to store some or |
248
|
|
|
|
|
|
|
all of the following metadata when calling C: |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
=over 4 |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
=item B - The postcode or zip code of the place discussed by the node. Defaults to the empty string. |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
=item B - The name of the city that the node is in. If not supplied, then the value of C in the config object supplied to C, if available, otherwise the empty string. |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
=item B - The name of the country that the node is in. If not supplied, then the value of C in the config object supplied to C will be used, if available, otherwise the empty string. |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
=item B - An identifier for the person who made the latest edit to the node. This person will be listed as a contributor (Dublin Core). Defaults to empty string. |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
=item B - The value of this can be a scalar or an arrayref, since some places have a plausible claim to being in more than one locale. Each of these is put in as a C attribute. |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
=item B - Only one number supported at the moment. No validation. |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
=item B - No validation. |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
=item B - A freeform text field. |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
=back |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
=back |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
=head1 SEE ALSO |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
=over 4 |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
=item * L |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
=item * L |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
=item * L |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
=back |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
=head1 AUTHOR |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
The OpenGuides Project (openguides-dev@lists.openguides.org) |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
=head1 COPYRIGHT |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
Copyright (C) 2003-2013 The OpenGuides Project. All Rights Reserved. |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
This module is free software; you can redistribute it and/or modify it |
293
|
|
|
|
|
|
|
under the same terms as Perl itself. |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
=head1 CREDITS |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
Code in this module written by Kake Pugh and Earle Martin. Dan Brickley, Matt |
298
|
|
|
|
|
|
|
Biddulph and other inhabitants of #swig on irc.freenode.net gave useful feedback |
299
|
|
|
|
|
|
|
and advice. |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
=cut |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
1; |