| 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; |