70cac4e1fe8cdc69f092ade6c3cbaf6cc1b982ec
1 /**
2 * \brief RDF manipulation functions
3 *
4 * FIXME: move these to xml/ instead of dialogs/
5 *
6 * Authors:
7 * Kees Cook <kees@outflux.net>
8 * Jon Phillips <jon@rejon.org>
9 *
10 * Copyright (C) 2004 Kees Cook <kees@outflux.net>
11 * Copyright (C) 2006 Jon Phillips <jon@rejon.org>
12 *
13 * Released under GNU GPL, read the file 'COPYING' for more information
14 *
15 */
17 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
23 #include "xml/repr.h"
24 #include "rdf.h"
25 #include "sp-item-group.h"
26 #include "inkscape.h"
28 /*
30 Example RDF XML from various places...
32 <rdf:RDF xmlns="http://creativecommons.org/ns#"
33 xmlns:dc="http://purl.org/dc/elements/1.1/"
34 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
35 <Work rdf:about="">
36 <dc:title>title of work</dc:title>
37 <dc:date>year</dc:date>
38 <dc:description>description of work</dc:description>
39 <dc:creator><Agent>
40 <dc:title>creator</dc:title>
41 </Agent></dc:creator>
42 <dc:rights><Agent>
43 <dc:title>holder</dc:title>
44 </Agent></dc:rights>
45 <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
46 <dc:source rdf:resource="source"/>
47 <license rdf:resource="http://creativecommons.org/licenses/by/2.0/"
48 />
49 </Work>
52 <rdf:RDF xmlns="http://creativecommons.org/ns#"
53 xmlns:dc="http://purl.org/dc/elements/1.1/"
54 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
55 <Work rdf:about="">
56 <dc:title>SVG Road Signs</dc:title>
57 <dc:rights><Agent>
58 <dc:title>John Cliff</dc:title>
59 </Agent></dc:rights>
60 <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
61 <license rdf:resource="http://creativecommons.org/ns#PublicDomain" />
62 </Work>
64 <License rdf:about="http://creativecommons.org/ns#PublicDomain">
65 <permits rdf:resource="http://creativecommons.org/ns#Reproduction" />
66 <permits rdf:resource="http://creativecommons.org/ns#Distribution" />
67 <permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
68 </License>
70 </rdf:RDF>
73 Bag example:
75 <dc:subject>
76 <rdf:Bag>
77 <rdf:li>open clip art logo</rdf:li>
78 <rdf:li>images</rdf:li>
79 <rdf:li>logo</rdf:li>
80 <rdf:li>clip art</rdf:li>
81 <rdf:li>ocal</rdf:li>
82 <rdf:li>logotype</rdf:li>
83 <rdf:li>filetype</rdf:li>
84 </rdf:Bag>
85 </dc:subject>
88 */
90 struct rdf_double_t rdf_license_empty [] = {
91 { NULL, NULL }
92 };
94 struct rdf_double_t rdf_license_cc_a [] = {
95 { "cc:permits", "http://creativecommons.org/ns#Reproduction", },
96 { "cc:permits", "http://creativecommons.org/ns#Distribution", },
97 { "cc:requires", "http://creativecommons.org/ns#Notice", },
98 { "cc:requires", "http://creativecommons.org/ns#Attribution", },
99 { "cc:permits", "http://creativecommons.org/ns#DerivativeWorks", },
100 { NULL, NULL }
101 };
103 struct rdf_double_t rdf_license_cc_a_sa [] = {
104 { "cc:permits", "http://creativecommons.org/ns#Reproduction", },
105 { "cc:permits", "http://creativecommons.org/ns#Distribution", },
106 { "cc:requires", "http://creativecommons.org/ns#Notice", },
107 { "cc:requires", "http://creativecommons.org/ns#Attribution", },
108 { "cc:permits", "http://creativecommons.org/ns#DerivativeWorks", },
109 { "cc:requires", "http://creativecommons.org/ns#ShareAlike", },
110 { NULL, NULL }
111 };
113 struct rdf_double_t rdf_license_cc_a_nd [] = {
114 { "cc:permits", "http://creativecommons.org/ns#Reproduction", },
115 { "cc:permits", "http://creativecommons.org/ns#Distribution", },
116 { "cc:requires", "http://creativecommons.org/ns#Notice", },
117 { "cc:requires", "http://creativecommons.org/ns#Attribution", },
118 { NULL, NULL }
119 };
121 struct rdf_double_t rdf_license_cc_a_nc [] = {
122 { "cc:permits", "http://creativecommons.org/ns#Reproduction", },
123 { "cc:permits", "http://creativecommons.org/ns#Distribution", },
124 { "cc:requires", "http://creativecommons.org/ns#Notice", },
125 { "cc:requires", "http://creativecommons.org/ns#Attribution", },
126 { "cc:prohibits", "http://creativecommons.org/ns#CommercialUse", },
127 { "cc:permits", "http://creativecommons.org/ns#DerivativeWorks", },
128 { NULL, NULL }
129 };
131 struct rdf_double_t rdf_license_cc_a_nc_sa [] = {
132 { "cc:permits", "http://creativecommons.org/ns#Reproduction", },
133 { "cc:permits", "http://creativecommons.org/ns#Distribution", },
134 { "cc:requires", "http://creativecommons.org/ns#Notice", },
135 { "cc:requires", "http://creativecommons.org/ns#Attribution", },
136 { "cc:prohibits", "http://creativecommons.org/ns#CommercialUse", },
137 { "cc:permits", "http://creativecommons.org/ns#DerivativeWorks", },
138 { "cc:requires", "http://creativecommons.org/ns#ShareAlike", },
139 { NULL, NULL }
140 };
142 struct rdf_double_t rdf_license_cc_a_nc_nd [] = {
143 { "cc:permits", "http://creativecommons.org/ns#Reproduction", },
144 { "cc:permits", "http://creativecommons.org/ns#Distribution", },
145 { "cc:requires", "http://creativecommons.org/ns#Notice", },
146 { "cc:requires", "http://creativecommons.org/ns#Attribution", },
147 { "cc:prohibits", "http://creativecommons.org/ns#CommercialUse", },
148 { NULL, NULL }
149 };
151 struct rdf_double_t rdf_license_pd [] = {
152 { "cc:permits", "http://creativecommons.org/ns#Reproduction", },
153 { "cc:permits", "http://creativecommons.org/ns#Distribution", },
154 { "cc:permits", "http://creativecommons.org/ns#DerivativeWorks", },
155 { NULL, NULL }
156 };
158 struct rdf_double_t rdf_license_freeart [] = {
159 { "cc:permits", "http://creativecommons.org/ns#Reproduction", },
160 { "cc:permits", "http://creativecommons.org/ns#Distribution", },
161 { "cc:permits", "http://creativecommons.org/ns#DerivativeWorks", },
162 { "cc:requires", "http://creativecommons.org/ns#ShareAlike", },
163 { "cc:requires", "http://creativecommons.org/ns#Notice", },
164 { "cc:requires", "http://creativecommons.org/ns#Attribution", },
165 { NULL, NULL }
166 };
168 struct rdf_double_t rdf_license_ofl [] = {
169 { "cc:permits", "http://scripts.sil.org/pub/OFL/Reproduction", },
170 { "cc:permits", "http://scripts.sil.org/pub/OFL/Distribution", },
171 { "cc:permits", "http://scripts.sil.org/pub/OFL/Embedding", },
172 { "cc:permits", "http://scripts.sil.org/pub/OFL/DerivativeWorks", },
173 { "cc:requires", "http://scripts.sil.org/pub/OFL/Notice", },
174 { "cc:requires", "http://scripts.sil.org/pub/OFL/Attribution", },
175 { "cc:requires", "http://scripts.sil.org/pub/OFL/ShareAlike", },
176 { "cc:requires", "http://scripts.sil.org/pub/OFL/DerivativeRenaming", },
177 { "cc:requires", "http://scripts.sil.org/pub/OFL/BundlingWhenSelling", },
178 { NULL, NULL }
179 };
181 struct rdf_license_t rdf_licenses [] = {
182 { N_("CC Attribution"),
183 "http://creativecommons.org/licenses/by/3.0/",
184 rdf_license_cc_a,
185 },
187 { N_("CC Attribution-ShareAlike"),
188 "http://creativecommons.org/licenses/by-sa/3.0/",
189 rdf_license_cc_a_sa,
190 },
192 { N_("CC Attribution-NoDerivs"),
193 "http://creativecommons.org/licenses/by-nd/3.0/",
194 rdf_license_cc_a_nd,
195 },
197 { N_("CC Attribution-NonCommercial"),
198 "http://creativecommons.org/licenses/by-nc/3.0/",
199 rdf_license_cc_a_nc,
200 },
202 { N_("CC Attribution-NonCommercial-ShareAlike"),
203 "http://creativecommons.org/licenses/by-nc-sa/3.0/",
204 rdf_license_cc_a_nc_sa,
205 },
207 { N_("CC Attribution-NonCommercial-NoDerivs"),
208 "http://creativecommons.org/licenses/by-nc-nd/3.0/",
209 rdf_license_cc_a_nc_nd,
210 },
212 { N_("Public Domain"),
213 "http://creativecommons.org/licenses/publicdomain/",
214 rdf_license_pd,
215 },
217 { N_("FreeArt"),
218 "http://artlibre.org/licence.php/lalgb.html",
219 rdf_license_freeart,
220 },
222 { N_("Open Font License"),
223 "http://scripts.sil.org/OFL",
224 rdf_license_ofl,
225 },
227 { NULL, NULL, rdf_license_empty, }
228 };
230 #define XML_TAG_NAME_SVG "svg:svg"
231 #define XML_TAG_NAME_METADATA "svg:metadata"
232 #define XML_TAG_NAME_RDF "rdf:RDF"
233 #define XML_TAG_NAME_WORK "cc:Work"
234 #define XML_TAG_NAME_LICENSE "cc:License"
236 // Remember when using the "title" and "tip" elements to pass them through
237 // the localization functions when you use them!
238 struct rdf_work_entity_t rdf_work_entities [] = {
239 { "title", N_("Title"), "dc:title", RDF_CONTENT,
240 N_("Name by which this document is formally known."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
241 },
242 { "date", N_("Date"), "dc:date", RDF_CONTENT,
243 N_("Date associated with the creation of this document (YYYY-MM-DD)."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
244 },
245 { "format", N_("Format"), "dc:format", RDF_CONTENT,
246 N_("The physical or digital manifestation of this document (MIME type)."), RDF_FORMAT_LINE, RDF_EDIT_HARDCODED,
247 },
248 { "type", N_("Type"), "dc:type", RDF_RESOURCE,
249 N_("Type of document (DCMI Type)."), RDF_FORMAT_LINE, RDF_EDIT_HARDCODED,
250 },
252 { "creator", N_("Creator"), "dc:creator", RDF_AGENT,
253 N_("Name of entity primarily responsible for making the content of this document."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
254 },
255 { "rights", N_("Rights"), "dc:rights", RDF_AGENT,
256 N_("Name of entity with rights to the Intellectual Property of this document."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
257 },
258 { "publisher", N_("Publisher"), "dc:publisher", RDF_AGENT,
259 N_("Name of entity responsible for making this document available."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
260 },
262 { "identifier", N_("Identifier"), "dc:identifier", RDF_CONTENT,
263 N_("Unique URI to reference this document."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
264 },
265 { "source", N_("Source"), "dc:source", RDF_CONTENT,
266 N_("Unique URI to reference the source of this document."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
267 },
268 { "relation", N_("Relation"), "dc:relation", RDF_CONTENT,
269 N_("Unique URI to a related document."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
270 },
271 { "language", N_("Language"), "dc:language", RDF_CONTENT,
272 N_("Two-letter language tag with optional subtags for the language of this document. (e.g. 'en-GB')"), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
273 },
274 { "subject", N_("Keywords"), "dc:subject", RDF_BAG,
275 N_("The topic of this document as comma-separated key words, phrases, or classifications."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
276 },
277 // TRANSLATORS: "Coverage": the spatial or temporal characteristics of the content.
278 // For info, see Appendix D of http://www.w3.org/TR/1998/WD-rdf-schema-19980409/
279 { "coverage", N_("Coverage"), "dc:coverage", RDF_CONTENT,
280 N_("Extent or scope of this document."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
281 },
283 { "description", N_("Description"), "dc:description", RDF_CONTENT,
284 N_("A short account of the content of this document."), RDF_FORMAT_MULTILINE, RDF_EDIT_GENERIC,
285 },
287 // FIXME: need to handle 1 agent per line of input
288 { "contributor", N_("Contributors"), "dc:contributor", RDF_AGENT,
289 N_("Names of entities responsible for making contributions to the content of this document."), RDF_FORMAT_MULTILINE, RDF_EDIT_GENERIC,
290 },
292 // TRANSLATORS: URL to a page that defines the license for the document
293 { "license_uri", N_("URI"), "cc:license", RDF_RESOURCE,
294 // TRANSLATORS: this is where you put a URL to a page that defines the license
295 N_("URI to this document's license's namespace definition."), RDF_FORMAT_LINE, RDF_EDIT_SPECIAL,
296 },
298 // TRANSLATORS: fragment of XML representing the license of the document
299 { "license_fragment", N_("Fragment"), "License", RDF_XML,
300 N_("XML fragment for the RDF 'License' section."), RDF_FORMAT_MULTILINE, RDF_EDIT_SPECIAL,
301 },
303 { NULL, NULL, NULL, RDF_CONTENT,
304 NULL, RDF_FORMAT_LINE, RDF_EDIT_HARDCODED,
305 }
306 };
308 /**
309 * \brief Retrieves a known RDF/Work entity by name
310 * \return A pointer to an RDF/Work entity
311 * \param name The desired RDF/Work entity
312 *
313 */
314 struct rdf_work_entity_t *
315 rdf_find_entity(gchar const * name)
316 {
317 struct rdf_work_entity_t *entity;
318 for (entity=rdf_work_entities; entity->name; entity++) {
319 if (strcmp(entity->name,name)==0) break;
320 }
321 if (entity->name) return entity;
322 return NULL;
323 }
325 /*
326 * Takes the inkscape rdf struct and spits out a static RDF, which is only
327 * useful for testing. We must merge the rdf struct into the XML DOM for
328 * changes to be saved.
329 */
330 /*
332 Since g_markup_printf_escaped doesn't exist for most people's glib
333 right now, this function will remain commented out since it's only
334 for generic debug anyway. --Kees
336 gchar *
337 rdf_string(struct rdf_t * rdf)
338 {
339 gulong overall=0;
340 gchar *string=NULL;
342 gchar *rdf_head="\
343 <rdf:RDF xmlns=\"http://creativecommons.org/ns#\"\
344 xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\
345 xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\
346 ";
347 gchar *work_head="\
348 <Work rdf:about=\"\">\
349 <dc:type rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\" />\
350 ";
351 gchar *work_title=NULL;
352 gchar *work_date=NULL;
353 gchar *work_description=NULL;
354 gchar *work_creator=NULL;
355 gchar *work_owner=NULL;
356 gchar *work_source=NULL;
357 gchar *work_license=NULL;
358 gchar *license_head=NULL;
359 gchar *license=NULL;
360 gchar *license_end="</License>\n";
361 gchar *work_end="</Work>\n";
362 gchar *rdf_end="</rdf:RDF>\n";
364 if (rdf && rdf->work_title && rdf->work_title[0]) {
365 work_title=g_markup_printf_escaped(" <dc:title>%s</dc:title>\n",
366 rdf->work_title);
367 overall+=strlen(work_title);
368 }
369 if (rdf && rdf->work_date && rdf->work_date[0]) {
370 work_date=g_markup_printf_escaped(" <dc:date>%s</dc:date>\n",
371 rdf->work_date);
372 overall+=strlen(work_date);
373 }
374 if (rdf && rdf->work_description && rdf->work_description[0]) {
375 work_description=g_markup_printf_escaped(" <dc:description>%s</dc:description>\n",
376 rdf->work_description);
377 overall+=strlen(work_description);
378 }
379 if (rdf && rdf->work_creator && rdf->work_creator[0]) {
380 work_creator=g_markup_printf_escaped(" <dc:creator><Agent>\
381 <dc:title>%s</dc:title>\
382 </Agent></dc:creator>\n",
383 rdf->work_creator);
384 overall+=strlen(work_creator);
385 }
386 if (rdf && rdf->work_owner && rdf->work_owner[0]) {
387 work_owner=g_markup_printf_escaped(" <dc:rights><Agent>\
388 <dc:title>%s</dc:title>\
389 </Agent></dc:rights>\n",
390 rdf->work_owner);
391 overall+=strlen(work_owner);
392 }
393 if (rdf && rdf->work_source && rdf->work_source[0]) {
394 work_source=g_markup_printf_escaped(" <dc:source rdf:resource=\"%s\" />\n",
395 rdf->work_source);
396 overall+=strlen(work_source);
397 }
398 if (rdf && rdf->license && rdf->license->work_rdf && rdf->license->work_rdf[0]) {
399 work_license=g_markup_printf_escaped(" <license rdf:resource=\"%s\" />\n",
400 rdf->license->work_rdf);
401 overall+=strlen(work_license);
403 license_head=g_markup_printf_escaped("<License rdf:about=\"%s\">\n",
404 rdf->license->work_rdf);
405 overall+=strlen(license_head);
406 overall+=strlen(rdf->license->license_rdf);
407 overall+=strlen(license_end);
408 }
410 overall+=strlen(rdf_head)+strlen(rdf_end);
411 overall+=strlen(work_head)+strlen(work_end);
413 overall++; // NULL term
415 if (!(string=(gchar*)g_malloc(overall))) {
416 return NULL;
417 }
419 string[0]='\0';
420 strcat(string,rdf_head);
421 strcat(string,work_head);
423 if (work_title) strcat(string,work_title);
424 if (work_date) strcat(string,work_date);
425 if (work_description) strcat(string,work_description);
426 if (work_creator) strcat(string,work_creator);
427 if (work_owner) strcat(string,work_owner);
428 if (work_source) strcat(string,work_source);
429 if (work_license) strcat(string,work_license);
431 strcat(string,work_end);
432 if (license_head) {
433 strcat(string,license_head);
434 strcat(string,rdf->license->license_rdf);
435 strcat(string,license_end);
436 }
437 strcat(string,rdf_end);
439 return string;
440 }
441 */
444 /**
445 * \brief Pull the text out of an RDF entity, depends on how it's stored
446 * \return A pointer to the entity's static contents as a string
447 * \param repr The XML element to extract from
448 * \param entity The desired RDF/Work entity
449 *
450 */
451 const gchar *
452 rdf_get_repr_text ( Inkscape::XML::Node * repr, struct rdf_work_entity_t * entity )
453 {
454 g_return_val_if_fail (repr != NULL, NULL);
455 g_return_val_if_fail (entity != NULL, NULL);
456 static gchar * bag = NULL;
457 gchar * holder = NULL;
459 Inkscape::XML::Node * temp=NULL;
460 switch (entity->datatype) {
461 case RDF_CONTENT:
462 temp = sp_repr_children(repr);
463 if ( temp == NULL ) return NULL;
465 return temp->content();
467 case RDF_AGENT:
468 temp = sp_repr_lookup_name ( repr, "cc:Agent", 1 );
469 if ( temp == NULL ) return NULL;
471 temp = sp_repr_lookup_name ( temp, "dc:title", 1 );
472 if ( temp == NULL ) return NULL;
474 temp = sp_repr_children(temp);
475 if ( temp == NULL ) return NULL;
477 return temp->content();
479 case RDF_RESOURCE:
480 return repr->attribute("rdf:resource");
482 case RDF_XML:
483 return "xml goes here";
485 case RDF_BAG:
486 /* clear the static string. yucky. */
487 if (bag) g_free(bag);
488 bag = NULL;
490 temp = sp_repr_lookup_name ( repr, "rdf:Bag", 1 );
491 if ( temp == NULL ) {
492 /* backwards compatible: read contents */
493 temp = sp_repr_children(repr);
494 if ( temp == NULL ) return NULL;
496 return temp->content();
497 }
499 for ( temp = sp_repr_children(temp) ;
500 temp ;
501 temp = sp_repr_next(temp) ) {
502 if (!strcmp(temp->name(),"rdf:li") &&
503 temp->firstChild()) {
504 const gchar * str = temp->firstChild()->content();
505 if (bag) {
506 holder = bag;
507 bag = g_strconcat(holder, ", ", str, NULL);
508 g_free(holder);
509 }
510 else {
511 bag = g_strdup(str);
512 }
513 }
514 }
515 return bag;
517 default:
518 break;
519 }
520 return NULL;
521 }
523 unsigned int
524 rdf_set_repr_text ( Inkscape::XML::Node * repr,
525 struct rdf_work_entity_t * entity,
526 gchar const * text )
527 {
528 g_return_val_if_fail ( repr != NULL, 0);
529 g_return_val_if_fail ( entity != NULL, 0);
530 g_return_val_if_fail ( text != NULL, 0);
531 gchar * str = NULL;
532 gchar** strlist = NULL;
533 int i;
535 Inkscape::XML::Node * temp=NULL;
536 Inkscape::XML::Node * child=NULL;
537 Inkscape::XML::Node * parent=repr;
539 Inkscape::XML::Document * xmldoc = parent->document();
540 g_return_val_if_fail (xmldoc != NULL, FALSE);
542 // set document's title element to the RDF title
543 if (!strcmp(entity->name, "title")) {
544 SPDocument *doc = SP_ACTIVE_DOCUMENT;
545 if(doc && doc->root) doc->root->setTitle(text);
546 }
548 switch (entity->datatype) {
549 case RDF_CONTENT:
550 temp = sp_repr_children(parent);
551 if ( temp == NULL ) {
552 temp = xmldoc->createTextNode( text );
553 g_return_val_if_fail (temp != NULL, FALSE);
555 parent->appendChild(temp);
556 Inkscape::GC::release(temp);
558 return TRUE;
559 }
560 else {
561 temp->setContent(text);
562 return TRUE;
563 }
565 case RDF_AGENT:
566 temp = sp_repr_lookup_name ( parent, "cc:Agent", 1 );
567 if ( temp == NULL ) {
568 temp = xmldoc->createElement ( "cc:Agent" );
569 g_return_val_if_fail (temp != NULL, FALSE);
571 parent->appendChild(temp);
572 Inkscape::GC::release(temp);
573 }
574 parent = temp;
576 temp = sp_repr_lookup_name ( parent, "dc:title", 1 );
577 if ( temp == NULL ) {
578 temp = xmldoc->createElement ( "dc:title" );
579 g_return_val_if_fail (temp != NULL, FALSE);
581 parent->appendChild(temp);
582 Inkscape::GC::release(temp);
583 }
584 parent = temp;
586 temp = sp_repr_children(parent);
587 if ( temp == NULL ) {
588 temp = xmldoc->createTextNode( text );
589 g_return_val_if_fail (temp != NULL, FALSE);
591 parent->appendChild(temp);
592 Inkscape::GC::release(temp);
594 return TRUE;
595 }
596 else {
597 temp->setContent(text);
598 return TRUE;
599 }
601 case RDF_RESOURCE:
602 parent->setAttribute("rdf:resource", text );
603 return true;
605 case RDF_XML:
606 return 1;
608 case RDF_BAG:
609 /* find/create the rdf:Bag item */
610 temp = sp_repr_lookup_name ( parent, "rdf:Bag", 1 );
611 if ( temp == NULL ) {
612 /* backward compatibility: drop the dc:subject contents */
613 while ( (temp = sp_repr_children( parent )) ) {
614 parent->removeChild(temp);
615 }
617 temp = xmldoc->createElement ( "rdf:Bag" );
618 g_return_val_if_fail (temp != NULL, FALSE);
620 parent->appendChild(temp);
621 Inkscape::GC::release(temp);
622 }
623 parent = temp;
625 /* toss all the old list items */
626 while ( (temp = sp_repr_children( parent )) ) {
627 parent->removeChild(temp);
628 }
630 /* chop our list up on commas */
631 strlist = g_strsplit( text, ",", 0);
633 for (i = 0; (str = strlist[i]); i++) {
634 temp = xmldoc->createElement ( "rdf:li" );
635 g_return_val_if_fail (temp != NULL, 0);
637 parent->appendChild(temp);
638 Inkscape::GC::release(temp);
640 child = xmldoc->createTextNode( g_strstrip(str) );
641 g_return_val_if_fail (child != NULL, 0);
643 temp->appendChild(child);
644 Inkscape::GC::release(child);
645 }
646 g_strfreev( strlist );
648 return 1;
650 default:
651 break;
652 }
653 return 0;
654 }
656 Inkscape::XML::Node *
657 rdf_get_rdf_root_repr ( SPDocument * doc, bool build )
658 {
659 g_return_val_if_fail (doc != NULL, NULL);
660 g_return_val_if_fail (doc->rroot != NULL, NULL);
662 Inkscape::XML::Document * xmldoc = sp_document_repr_doc(doc);
663 g_return_val_if_fail (xmldoc != NULL, NULL);
665 Inkscape::XML::Node * rdf = sp_repr_lookup_name ( doc->rroot, XML_TAG_NAME_RDF );
667 if (rdf == NULL) {
668 //printf("missing XML '%s'\n",XML_TAG_NAME_RDF);
669 if (!build) return NULL;
671 Inkscape::XML::Node * svg = sp_repr_lookup_name ( doc->rroot, XML_TAG_NAME_SVG );
672 g_return_val_if_fail ( svg != NULL, NULL );
674 Inkscape::XML::Node * parent = sp_repr_lookup_name ( svg, XML_TAG_NAME_METADATA );
675 if ( parent == NULL ) {
676 parent = xmldoc->createElement( XML_TAG_NAME_METADATA );
677 g_return_val_if_fail ( parent != NULL, NULL);
679 svg->appendChild(parent);
680 Inkscape::GC::release(parent);
681 }
683 Inkscape::XML::Document * xmldoc = parent->document();
684 g_return_val_if_fail (xmldoc != NULL, FALSE);
686 rdf = xmldoc->createElement( XML_TAG_NAME_RDF );
687 g_return_val_if_fail (rdf != NULL, NULL);
689 parent->appendChild(rdf);
690 Inkscape::GC::release(rdf);
691 }
693 /*
694 * some implementations do not put RDF stuff inside <metadata>,
695 * so we need to check for it and add it if we don't see it
696 */
697 Inkscape::XML::Node * want_metadata = sp_repr_parent ( rdf );
698 g_return_val_if_fail (want_metadata != NULL, NULL);
699 if (strcmp( want_metadata->name(), XML_TAG_NAME_METADATA )) {
700 Inkscape::XML::Node * metadata = xmldoc->createElement( XML_TAG_NAME_METADATA );
701 g_return_val_if_fail (metadata != NULL, NULL);
703 /* attach the metadata node */
704 want_metadata->appendChild(metadata);
705 Inkscape::GC::release(metadata);
707 /* move the RDF into it */
708 Inkscape::GC::anchor(rdf);
709 sp_repr_unparent ( rdf );
710 metadata->appendChild(rdf);
711 Inkscape::GC::release(rdf);
712 }
714 return rdf;
715 }
717 Inkscape::XML::Node *
718 rdf_get_xml_repr( SPDocument * doc, gchar const * name, bool build )
719 {
720 g_return_val_if_fail (name != NULL, NULL);
721 g_return_val_if_fail (doc != NULL, NULL);
722 g_return_val_if_fail (doc->rroot != NULL, NULL);
724 Inkscape::XML::Node * rdf = rdf_get_rdf_root_repr ( doc, build );
725 if (!rdf) return NULL;
727 Inkscape::XML::Node * xml = sp_repr_lookup_name ( rdf, name );
728 if (xml == NULL) {
729 //printf("missing XML '%s'\n",name);
730 if (!build) return NULL;
732 Inkscape::XML::Document * xmldoc = sp_document_repr_doc(doc);
733 g_return_val_if_fail (xmldoc != NULL, NULL);
735 xml = xmldoc->createElement( name );
736 g_return_val_if_fail (xml != NULL, NULL);
738 xml->setAttribute("rdf:about", "" );
740 rdf->appendChild(xml);
741 Inkscape::GC::release(xml);
742 }
744 return xml;
745 }
747 Inkscape::XML::Node *
748 rdf_get_work_repr( SPDocument * doc, gchar const * name, bool build )
749 {
750 g_return_val_if_fail (name != NULL, NULL);
751 g_return_val_if_fail (doc != NULL, NULL);
752 g_return_val_if_fail (doc->rroot != NULL, NULL);
754 Inkscape::XML::Node * work = rdf_get_xml_repr ( doc, XML_TAG_NAME_WORK, build );
755 if (!work) return NULL;
757 Inkscape::XML::Node * item = sp_repr_lookup_name ( work, name, 1 );
758 if (item == NULL) {
759 //printf("missing XML '%s'\n",name);
760 if (!build) return NULL;
762 Inkscape::XML::Document * xmldoc = sp_document_repr_doc(doc);
763 g_return_val_if_fail (xmldoc != NULL, NULL);
765 item = xmldoc->createElement( name );
766 g_return_val_if_fail (item != NULL, NULL);
768 work->appendChild(item);
769 Inkscape::GC::release(item);
770 }
772 return item;
773 }
777 /**
778 * \brief Retrieves a known RDF/Work entity's contents from the document XML by name
779 * \return A pointer to the entity's static contents as a string, or NULL if no entity exists
780 * \param entity The desired RDF/Work entity
781 *
782 */
783 const gchar *
784 rdf_get_work_entity(SPDocument * doc, struct rdf_work_entity_t * entity)
785 {
786 g_return_val_if_fail (doc != NULL, NULL);
787 if ( entity == NULL ) return NULL;
788 //printf("want '%s'\n",entity->title);
789 bool bIsTitle = !strcmp(entity->name, "title");
791 Inkscape::XML::Node * item;
792 if ( entity->datatype == RDF_XML ) {
793 item = rdf_get_xml_repr ( doc, entity->tag, FALSE );
794 }
795 else {
796 item = rdf_get_work_repr( doc, entity->tag, bIsTitle ); // build title if necessary
797 }
798 if ( item == NULL ) return NULL;
799 const gchar * result = rdf_get_repr_text ( item, entity );
800 if(!result && bIsTitle && doc->root) { // if RDF title not set
801 result = doc->root->title(); // get the document's <title>
802 rdf_set_work_entity(doc, entity, result); // and set the RDF
803 }
804 //printf("found '%s' == '%s'\n", entity->title, result );
805 return result;
806 }
808 /**
809 * \brief Stores a string into a named RDF/Work entity in the document XML
810 * \param entity The desired RDF/Work entity to replace
811 * \param string The string to replace the entity contents with
812 *
813 */
814 unsigned int
815 rdf_set_work_entity(SPDocument * doc, struct rdf_work_entity_t * entity,
816 const gchar * text)
817 {
818 g_return_val_if_fail ( entity != NULL, 0 );
819 if (text == NULL) {
820 // FIXME: on a "NULL" text, delete the entity. For now, blank it.
821 text="";
822 }
824 /*
825 printf("changing '%s' (%s) to '%s'\n",
826 entity->title,
827 entity->tag,
828 text);
829 */
831 Inkscape::XML::Node * item = rdf_get_work_repr( doc, entity->tag, TRUE );
832 g_return_val_if_fail ( item != NULL, 0 );
834 return rdf_set_repr_text ( item, entity, text );
835 }
837 #undef DEBUG_MATCH
839 static bool
840 rdf_match_license(Inkscape::XML::Node const *repr, struct rdf_license_t const *license)
841 {
842 g_assert ( repr != NULL );
843 g_assert ( license != NULL );
845 bool result=TRUE;
846 #ifdef DEBUG_MATCH
847 printf("checking against '%s'\n",license->name);
848 #endif
850 int count = 0;
851 for (struct rdf_double_t const *details = license->details;
852 details->name; details++ ) {
853 count++;
854 }
855 bool * matched = (bool*)calloc(count,sizeof(bool));
857 for (Inkscape::XML::Node const *current = sp_repr_children(repr);
858 current;
859 current = sp_repr_next ( current ) ) {
861 gchar const * attr = current->attribute("rdf:resource");
862 if ( attr == NULL ) continue;
864 #ifdef DEBUG_MATCH
865 printf("\texamining '%s' => '%s'\n", current->name(), attr);
866 #endif
868 bool found_match=FALSE;
869 for (int i=0; i<count; i++) {
870 // skip already matched items
871 if (matched[i]) continue;
873 #ifdef DEBUG_MATCH
874 printf("\t\t'%s' vs '%s'\n", current->name(), license->details[i].name);
875 printf("\t\t'%s' vs '%s'\n", attr, license->details[i].resource);
876 #endif
878 if (!strcmp( current->name(),
879 license->details[i].name ) &&
880 !strcmp( attr,
881 license->details[i].resource )) {
882 matched[i]=TRUE;
883 found_match=TRUE;
884 #ifdef DEBUG_MATCH
885 printf("\t\tgood!\n");
886 #endif
887 break;
888 }
889 }
890 if (!found_match) {
891 // if we checked each known item of the license
892 // and didn't find it, we must abort
893 result=FALSE;
894 #ifdef DEBUG_MATCH
895 printf("\t\tno '%s' element matched XML (bong)!\n",license->name);
896 #endif
897 break;
898 }
899 }
900 #ifdef DEBUG_MATCH
901 if (result) printf("\t\tall XML found matching elements!\n");
902 #endif
903 for (int i=0; result && i<count; i++) {
904 // scan looking for an unmatched item
905 if (matched[i]==0) {
906 result=FALSE;
907 #ifdef DEBUG_MATCH
908 printf("\t\tnot all '%s' elements used to match (bong)!\n", license->name);
909 #endif
910 }
911 }
913 #ifdef DEBUG_MATCH
914 printf("\t\tall '%s' elements used to match!\n",license->name);
915 #endif
917 free(matched);
919 #ifdef DEBUG_MATCH
920 if (result) printf("matched '%s'\n",license->name);
921 #endif
922 return result;
923 }
925 /**
926 * \brief Attempts to match and retrieve a known RDF/License from the document XML
927 * \return A pointer to the static RDF license structure
928 *
929 */
930 struct rdf_license_t *
931 rdf_get_license(SPDocument * document)
932 {
933 Inkscape::XML::Node const *repr = rdf_get_xml_repr ( document, XML_TAG_NAME_LICENSE, FALSE );
934 if (repr) {
935 for (struct rdf_license_t * license = rdf_licenses;
936 license->name; license++ ) {
937 if ( rdf_match_license ( repr, license ) ) return license;
938 }
939 }
940 #ifdef DEBUG_MATCH
941 else {
942 printf("no license XML\n");
943 }
944 #endif
945 return NULL;
946 }
948 /**
949 * \brief Stores an RDF/License XML in the document XML
950 * \param document Which document to update
951 * \param license The desired RDF/License structure to store; NULL drops old license, so can be used for proprietary license.
952 *
953 */
954 void
955 rdf_set_license(SPDocument * doc, struct rdf_license_t const * license)
956 {
957 // drop old license section
958 Inkscape::XML::Node * repr = rdf_get_xml_repr ( doc, XML_TAG_NAME_LICENSE, FALSE );
959 if (repr) sp_repr_unparent(repr);
961 if (!license) return;
963 // build new license section
964 repr = rdf_get_xml_repr ( doc, XML_TAG_NAME_LICENSE, TRUE );
965 g_assert ( repr );
967 repr->setAttribute("rdf:about", license->uri );
969 Inkscape::XML::Document * xmldoc = sp_document_repr_doc(doc);
970 g_return_if_fail (xmldoc != NULL);
972 for (struct rdf_double_t const * detail = license->details;
973 detail->name; detail++) {
974 Inkscape::XML::Node * child = xmldoc->createElement( detail->name );
975 g_assert ( child != NULL );
977 child->setAttribute("rdf:resource", detail->resource );
978 repr->appendChild(child);
979 Inkscape::GC::release(child);
980 }
981 }
983 struct rdf_entity_default_t {
984 gchar const * name;
985 gchar const * text;
986 };
987 struct rdf_entity_default_t rdf_defaults[] = {
988 { "format", "image/svg+xml", },
989 { "type", "http://purl.org/dc/dcmitype/StillImage", },
990 { NULL, NULL, }
991 };
993 void
994 rdf_set_defaults ( SPDocument * doc )
995 {
996 g_assert ( doc != NULL );
998 // Create metadata node if it doesn't already exist
999 if (!sp_item_group_get_child_by_name ((SPGroup *) doc->root, NULL,
1000 XML_TAG_NAME_METADATA)) {
1001 // create repr
1002 Inkscape::XML::Document * xmldoc = sp_document_repr_doc(doc);
1003 g_return_if_fail (xmldoc != NULL);
1004 Inkscape::XML::Node * rnew = xmldoc->createElement (XML_TAG_NAME_METADATA);
1005 // insert into the document
1006 doc->rroot->addChild(rnew, NULL);
1007 // clean up
1008 Inkscape::GC::release(rnew);
1009 }
1011 /* install defaults */
1012 for ( struct rdf_entity_default_t * rdf_default = rdf_defaults;
1013 rdf_default->name;
1014 rdf_default++) {
1015 struct rdf_work_entity_t * entity = rdf_find_entity ( rdf_default->name );
1016 g_assert ( entity != NULL );
1018 if ( rdf_get_work_entity ( doc, entity ) == NULL ) {
1019 rdf_set_work_entity ( doc, entity, rdf_default->text );
1020 }
1021 }
1022 }
1025 /*
1026 Local Variables:
1027 mode:c++
1028 c-file-style:"stroustrup"
1029 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1030 indent-tabs-mode:nil
1031 fill-column:99
1032 End:
1033 */
1034 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :