1use Test::More tests => 22;
2use Test::Exception;
3
4use strict;
5use warnings;
6no warnings 'redefine';
7
8use RDF::Trine qw(iri statement);
9use_ok('RDF::Trine::Serializer::RDFXML');
10
11
12{
13	my $model = RDF::Trine::Model->temporary_model;
14	$model->add_hashref({
15		'http://example.com/doc' => {
16			'http://example.com/predicate' => [
17				{'type' => 'literal','value' => 'Foo'},
18				{'type' => 'uri','value' => 'http://example.com/bar'},
19				'baz@en'
20			],
21		},
22	});
23
24	my $serializer = RDF::Trine::Serializer::RDFXML->new();
25	my $expect	= <<"END";
26<?xml version="1.0" encoding="utf-8"?>
27<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
28<rdf:Description xmlns:ns1="http://example.com/" rdf:about="http://example.com/doc">
29	<ns1:predicate rdf:resource="http://example.com/bar"/>
30	<ns1:predicate>Foo</ns1:predicate>
31	<ns1:predicate xml:lang="en">baz</ns1:predicate>
32</rdf:Description>
33</rdf:RDF>
34END
35
36	{
37		my $xml = $serializer->serialize_model_to_string($model);
38		is($xml, $expect, 'serialize_model_to_string 1');
39	}
40	{
41		my $iter	= $model->as_stream;
42		my $xml = $serializer->serialize_iterator_to_string($iter);
43		is($xml, $expect, 'serialize_iterator_to_string 1');
44	}
45}
46
47{
48	my $model = RDF::Trine::Model->temporary_model;
49	$model->add_hashref({
50		'./doc' => {
51			'./predicate' => [
52				{'type' => 'literal','value' => 'Foo'},
53				{'type' => 'uri','value' => './bar'},
54				'baz@en'
55			],
56		},
57	});
58
59	my $serializer = RDF::Trine::Serializer::RDFXML->new( base_uri => 'http://example.org/');
60	my $expect	= <<"END";
61<?xml version="1.0" encoding="utf-8"?>
62<rdf:RDF xml:base="http://example.org/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
63<rdf:Description xmlns:ns1="./" rdf:about="./doc">
64	<ns1:predicate rdf:resource="./bar"/>
65	<ns1:predicate>Foo</ns1:predicate>
66	<ns1:predicate xml:lang="en">baz</ns1:predicate>
67</rdf:Description>
68</rdf:RDF>
69END
70
71	{
72		my $xml = $serializer->serialize_model_to_string($model);
73		is($xml, $expect, 'serialize_model_to_string 1');
74	}
75}
76
77{
78	my $model = RDF::Trine::Model->temporary_model;
79	$model->add_hashref({
80		'_:b' => {
81			'http://example.com/ns#description' => ['quux'],
82		},
83	});
84
85	my $serializer = RDF::Trine::Serializer::RDFXML->new();
86	my $xml = $serializer->serialize_model_to_string($model);
87
88	is($xml, <<"END", 'serialize_model_to_string 2: simple literal');
89<?xml version="1.0" encoding="utf-8"?>
90<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
91<rdf:Description xmlns:ns1="http://example.com/ns#" rdf:nodeID="b">
92	<ns1:description>quux</ns1:description>
93</rdf:Description>
94</rdf:RDF>
95END
96}
97
98{
99	my $model = RDF::Trine::Model->temporary_model;
100	$model->add_hashref({
101		'_:a' => {
102			'http://example.com/ns#title' => [
103				'foo',
104				{type => 'literal', value => 'bar', datatype => 'http://www.w3.org/2001/XMLSchema#string'},
105			],
106		},
107	});
108
109	my $serializer = RDF::Trine::Serializer::RDFXML->new();
110	my $xml = $serializer->serialize_model_to_string($model);
111
112	is($xml, <<"END", 'serialize_model_to_string 3: datatype literal');
113<?xml version="1.0" encoding="utf-8"?>
114<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
115<rdf:Description xmlns:ns1="http://example.com/ns#" rdf:nodeID="a">
116	<ns1:title rdf:datatype="http://www.w3.org/2001/XMLSchema#string">bar</ns1:title>
117	<ns1:title>foo</ns1:title>
118</rdf:Description>
119</rdf:RDF>
120END
121}
122
123{
124	my $model = RDF::Trine::Model->temporary_model;
125	$model->add_hashref({
126		'_:b' => {
127			'http://example.com/ns#description' => [{type=>'uri', value=>'_:a'}],
128		},
129	});
130
131	my $serializer = RDF::Trine::Serializer::RDFXML->new();
132	my $xml = $serializer->serialize_model_to_string($model);
133
134	is($xml, <<"END", 'serialize_model_to_string 4: blank object');
135<?xml version="1.0" encoding="utf-8"?>
136<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
137<rdf:Description xmlns:ns1="http://example.com/ns#" rdf:nodeID="b">
138	<ns1:description rdf:nodeID="a"/>
139</rdf:Description>
140</rdf:RDF>
141END
142}
143
144{
145	my $model = RDF::Trine::Model->temporary_model;
146	$model->add_hashref({
147		'http://example.com/alice' => {
148			'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' => [{ type => 'resource', value => 'http://xmlns.com/foaf/0.1/Person' }],
149			'http://purl.org/net/inkel/rdf/schemas/lang/1.1#masters' => ['en'],
150			'http://xmlns.com/foaf/0.1/name' => [ 'Alice', {'type' => 'literal','value' => 'Alice', language => 'en' } ],
151		},
152	});
153
154	my $serializer = RDF::Trine::Serializer::RDFXML->new();
155	my $expect	= <<"END";
156<?xml version="1.0" encoding="utf-8"?>
157<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
158<rdf:Description xmlns:ns1="http://purl.org/net/inkel/rdf/schemas/lang/1.1#" xmlns:ns2="http://xmlns.com/foaf/0.1/" rdf:about="http://example.com/alice">
159	<ns1:masters>en</ns1:masters>
160	<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/>
161	<ns2:name>Alice</ns2:name>
162</rdf:Description>
163</rdf:RDF>
164END
165
166	my $xml = $serializer->serialize_model_to_string($model);
167	is($xml, $expect, 'serialize_model_to_string 5: multiple namespaces');
168}
169
170{
171	my $model = RDF::Trine::Model->temporary_model;
172	$model->add_hashref({
173		'_:b' => {
174			'http://example.com/' => [{type=>'uri', value=>'_:a'}],
175		},
176	});
177
178	my $serializer = RDF::Trine::Serializer::RDFXML->new();
179	throws_ok {
180		my $xml = $serializer->serialize_model_to_string($model);
181	} 'RDF::Trine::Error::SerializationError', "serializing bad predicates throws exception (uri ends with '/')";
182}
183
184{
185	my $model = RDF::Trine::Model->temporary_model;
186	$model->add_hashref({
187		'_:b' => {
188			'http://example.com/123' => [{type=>'uri', value=>'_:a'}],
189		},
190	});
191
192	my $serializer = RDF::Trine::Serializer::RDFXML->new();
193	throws_ok {
194		my $xml = $serializer->serialize_model_to_string($model);
195		warn $xml;
196	} 'RDF::Trine::Error::SerializationError', "serializing bad predicates throws exception (local part starts with digits)";
197}
198
199{
200	my $model = RDF::Trine::Model->temporary_model;
201	$model->add_hashref({
202		'http://example.com/doc' => {
203			'http://example.com/predicate' => [
204				{'type' => 'literal','value' => 'Foo'},
205				{'type' => 'uri','value' => 'http://example.com/bar'},
206				'baz@en'
207			],
208		},
209		'http://example.com/bar' => {
210			'http://example.com/predicate' => [
211				{'type' => 'literal','value' => 'Bar'},
212			],
213		},
214	});
215
216	my $serializer = RDF::Trine::Serializer::RDFXML->new();
217	my $expect	= <<"END";
218<?xml version="1.0" encoding="utf-8"?>
219<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
220<rdf:Description xmlns:ns1="http://example.com/" rdf:about="http://example.com/bar">
221	<ns1:predicate>Bar</ns1:predicate>
222</rdf:Description>
223<rdf:Description xmlns:ns1="http://example.com/" rdf:about="http://example.com/doc">
224	<ns1:predicate rdf:resource="http://example.com/bar"/>
225	<ns1:predicate>Foo</ns1:predicate>
226	<ns1:predicate xml:lang="en">baz</ns1:predicate>
227</rdf:Description>
228</rdf:RDF>
229END
230
231	{
232		my $xml = $serializer->serialize_model_to_string($model);
233		is($xml, $expect, 'serialize_model_to_string 1');
234	}
235	{
236		my $iter	= $model->as_stream;
237		my $xml = $serializer->serialize_iterator_to_string($iter);
238		is($xml, $expect, 'serialize_iterator_to_string 1');
239	}
240}
241
242{
243	my $model = RDF::Trine::Model->temporary_model;
244	$model->add_hashref({
245		'http://example.com/doc' => {
246			'http://example.com/maker' => [
247				{'type' => 'uri','value' => '_:a'},
248			],
249		},
250		'_:a' => {
251			'http://example.com/name' => [
252				{'type' => 'literal','value' => 'Alice', 'lang' => 'en'},
253			],
254			'http://example.com/homepage' => [
255				{'type' => 'uri', 'value' => 'http://example.com/' },
256			],
257		},
258	});
259
260	my $serializer = RDF::Trine::Serializer::RDFXML->new();
261	my $expect	= <<"END";
262<?xml version="1.0" encoding="utf-8"?>
263<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
264<rdf:Description xmlns:ns1="http://example.com/" rdf:about="http://example.com/doc">
265	<ns1:maker rdf:nodeID="a"/>
266</rdf:Description>
267<rdf:Description xmlns:ns1="http://example.com/" rdf:nodeID="a">
268	<ns1:homepage rdf:resource="http://example.com/"/>
269	<ns1:name xml:lang="en">Alice</ns1:name>
270</rdf:Description>
271</rdf:RDF>
272END
273
274	my $iter	= $model->bounded_description( iri('http://example.com/doc') );
275	my $xml		= $serializer->serialize_iterator_to_string( $iter );
276	is($xml, $expect, 'serialize bounded description 1');
277}
278
279{
280	my $model = RDF::Trine::Model->temporary_model;
281	$model->add_hashref({
282		'http://example.com/doc' => {
283			'http://example.com/maker' => [
284				{'type' => 'uri','value' => '_:a'},
285			],
286			'http://example.com/creator' => [
287				{'type' => 'uri','value' => '_:a'},
288			],
289		},
290		'_:a' => {
291			'http://example.com/name' => [
292				{'type' => 'literal','value' => 'Alice', 'lang' => 'en'},
293			],
294			'http://example.com/homepage' => [
295				{'type' => 'uri', 'value' => 'http://example.com/' },
296			],
297		},
298	});
299
300	my $serializer = RDF::Trine::Serializer::RDFXML->new();
301	my $expect	= <<"END";
302<?xml version="1.0" encoding="utf-8"?>
303<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
304<rdf:Description xmlns:ns1="http://example.com/" rdf:about="http://example.com/doc">
305	<ns1:creator rdf:nodeID="a"/>
306	<ns1:maker rdf:nodeID="a"/>
307</rdf:Description>
308<rdf:Description xmlns:ns1="http://example.com/" rdf:nodeID="a">
309	<ns1:homepage rdf:resource="http://example.com/"/>
310	<ns1:name xml:lang="en">Alice</ns1:name>
311</rdf:Description>
312</rdf:RDF>
313END
314
315	my $iter	= $model->bounded_description( iri('http://example.com/doc') );
316	my $xml		= $serializer->serialize_iterator_to_string( $iter );
317	is($xml, $expect, 'serialize bounded description 2');
318}
319
320{
321	my $model = RDF::Trine::Model->temporary_model;
322	$model->add_hashref({
323		'http://example.com/doc' => {
324			'http://example.com/maker' => [
325				{'type' => 'uri','value' => '_:a'},
326			],
327			'http://example.com/creator' => [
328				{'type' => 'uri','value' => '_:a'},
329			],
330		},
331		'_:a' => {
332			'http://example.com/name' => [
333				{'type' => 'literal','value' => 'Alice', 'lang' => 'en'},
334			],
335			'http://example.com/homepage' => [
336				{'type' => 'uri', 'value' => 'http://example.com/' },
337			],
338		},
339	});
340
341	my $serializer = RDF::Trine::Serializer::RDFXML->new();
342	my $expect	= <<"END";
343<?xml version="1.0" encoding="utf-8"?>
344<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
345</rdf:RDF>
346END
347
348	my $iter	= $model->bounded_description( iri('http://example.com/unknown') );
349	my $xml		= $serializer->serialize_iterator_to_string( $iter );
350	is($xml, $expect, 'serialize bounded description with unknown node');
351}
352
353{
354	my $model = RDF::Trine::Model->temporary_model();
355	my $serializer = RDF::Trine::Serializer::RDFXML->new();
356	my $expect	= <<"END";
357<?xml version="1.0" encoding="utf-8"?>
358<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
359</rdf:RDF>
360END
361
362	my $xml = $serializer->serialize_model_to_string($model);
363	is($xml, $expect, 'serialize_model_to_string with empty model');
364}
365
366{
367	my $serializer = RDF::Trine::Serializer::RDFXML->new( namespaces => { ex => 'http://example.com/' } );
368	my $model = RDF::Trine::Model->temporary_model;
369	$model->add_hashref({
370		'http://example.com/doc' => {
371			'http://example.com/maker' => [
372				{'type' => 'uri','value' => '_:a'},
373			],
374		},
375		'_:a' => {
376			'http://example.com/name' => [
377				{'type' => 'literal','value' => 'Alice', 'lang' => 'en'},
378			],
379			'http://example.com/homepage' => [
380				{'type' => 'uri', 'value' => 'http://example.com/' },
381			],
382		},
383	});
384
385	my $expect	= <<"END";
386<?xml version="1.0" encoding="utf-8"?>
387<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:ex="http://example.com/">
388<rdf:Description rdf:about="http://example.com/doc">
389	<ex:maker rdf:nodeID="a"/>
390</rdf:Description>
391<rdf:Description rdf:nodeID="a">
392	<ex:homepage rdf:resource="http://example.com/"/>
393	<ex:name xml:lang="en">Alice</ex:name>
394</rdf:Description>
395</rdf:RDF>
396END
397
398	my $iter	= $model->bounded_description( iri('http://example.com/doc') );
399	my $xml		= $serializer->serialize_iterator_to_string( $iter );
400	is($xml, $expect, 'xmlns namespaces 1');
401}
402
403{
404	my $serializer = RDF::Trine::Serializer::RDFXML->new( namespaces => {
405		foaf	=> 'http://xmlns.com/foaf/0.1/',
406		rdfs	=> "http://www.w3.org/2000/01/rdf-schema#",
407		lang	=> "http://purl.org/net/inkel/rdf/schemas/lang/1.1#",
408	} );
409	my $model = RDF::Trine::Model->temporary_model;
410	$model->add_hashref({
411		'_:a' => {
412			'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'	=> [{type => 'uri', value => 'http://xmlns.com/foaf/0.1/Person'}],
413			'http://xmlns.com/foaf/0.1/name'	=> ['Eve'],
414			'http://purl.org/net/inkel/rdf/schemas/lang/1.1#masters' => ['en','fr'],
415			'http://www.w3.org/2000/01/rdf-schema#seeAlso'	=> [{type => 'uri', value => 'http://eve.example.com/'}],
416		},
417	});
418
419	my $xml = $serializer->serialize_model_to_string($model);
420	like( $xml, qr[xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:foaf="http://xmlns.com/foaf/0.1/" xmlns:lang="http://purl.org/net/inkel/rdf/schemas/lang/1.1#" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"]sm, 'xmlns sorted in rdf:RDF tag' );
421	like( $xml, qr[<lang:masters>en</lang:masters>]sm, 'Qname literal tag' );
422	like( $xml, qr[<rdfs:seeAlso rdf:resource="http://eve.example.com/"/>]sm, 'Qname resource tag' );
423}
424
425{
426	my $serializer	= RDF::Trine::Serializer::RDFXML->new();
427	my $model		= RDF::Trine::Model->temporary_model;
428	my $base_uri		= 'http://example.org/';
429	my $url_with_amp	= "$base_uri?foo=bar&doz=baz";
430	$model->add_statement( statement( iri($base_uri), iri("http://xmlns.com/foaf/0.1/page"), iri($url_with_amp) ) );
431
432	my $xml = $serializer->serialize_model_to_string($model);
433	like( $xml, qr[&amp;]sm, 'XML entity escaping' );
434}
435
436{
437	my $serializer = RDF::Trine::Serializer::RDFXML->new( scoped_namespaces => 1, namespaces => { ex => 'http://example.com/', unused1 => 'http://example.org/not-used', unused2 => 'tag:kasei.us,2012-01-01:' } );
438	my $model = RDF::Trine::Model->temporary_model;
439	$model->add_hashref({
440		'http://example.com/doc' => {
441			'http://example.com/maker' => [
442				{'type' => 'uri','value' => '_:a'},
443			],
444		},
445		'_:a' => {
446			'http://example.com/name' => [
447				{'type' => 'literal','value' => 'Alice', 'lang' => 'en'},
448			],
449			'http://example.com/homepage' => [
450				{'type' => 'uri', 'value' => 'http://example.com/' },
451			],
452		},
453	});
454
455	my $expect	= <<"END";
456<?xml version="1.0" encoding="utf-8"?>
457<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
458<rdf:Description rdf:about="http://example.com/doc">
459	<ex:maker xmlns:ex="http://example.com/" rdf:nodeID="a"/>
460</rdf:Description>
461<rdf:Description rdf:nodeID="a">
462	<ex:homepage xmlns:ex="http://example.com/" rdf:resource="http://example.com/"/>
463	<ex:name xmlns:ex="http://example.com/" xml:lang="en">Alice</ex:name>
464</rdf:Description>
465</rdf:RDF>
466END
467
468	my $iter	= $model->bounded_description( iri('http://example.com/doc') );
469	my $xml		= $serializer->serialize_iterator_to_string( $iter );
470	is($xml, $expect, 'xmlns namespaces 2 with unused definitions');
471}
472