Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
rdf.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
7/* Authors:
8 * Kees Cook <kees@outflux.net>
9 * Jon Phillips <jon@rejon.org>
10 * Jon A. Cruz <jon@joncruz.org>
11 *
12 * Copyright (C) 2004 Kees Cook <kees@outflux.net>
13 * Copyright (C) 2006 Jon Phillips <jon@rejon.org>
14 *
15 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
16 */
17
18#include "rdf.h"
19
20#include "document.h"
21#include "inkscape.h"
22#include "preferences.h"
23
24#include "object/sp-root.h"
25
26#include "xml/repr.h"
27
28/*
29 Example RDF XML from various places...
30
31<rdf:RDF xmlns="http://creativecommons.org/ns#"
32 xmlns:dc="http://purl.org/dc/elements/1.1/"
33 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
34<Work rdf:about="">
35 <dc:title>title of work</dc:title>
36 <dc:date>year</dc:date>
37 <dc:description>description of work</dc:description>
38 <dc:creator><Agent>
39 <dc:title>creator</dc:title>
40 </Agent></dc:creator>
41 <dc:rights><Agent>
42 <dc:title>holder</dc:title>
43 </Agent></dc:rights>
44 <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
45 <dc:source rdf:resource="source"/>
46 <license rdf:resource="http://creativecommons.org/licenses/by/4.0/"
47/>
48</Work>
49
50
51 <rdf:RDF xmlns="http://creativecommons.org/ns#"
52 xmlns:dc="http://purl.org/dc/elements/1.1/"
53 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
54 <Work rdf:about="">
55 <dc:title>SVG Road Signs</dc:title>
56 <dc:rights><Agent>
57 <dc:title>John Cliff</dc:title>
58 </Agent></dc:rights>
59 <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
60 <license rdf:resource="http://creativecommons.org/ns#PublicDomain" />
61 </Work>
62
63 <License rdf:about="http://creativecommons.org/ns#PublicDomain">
64 <permits rdf:resource="http://creativecommons.org/ns#Reproduction" />
65 <permits rdf:resource="http://creativecommons.org/ns#Distribution" />
66 <permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
67 </License>
68
69</rdf:RDF>
70
71
72Bag example:
73
74<dc:subject>
75<rdf:Bag>
76<rdf:li>open clip art logo</rdf:li>
77<rdf:li>images</rdf:li>
78<rdf:li>logo</rdf:li>
79<rdf:li>clip art</rdf:li>
80<rdf:li>ocal</rdf:li>
81<rdf:li>logotype</rdf:li>
82<rdf:li>filetype</rdf:li>
83</rdf:Bag>
84</dc:subject>
85*/
86
87// clang-format off
89 { nullptr, nullptr }
90};
91
93 { "cc:permits", "http://creativecommons.org/ns#Reproduction", },
94 { "cc:permits", "http://creativecommons.org/ns#Distribution", },
95 { "cc:requires", "http://creativecommons.org/ns#Notice", },
96 { "cc:requires", "http://creativecommons.org/ns#Attribution", },
97 { "cc:permits", "http://creativecommons.org/ns#DerivativeWorks", },
98 { nullptr, nullptr }
99};
100
102 { "cc:permits", "http://creativecommons.org/ns#Reproduction", },
103 { "cc:permits", "http://creativecommons.org/ns#Distribution", },
104 { "cc:requires", "http://creativecommons.org/ns#Notice", },
105 { "cc:requires", "http://creativecommons.org/ns#Attribution", },
106 { "cc:permits", "http://creativecommons.org/ns#DerivativeWorks", },
107 { "cc:requires", "http://creativecommons.org/ns#ShareAlike", },
108 { nullptr, nullptr }
109};
110
112 { "cc:permits", "http://creativecommons.org/ns#Reproduction", },
113 { "cc:permits", "http://creativecommons.org/ns#Distribution", },
114 { "cc:requires", "http://creativecommons.org/ns#Notice", },
115 { "cc:requires", "http://creativecommons.org/ns#Attribution", },
116 { nullptr, nullptr }
117};
118
120 { "cc:permits", "http://creativecommons.org/ns#Reproduction", },
121 { "cc:permits", "http://creativecommons.org/ns#Distribution", },
122 { "cc:requires", "http://creativecommons.org/ns#Notice", },
123 { "cc:requires", "http://creativecommons.org/ns#Attribution", },
124 { "cc:prohibits", "http://creativecommons.org/ns#CommercialUse", },
125 { "cc:permits", "http://creativecommons.org/ns#DerivativeWorks", },
126 { nullptr, nullptr }
127};
128
130 { "cc:permits", "http://creativecommons.org/ns#Reproduction", },
131 { "cc:permits", "http://creativecommons.org/ns#Distribution", },
132 { "cc:requires", "http://creativecommons.org/ns#Notice", },
133 { "cc:requires", "http://creativecommons.org/ns#Attribution", },
134 { "cc:prohibits", "http://creativecommons.org/ns#CommercialUse", },
135 { "cc:permits", "http://creativecommons.org/ns#DerivativeWorks", },
136 { "cc:requires", "http://creativecommons.org/ns#ShareAlike", },
137 { nullptr, nullptr }
138};
139
141 { "cc:permits", "http://creativecommons.org/ns#Reproduction", },
142 { "cc:permits", "http://creativecommons.org/ns#Distribution", },
143 { "cc:requires", "http://creativecommons.org/ns#Notice", },
144 { "cc:requires", "http://creativecommons.org/ns#Attribution", },
145 { "cc:prohibits", "http://creativecommons.org/ns#CommercialUse", },
146 { nullptr, nullptr }
147};
148
150 { "cc:permits", "http://creativecommons.org/ns#Reproduction", },
151 { "cc:permits", "http://creativecommons.org/ns#Distribution", },
152 { "cc:permits", "http://creativecommons.org/ns#DerivativeWorks", },
153 { nullptr, nullptr }
154};
155
157 { "cc:permits", "http://creativecommons.org/ns#Reproduction", },
158 { "cc:permits", "http://creativecommons.org/ns#Distribution", },
159 { "cc:permits", "http://creativecommons.org/ns#DerivativeWorks", },
160 { "cc:requires", "http://creativecommons.org/ns#ShareAlike", },
161 { "cc:requires", "http://creativecommons.org/ns#Notice", },
162 { "cc:requires", "http://creativecommons.org/ns#Attribution", },
163 { nullptr, nullptr }
164};
165
167 { "cc:permits", "http://scripts.sil.org/pub/OFL/Reproduction", },
168 { "cc:permits", "http://scripts.sil.org/pub/OFL/Distribution", },
169 { "cc:permits", "http://scripts.sil.org/pub/OFL/Embedding", },
170 { "cc:permits", "http://scripts.sil.org/pub/OFL/DerivativeWorks", },
171 { "cc:requires", "http://scripts.sil.org/pub/OFL/Notice", },
172 { "cc:requires", "http://scripts.sil.org/pub/OFL/Attribution", },
173 { "cc:requires", "http://scripts.sil.org/pub/OFL/ShareAlike", },
174 { "cc:requires", "http://scripts.sil.org/pub/OFL/DerivativeRenaming", },
175 { "cc:requires", "http://scripts.sil.org/pub/OFL/BundlingWhenSelling", },
176 { nullptr, nullptr }
177};
178
180 { N_("CC Attribution"),
181 "http://creativecommons.org/licenses/by/4.0/",
183 },
184
185 { N_("CC Attribution-ShareAlike"),
186 "http://creativecommons.org/licenses/by-sa/4.0/",
188 },
189
190 { N_("CC Attribution-NoDerivs"),
191 "http://creativecommons.org/licenses/by-nd/4.0/",
193 },
194
195 { N_("CC Attribution-NonCommercial"),
196 "http://creativecommons.org/licenses/by-nc/4.0/",
198 },
199
200 { N_("CC Attribution-NonCommercial-ShareAlike"),
201 "http://creativecommons.org/licenses/by-nc-sa/4.0/",
203 },
204
205 { N_("CC Attribution-NonCommercial-NoDerivs"),
206 "http://creativecommons.org/licenses/by-nc-nd/4.0/",
208 },
209
210 { N_("CC0 Public Domain Dedication"),
211 "http://creativecommons.org/publicdomain/zero/1.0/",
213 },
214
215 { N_("FreeArt"),
216 "http://artlibre.org/licence/lal",
218 },
219
220 { N_("Open Font License"),
221 "http://scripts.sil.org/OFL",
223 },
224
225 { nullptr, nullptr, rdf_license_empty, }
226};
227// clang-format on
228
229#define XML_TAG_NAME_SVG "svg:svg"
230#define XML_TAG_NAME_METADATA "svg:metadata"
231#define XML_TAG_NAME_RDF "rdf:RDF"
232#define XML_TAG_NAME_WORK "cc:Work"
233#define XML_TAG_NAME_LICENSE "cc:License"
234// Note the lowercase L!
235#define XML_TAG_NAME_LICENSE_PROP "cc:license"
236
237
238// Remember when using the "title" and "tip" elements to pass them through
239// the localization functions when you use them!
241 // clang-format off
242 { "title", N_("Title:"), "dc:title", RDF_CONTENT,
243 N_("A name given to the resource"), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
244 },
245 { "date", N_("Date:"), "dc:date", RDF_CONTENT,
246 N_("A point or period of time associated with an event in the lifecycle of the resource"), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
247 },
248 { "format", N_("Format:"), "dc:format", RDF_CONTENT,
249 N_("The file format, physical medium, or dimensions of the resource"), RDF_FORMAT_LINE, RDF_EDIT_HARDCODED,
250 },
251 { "type", N_("Type:"), "dc:type", RDF_RESOURCE,
252 N_("The nature or genre of the resource"), RDF_FORMAT_LINE, RDF_EDIT_HARDCODED,
253 },
254
255 { "creator", N_("Creator:"), "dc:creator", RDF_AGENT,
256 N_("An entity primarily responsible for making the resource"), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
257 },
258 { "rights", N_("Rights:"), "dc:rights", RDF_AGENT,
259 N_("Information about rights held in and over the resource"), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
260 },
261 { "publisher", N_("Publisher:"), "dc:publisher", RDF_AGENT,
262 N_("An entity responsible for making the resource available"), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
263 },
264
265 { "identifier", N_("Identifier:"), "dc:identifier", RDF_CONTENT,
266 N_("An unambiguous reference to the resource within a given context"), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
267 },
268 { "source", N_("Source:"), "dc:source", RDF_CONTENT,
269 N_("A related resource from which the described resource is derived"), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
270 },
271 { "relation", N_("Relation:"), "dc:relation", RDF_CONTENT,
272 N_("A related resource"), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
273 },
274 { "language", N_("Language:"), "dc:language", RDF_CONTENT,
275 N_("A language of the resource"), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
276 },
277 { "subject", N_("Keywords:"), "dc:subject", RDF_BAG,
278 N_("The topic of the resource"), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
279 },
280 // TRANSLATORS: "Coverage": the spatial or temporal characteristics of the content.
281 // For info, see Appendix D of http://www.w3.org/TR/1998/WD-rdf-schema-19980409/
282 { "coverage", N_("Coverage:"), "dc:coverage", RDF_CONTENT,
283 N_("The spatial or temporal topic of the resource, the spatial applicability of the resource, or the jurisdiction under which the resource is relevant"), RDF_FORMAT_LINE, RDF_EDIT_GENERIC,
284 },
285
286 { "description", N_("Description:"), "dc:description", RDF_CONTENT,
287 N_("An account of the resource"), RDF_FORMAT_MULTILINE, RDF_EDIT_GENERIC,
288 },
289
290 // FIXME: need to handle 1 agent per line of input
291 { "contributor", N_("Contributors:"), "dc:contributor", RDF_AGENT,
292 N_("An entity responsible for making contributions to the resource"), RDF_FORMAT_MULTILINE, RDF_EDIT_GENERIC,
293 },
294
295 // TRANSLATORS: URL to a page that defines the license for the document
296 { "license_uri", N_("URI:"), "cc:license", RDF_RESOURCE,
297 // TRANSLATORS: this is where you put a URL to a page that defines the license
298 N_("URI to this document's license's namespace definition"), RDF_FORMAT_LINE, RDF_EDIT_SPECIAL,
299 },
300
301 // TRANSLATORS: fragment of XML representing the license of the document
302 { "license_fragment", N_("Fragment:"), "License", RDF_XML,
303 N_("XML fragment for the RDF 'License' section"), RDF_FORMAT_MULTILINE, RDF_EDIT_SPECIAL,
304 },
305
306 { nullptr, nullptr, nullptr, RDF_CONTENT,
308 }
309 // clang-format on
310};
311
312
313// Simple start of C++-ification:
314class RDFImpl
315{
316public:
321 static void ensureParentIsMetadata( SPDocument *doc, Inkscape::XML::Node *node );
322
323 static Inkscape::XML::Node const *getRdfRootRepr( SPDocument const * doc );
324 static Inkscape::XML::Node *ensureRdfRootRepr( SPDocument * doc );
325
326 static Inkscape::XML::Node const *getXmlRepr( SPDocument const * doc, gchar const * name );
327 static Inkscape::XML::Node *getXmlRepr( SPDocument * doc, gchar const * name );
328 static Inkscape::XML::Node *ensureXmlRepr( SPDocument * doc, gchar const * name );
329
330 static Inkscape::XML::Node const *getWorkRepr( SPDocument const * doc, gchar const * name );
331 static Inkscape::XML::Node *ensureWorkRepr( SPDocument * doc, gchar const * name );
332
333 static const gchar *getWorkEntity(SPDocument const * doc, struct rdf_work_entity_t & entity);
334 static unsigned int setWorkEntity(SPDocument * doc, struct rdf_work_entity_t & entity, gchar const * text);
335
336 static void setDefaults( SPDocument * doc );
337
346 static const gchar *getReprText( Inkscape::XML::Node const * repr, struct rdf_work_entity_t const & entity );
347
348 static unsigned int setReprText( Inkscape::XML::Node * repr,
349 struct rdf_work_entity_t const & entity,
350 gchar const * text );
351
352 static struct rdf_license_t *getLicense(SPDocument *document, bool read_only);
353
354 static void setLicense(SPDocument * doc, struct rdf_license_t const * license);
355};
356
365{
366 struct rdf_work_entity_t *entity;
367 for (entity=rdf_work_entities; entity->name; entity++) {
368 if (strcmp(entity->name,name)==0) break;
369 }
370 if (entity->name) return entity;
371 return nullptr;
372}
373
374/*
375 * Takes the inkscape rdf struct and spits out a static RDF, which is only
376 * useful for testing. We must merge the rdf struct into the XML DOM for
377 * changes to be saved.
378 */
379/*
380
381 Since g_markup_printf_escaped doesn't exist for most people's glib
382 right now, this function will remain commented out since it's only
383 for generic debug anyway. --Kees
384
385gchar *
386rdf_string(struct rdf_t * rdf)
387{
388 gulong overall=0;
389 gchar *string=NULL;
390
391 gchar *rdf_head="\
392<rdf:RDF xmlns=\"http://creativecommons.org/ns#\"\
393 xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\
394 xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\
395";
396 gchar *work_head="\
397<Work rdf:about=\"\">\
398 <dc:type rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\" />\
399";
400 gchar *work_title=NULL;
401 gchar *work_date=NULL;
402 gchar *work_description=NULL;
403 gchar *work_creator=NULL;
404 gchar *work_owner=NULL;
405 gchar *work_source=NULL;
406 gchar *work_license=NULL;
407 gchar *license_head=NULL;
408 gchar *license=NULL;
409 gchar *license_end="</License>\n";
410 gchar *work_end="</Work>\n";
411 gchar *rdf_end="</rdf:RDF>\n";
412
413 if (rdf && rdf->work_title && rdf->work_title[0]) {
414 work_title=g_markup_printf_escaped(" <dc:title>%s</dc:title>\n",
415 rdf->work_title);
416 overall+=strlen(work_title);
417 }
418 if (rdf && rdf->work_date && rdf->work_date[0]) {
419 work_date=g_markup_printf_escaped(" <dc:date>%s</dc:date>\n",
420 rdf->work_date);
421 overall+=strlen(work_date);
422 }
423 if (rdf && rdf->work_description && rdf->work_description[0]) {
424 work_description=g_markup_printf_escaped(" <dc:description>%s</dc:description>\n",
425 rdf->work_description);
426 overall+=strlen(work_description);
427 }
428 if (rdf && rdf->work_creator && rdf->work_creator[0]) {
429 work_creator=g_markup_printf_escaped(" <dc:creator><Agent>\
430 <dc:title>%s</dc:title>\
431 </Agent></dc:creator>\n",
432 rdf->work_creator);
433 overall+=strlen(work_creator);
434 }
435 if (rdf && rdf->work_owner && rdf->work_owner[0]) {
436 work_owner=g_markup_printf_escaped(" <dc:rights><Agent>\
437 <dc:title>%s</dc:title>\
438 </Agent></dc:rights>\n",
439 rdf->work_owner);
440 overall+=strlen(work_owner);
441 }
442 if (rdf && rdf->work_source && rdf->work_source[0]) {
443 work_source=g_markup_printf_escaped(" <dc:source rdf:resource=\"%s\" />\n",
444 rdf->work_source);
445 overall+=strlen(work_source);
446 }
447 if (rdf && rdf->license && rdf->license->work_rdf && rdf->license->work_rdf[0]) {
448 work_license=g_markup_printf_escaped(" <license rdf:resource=\"%s\" />\n",
449 rdf->license->work_rdf);
450 overall+=strlen(work_license);
451
452 license_head=g_markup_printf_escaped("<License rdf:about=\"%s\">\n",
453 rdf->license->work_rdf);
454 overall+=strlen(license_head);
455 overall+=strlen(rdf->license->license_rdf);
456 overall+=strlen(license_end);
457 }
458
459 overall+=strlen(rdf_head)+strlen(rdf_end);
460 overall+=strlen(work_head)+strlen(work_end);
461
462 overall++; // NULL term
463
464 if (!(string=(gchar*)g_malloc(overall))) {
465 return NULL;
466 }
467
468 string[0]='\0';
469 strcat(string,rdf_head);
470 strcat(string,work_head);
471
472 if (work_title) strcat(string,work_title);
473 if (work_date) strcat(string,work_date);
474 if (work_description) strcat(string,work_description);
475 if (work_creator) strcat(string,work_creator);
476 if (work_owner) strcat(string,work_owner);
477 if (work_source) strcat(string,work_source);
478 if (work_license) strcat(string,work_license);
479
480 strcat(string,work_end);
481 if (license_head) {
482 strcat(string,license_head);
483 strcat(string,rdf->license->license_rdf);
484 strcat(string,license_end);
485 }
486 strcat(string,rdf_end);
487
488 return string;
489}
490*/
491
492
493const gchar *RDFImpl::getReprText( Inkscape::XML::Node const * repr, struct rdf_work_entity_t const & entity )
494{
495 g_return_val_if_fail (repr != nullptr, NULL);
496 static gchar * bag = nullptr;
497 gchar * holder = nullptr;
498
499 Inkscape::XML::Node const * temp = nullptr;
500 switch (entity.datatype) {
501 case RDF_CONTENT:
502 temp = repr->firstChild();
503 if ( temp == nullptr ) return nullptr;
504
505 return temp->content();
506
507 case RDF_AGENT:
508 temp = sp_repr_lookup_name ( repr, "cc:Agent", 1 );
509 if ( temp == nullptr ) return nullptr;
510
511 temp = sp_repr_lookup_name ( temp, "dc:title", 1 );
512 if ( temp == nullptr ) return nullptr;
513
514 temp = temp->firstChild();
515 if ( temp == nullptr ) return nullptr;
516
517 return temp->content();
518
519 case RDF_RESOURCE:
520 return repr->attribute("rdf:resource");
521
522 case RDF_XML:
523 return "xml goes here";
524
525 case RDF_BAG:
526 /* clear the static string. yucky. */
527 if (bag) g_free(bag);
528 bag = nullptr;
529
530 temp = sp_repr_lookup_name ( repr, "rdf:Bag", 1 );
531 if ( temp == nullptr ) {
532 /* backwards compatible: read contents */
533 temp = repr->firstChild();
534 if ( temp == nullptr ) return nullptr;
535
536 return temp->content();
537 }
538
539 for ( temp = temp->firstChild() ;
540 temp ;
541 temp = temp->next() ) {
542 if (!strcmp(temp->name(),"rdf:li") &&
543 temp->firstChild()) {
544 const gchar * str = temp->firstChild()->content();
545 if (bag) {
546 holder = bag;
547 bag = g_strconcat(holder, ", ", str, nullptr);
548 g_free(holder);
549 }
550 else {
551 bag = g_strdup(str);
552 }
553 }
554 }
555 return bag;
556
557 default:
558 break;
559 }
560 return nullptr;
561}
562
563unsigned int RDFImpl::setReprText( Inkscape::XML::Node * repr,
564 struct rdf_work_entity_t const & entity,
565 gchar const * text )
566{
567 g_return_val_if_fail ( repr != nullptr, 0);
568 g_return_val_if_fail ( text != nullptr, 0);
569 gchar * str = nullptr;
570 gchar** strlist = nullptr;
571 int i;
572
573 Inkscape::XML::Node * temp=nullptr;
575
577 g_return_val_if_fail (xmldoc != nullptr, FALSE);
578
579 // set document's title element to the RDF title
580 if (!strcmp(entity.name, "title")) {
581 SPDocument *doc = SP_ACTIVE_DOCUMENT;
582 if (doc && doc->getRoot()) {
583 doc->getRoot()->setTitle(text);
584 }
585 }
586
587 switch (entity.datatype) {
588 case RDF_CONTENT:
589 temp = parent->firstChild();
590 if ( temp == nullptr ) {
591 temp = xmldoc->createTextNode( text );
592 g_return_val_if_fail (temp != nullptr, FALSE);
593
594 parent->appendChild(temp);
596
597 return TRUE;
598 }
599 else {
600 temp->setContent(text);
601 return TRUE;
602 }
603
604 case RDF_AGENT:
605 temp = sp_repr_lookup_name ( parent, "cc:Agent", 1 );
606 if ( temp == nullptr ) {
607 temp = xmldoc->createElement ( "cc:Agent" );
608 g_return_val_if_fail (temp != nullptr, FALSE);
609
610 parent->appendChild(temp);
612 }
613 parent = temp;
614
615 temp = sp_repr_lookup_name ( parent, "dc:title", 1 );
616 if ( temp == nullptr ) {
617 temp = xmldoc->createElement ( "dc:title" );
618 g_return_val_if_fail (temp != nullptr, FALSE);
619
620 parent->appendChild(temp);
622 }
623 parent = temp;
624
625 temp = parent->firstChild();
626 if ( temp == nullptr ) {
627 temp = xmldoc->createTextNode( text );
628 g_return_val_if_fail (temp != nullptr, FALSE);
629
630 parent->appendChild(temp);
632
633 return TRUE;
634 }
635 else {
636 temp->setContent(text);
637 return TRUE;
638 }
639
640 case RDF_RESOURCE:
641 parent->setAttribute("rdf:resource", text );
642 return true;
643
644 case RDF_XML:
645 return 1;
646
647 case RDF_BAG:
648 /* find/create the rdf:Bag item */
649 temp = sp_repr_lookup_name ( parent, "rdf:Bag", 1 );
650 if ( temp == nullptr ) {
651 /* backward compatibility: drop the dc:subject contents */
652 while ( (temp = parent->firstChild()) ) {
653 parent->removeChild(temp);
654 }
655
656 temp = xmldoc->createElement ( "rdf:Bag" );
657 g_return_val_if_fail (temp != nullptr, FALSE);
658
659 parent->appendChild(temp);
661 }
662 parent = temp;
663
664 /* toss all the old list items */
665 while ( (temp = parent->firstChild()) ) {
666 parent->removeChild(temp);
667 }
668
669 /* chop our list up on commas */
670 strlist = g_strsplit( text, ",", 0);
671
672 for (i = 0; (str = strlist[i]); i++) {
673 temp = xmldoc->createElement ( "rdf:li" );
674 g_return_val_if_fail (temp != nullptr, 0);
675
676 parent->appendChild(temp);
678
679 Inkscape::XML::Node * child = xmldoc->createTextNode( g_strstrip(str) );
680 g_return_val_if_fail (child != nullptr, 0);
681
682 temp->appendChild(child);
684 }
685 g_strfreev( strlist );
686
687 return 1;
688
689 default:
690 break;
691 }
692 return 0;
693}
694
695void RDFImpl::ensureParentIsMetadata( SPDocument *doc, Inkscape::XML::Node *node )
696{
697 if ( !node ) {
698 g_critical("Null node passed to ensureParentIsMetadata().");
699 } else if ( !node->parent() ) {
700 g_critical( "No parent node when verifying <metadata> placement." );
701 } else {
702 Inkscape::XML::Node * currentParent = node->parent();
703 if ( strcmp( currentParent->name(), XML_TAG_NAME_METADATA ) != 0 ) {
704 Inkscape::XML::Node * metadata = doc->getReprDoc()->createElement( XML_TAG_NAME_METADATA );
705 if ( !metadata ) {
706 g_critical("Unable to create metadata element.");
707 } else {
708 // attach the metadata node
709 currentParent->appendChild( metadata );
710 Inkscape::GC::release( metadata );
711
712 // move the node into it
715 metadata->appendChild( node );
717 }
718 }
719 }
720}
721
722Inkscape::XML::Node const *RDFImpl::getRdfRootRepr( SPDocument const * doc )
723{
724 Inkscape::XML::Node const *rdf = nullptr;
725 if ( !doc ) {
726 g_critical("Null doc passed to getRdfRootRepr()");
727 } else if ( !doc->getReprDoc() ) {
728 g_critical("XML doc is null.");
729 } else {
730 rdf = sp_repr_lookup_name( doc->getReprDoc(), XML_TAG_NAME_RDF );
731 }
732
733 return rdf;
734}
735
736Inkscape::XML::Node *RDFImpl::ensureRdfRootRepr( SPDocument * doc )
737{
738 Inkscape::XML::Node *rdf = nullptr;
739 if ( !doc ) {
740 g_critical("Null doc passed to ensureRdfRootRepr()");
741 } else if ( !doc->getReprDoc() ) {
742 g_critical("XML doc is null.");
743 } else {
744 rdf = sp_repr_lookup_name( doc->getReprDoc(), XML_TAG_NAME_RDF );
745 if ( !rdf ) {
746 Inkscape::XML::Node * svg = sp_repr_lookup_name( doc->getReprRoot(), XML_TAG_NAME_SVG );
747 if ( !svg ) {
748 g_critical("Unable to locate svg element.");
749 } else {
750 Inkscape::XML::Node * parent = sp_repr_lookup_name( svg, XML_TAG_NAME_METADATA, 1);
751 if ( parent == nullptr ) {
752 parent = doc->getReprDoc()->createElement( XML_TAG_NAME_METADATA );
753 if ( !parent ) {
754 g_critical("Unable to create metadata element");
755 } else {
756 svg->appendChild(parent);
758 }
759 }
760
761 if ( parent && !parent->document() ) {
762 g_critical("Parent has no document");
763 } else if ( parent ) {
764 rdf = parent->document()->createElement( XML_TAG_NAME_RDF );
765 if ( !rdf ) {
766 g_critical("Unable to create root RDF element.");
767 } else {
768 parent->appendChild(rdf);
770 }
771 }
772 }
773 }
774 }
775
776 if ( rdf ) {
777 ensureParentIsMetadata( doc, rdf );
778 }
779
780 return rdf;
781}
782
783Inkscape::XML::Node const *RDFImpl::getXmlRepr( SPDocument const * doc, gchar const * name )
784{
785 Inkscape::XML::Node const * xml = nullptr;
786 if ( !doc ) {
787 g_critical("Null doc passed to getXmlRepr()");
788 } else if ( !doc->getReprDoc() ) {
789 g_critical("XML doc is null.");
790 } else if (!name) {
791 g_critical("Null name passed to getXmlRepr()");
792 } else {
793 Inkscape::XML::Node const * rdf = getRdfRootRepr( doc );
794 if ( rdf ) {
795 xml = sp_repr_lookup_name( rdf, name );
796 }
797 }
798 return xml;
799}
800
801Inkscape::XML::Node *RDFImpl::getXmlRepr( SPDocument * doc, gchar const * name )
802{
803 Inkscape::XML::Node const *xml = getXmlRepr( const_cast<SPDocument const *>(doc), name );
804
805 return const_cast<Inkscape::XML::Node *>(xml);
806}
807
808Inkscape::XML::Node *RDFImpl::ensureXmlRepr( SPDocument * doc, gchar const * name )
809{
810 Inkscape::XML::Node * xml = nullptr;
811 if ( !doc ) {
812 g_critical("Null doc passed to ensureXmlRepr()");
813 } else if ( !doc->getReprDoc() ) {
814 g_critical("XML doc is null.");
815 } else if (!name) {
816 g_critical("Null name passed to ensureXmlRepr()");
817 } else {
818 Inkscape::XML::Node * rdf = ensureRdfRootRepr( doc );
819 if ( rdf ) {
820 xml = sp_repr_lookup_name( rdf, name );
821 if ( !xml ) {
822 xml = doc->getReprDoc()->createElement( name );
823 if ( !xml ) {
824 g_critical("Unable to create xml element <%s>.", name);
825 } else {
826 xml->setAttribute("rdf:about", "" );
827
828 rdf->appendChild(xml);
830 }
831 }
832 }
833 }
834 return xml;
835}
836
837Inkscape::XML::Node const *RDFImpl::getWorkRepr( SPDocument const * doc, gchar const * name )
838{
839 Inkscape::XML::Node const * item = nullptr;
840 if ( !doc ) {
841 g_critical("Null doc passed to getWorkRepr()");
842 } else if ( !doc->getReprDoc() ) {
843 g_critical("XML doc is null.");
844 } else if (!name) {
845 g_critical("Null name passed to getWorkRepr()");
846 } else {
847 Inkscape::XML::Node const* work = getXmlRepr( doc, XML_TAG_NAME_WORK );
848 if ( work ) {
849 item = sp_repr_lookup_name( work, name, 1 );
850 }
851 }
852 return item;
853}
854
855Inkscape::XML::Node *RDFImpl::ensureWorkRepr( SPDocument * doc, gchar const * name )
856{
857 Inkscape::XML::Node * item = nullptr;
858 if ( !doc ) {
859 g_critical("Null doc passed to ensureWorkRepr()");
860 } else if ( !doc->getReprDoc() ) {
861 g_critical("XML doc is null.");
862 } else if (!name) {
863 g_critical("Null name passed to ensureWorkRepr()");
864 } else {
865 Inkscape::XML::Node * work = ensureXmlRepr( doc, XML_TAG_NAME_WORK );
866 if ( work ) {
867 item = sp_repr_lookup_name( work, name, 1 );
868 if ( !item ) {
869 //printf("missing XML '%s'\n",name);
870 item = doc->getReprDoc()->createElement( name );
871 if ( !item ) {
872 g_critical("Unable to create xml element <%s>", name);
873 } else {
874 work->appendChild(item);
876 }
877 }
878 }
879 }
880 return item;
881}
882
883
884// Public API:
885const gchar *rdf_get_work_entity(SPDocument const * doc, struct rdf_work_entity_t * entity)
886{
887 const gchar *result = nullptr;
888 if ( !doc ) {
889 g_critical("Null doc passed to rdf_get_work_entity()");
890 } else if ( entity ) {
891 //g_message("want '%s'\n",entity->title);
892
893 result = RDFImpl::getWorkEntity(doc, *entity);
894
895 //g_message("found '%s' == '%s'\n", entity->title, result );
896 }
897 return result;
898}
899
900const gchar *RDFImpl::getWorkEntity(SPDocument const * doc, struct rdf_work_entity_t & entity)
901{
902 gchar const *result = nullptr;
903
904 Inkscape::XML::Node const * item = getWorkRepr(doc, entity.tag);
905 if ( item ) {
906 result = getReprText( item, entity );
907 // TODO note that this is the location that used to set the title if needed. Ensure code it not required.
908 }
909
910 return result;
911}
912
913// Public API:
914unsigned int rdf_set_work_entity(SPDocument * doc, struct rdf_work_entity_t * entity,
915 const gchar * text)
916{
917 unsigned int result = 0;
918 if ( !doc ) {
919 g_critical("Null doc passed to rdf_set_work_entity()");
920 } else if ( entity ) {
921 result = RDFImpl::setWorkEntity( doc, *entity, text );
922 }
923
924 return result;
925}
926
927unsigned int RDFImpl::setWorkEntity(SPDocument * doc, struct rdf_work_entity_t & entity, const gchar * text)
928{
929 int result = 0;
930 if (!text || !text[0]) {
931 auto *item = const_cast<Inkscape::XML::Node *>(getWorkRepr(doc, entity.tag));
932 if (item) {
934 if (!strcmp(entity.name, "title")) {
935 doc->getRoot()->setTitle(nullptr);
936 }
937 }
938 return true;
939 }
940
941 /*
942 printf("changing '%s' (%s) to '%s'\n",
943 entity->title,
944 entity->tag,
945 text);
946 */
947
948 Inkscape::XML::Node * item = ensureWorkRepr( doc, entity.tag );
949 if ( !item ) {
950 g_critical("Unable to get work element");
951 } else {
952 result = setReprText( item, entity, text );
953 }
954 return result;
955}
956
957
958#undef DEBUG_MATCH
959
960static bool
961rdf_match_license(Inkscape::XML::Node const *repr, struct rdf_license_t const *license)
962{
963 g_assert ( repr != nullptr );
964 g_assert ( license != nullptr );
965
966 bool result=TRUE;
967#ifdef DEBUG_MATCH
968 printf("checking against '%s'\n",license->name);
969#endif
970
971 int count = 0;
972 for (struct rdf_double_t const *details = license->details;
973 details->name; details++ ) {
974 count++;
975 }
976 bool * matched = (bool*)calloc(count,sizeof(bool));
977
978 for (Inkscape::XML::Node const *current = repr->firstChild();
979 current;
980 current = current->next() ) {
981
982 gchar const * attr = current->attribute("rdf:resource");
983 if ( attr == nullptr ) continue;
984
985#ifdef DEBUG_MATCH
986 printf("\texamining '%s' => '%s'\n", current->name(), attr);
987#endif
988
989 bool found_match=FALSE;
990 for (int i=0; i<count; i++) {
991 // skip already matched items
992 if (matched[i]) continue;
993
994#ifdef DEBUG_MATCH
995 printf("\t\t'%s' vs '%s'\n", current->name(), license->details[i].name);
996 printf("\t\t'%s' vs '%s'\n", attr, license->details[i].resource);
997#endif
998
999 if (!strcmp( current->name(),
1000 license->details[i].name ) &&
1001 !strcmp( attr,
1002 license->details[i].resource )) {
1003 matched[i]=TRUE;
1004 found_match=TRUE;
1005#ifdef DEBUG_MATCH
1006 printf("\t\tgood!\n");
1007#endif
1008 break;
1009 }
1010 }
1011 if (!found_match) {
1012 // if we checked each known item of the license
1013 // and didn't find it, we must abort
1014 result=FALSE;
1015#ifdef DEBUG_MATCH
1016 printf("\t\tno '%s' element matched XML (bong)!\n",license->name);
1017#endif
1018 break;
1019 }
1020 }
1021#ifdef DEBUG_MATCH
1022 if (result) printf("\t\tall XML found matching elements!\n");
1023#endif
1024 for (int i=0; result && i<count; i++) {
1025 // scan looking for an unmatched item
1026 if (matched[i]==0) {
1027 result=FALSE;
1028#ifdef DEBUG_MATCH
1029 printf("\t\tnot all '%s' elements used to match (bong)!\n", license->name);
1030#endif
1031 }
1032 }
1033
1034#ifdef DEBUG_MATCH
1035 printf("\t\tall '%s' elements used to match!\n",license->name);
1036#endif
1037
1038 free(matched);
1039
1040#ifdef DEBUG_MATCH
1041 if (result) printf("matched '%s'\n",license->name);
1042#endif
1043 return result;
1044}
1045
1046// Public API:
1047struct rdf_license_t *rdf_get_license(SPDocument *document, bool read_only)
1048{
1049 return RDFImpl::getLicense(document, read_only);
1050}
1051
1052struct rdf_license_t *RDFImpl::getLicense(SPDocument *document, bool read_only)
1053{
1054 // Base license lookup on the URI of cc:license rather than the license
1055 // properties, per instructions from the ccREL gurus.
1056 // (Fixes https://bugs.launchpad.net/inkscape/+bug/372427)
1057
1058 struct rdf_work_entity_t *entity = rdf_find_entity("license_uri");
1059 if (entity == nullptr) {
1060 g_critical("Can't find internal entity structure for 'license_uri'");
1061 return nullptr;
1062 }
1063
1064 const gchar *uri = getWorkEntity(document, *entity);
1065 struct rdf_license_t * license_by_uri = nullptr;
1066
1067 if (uri != nullptr) {
1068 for (struct rdf_license_t * license = rdf_licenses; license->name; license++) {
1069 if (g_strcmp0(uri, license->uri) == 0) {
1070 license_by_uri = license;
1071 break;
1072 }
1073 }
1074 }
1075
1076 // To improve backward compatibility, the old license matching code is
1077 // kept as fallback and to warn about and fix discrepancies.
1078
1079 // TODO: would it be better to do this code on document load? Is
1080 // sp_metadata_build() then the right place to put the call to sort out
1081 // any RDF mess?
1082
1083 struct rdf_license_t * license_by_properties = nullptr;
1084
1085 Inkscape::XML::Node const *repr = getXmlRepr( document, XML_TAG_NAME_LICENSE );
1086 if (repr) {
1087 for ( struct rdf_license_t * license = rdf_licenses; license->name; license++ ) {
1088 if ( rdf_match_license( repr, license ) ) {
1089 license_by_properties = license;
1090 break;
1091 }
1092 }
1093 }
1094
1095 if (license_by_uri != nullptr && license_by_properties != nullptr) {
1096 // Both property and structure, use property
1097 if (license_by_uri != license_by_properties) {
1098 // TODO: this should be a user-visible warning, but how?
1099 g_warning("Mismatch between %s and %s metadata:\n"
1100 "%s value URI: %s (using this one!)\n"
1101 "%s derived URI: %s",
1102 XML_TAG_NAME_LICENSE_PROP,
1103 XML_TAG_NAME_LICENSE,
1104 XML_TAG_NAME_LICENSE_PROP,
1105 license_by_uri->uri,
1106 XML_TAG_NAME_LICENSE,
1107 license_by_properties->uri);
1108 }
1109
1110 if (!read_only) {
1111 // Reset license structure to match so the document is consistent
1112 // (and this will also silence the warning above on repeated calls).
1113 setLicense(document, license_by_uri);
1114 }
1115
1116 return license_by_uri;
1117 }
1118 else if (license_by_uri != nullptr) {
1119 if (!read_only) {
1120 // Only cc:license property, set structure for backward compatibility
1121 setLicense(document, license_by_uri);
1122 }
1123
1124 return license_by_uri;
1125 }
1126 else if (license_by_properties != nullptr) {
1127 if (!read_only) {
1128 // Only cc:License structure
1129 // TODO: this could be a user-visible warning too
1130 g_warning("No %s metadata found, derived license URI from %s: %s",
1131 XML_TAG_NAME_LICENSE_PROP, XML_TAG_NAME_LICENSE,
1132 license_by_properties->uri);
1133
1134 // Set license property to match
1135 setWorkEntity(document, *entity, license_by_properties->uri);
1136 }
1137
1138 return license_by_properties;
1139 }
1140
1141 // No license info at all
1142 return nullptr;
1143}
1144
1145// Public API:
1146void rdf_set_license(SPDocument * doc, struct rdf_license_t const * license)
1147{
1148 RDFImpl::setLicense( doc, license );
1149}
1150
1151void RDFImpl::setLicense(SPDocument * doc, struct rdf_license_t const * license)
1152{
1153 // When basing license check on only the license URI (see fix for
1154 // https://bugs.launchpad.net/inkscape/+bug/372427 above) we should
1155 // really drop this license section, but keep writing it for a while for
1156 // compatibility with older versions.
1157
1158 // drop old license section
1159 Inkscape::XML::Node * repr = getXmlRepr( doc, XML_TAG_NAME_LICENSE );
1160 if (repr) {
1161 sp_repr_unparent(repr);
1162 }
1163
1164 if ( !license ) {
1165 // All done
1166 } else if ( !doc->getReprDoc() ) {
1167 g_critical("XML doc is null.");
1168 } else {
1169 // build new license section
1170 repr = ensureXmlRepr( doc, XML_TAG_NAME_LICENSE );
1171 g_assert( repr );
1172
1173 repr->setAttribute("rdf:about", license->uri );
1174
1175 for (struct rdf_double_t const * detail = license->details; detail->name; detail++) {
1176 Inkscape::XML::Node * child = doc->getReprDoc()->createElement( detail->name );
1177 g_assert ( child != nullptr );
1178
1179 child->setAttribute("rdf:resource", detail->resource );
1180 repr->appendChild(child);
1182 }
1183 }
1184}
1185
1186// Public API:
1188{
1189 RDFImpl::setDefaults( doc );
1190
1191}
1192
1193void RDFImpl::setDefaults( SPDocument * doc )
1194{
1195 g_assert( doc != nullptr );
1196
1197 // Used to add hard coded defaults here
1198}
1199
1200/*
1201 * Add the metadata stored in the users preferences to the document if
1202 * a) the preference 'Input/Output->Add default metadata to new documents' is true, and
1203 * b) there is no metadata already in the file (such as from a template)
1204 */
1206{
1208 if (!prefs->getBool("/metadata/addToNewFile")) {
1209 return;
1210 }
1211
1212 // If there is already some metadata in the doc (from a template) don't add default metadata
1213 for (struct rdf_work_entity_t *entity = rdf_work_entities; entity && entity->name; entity++) {
1214 if ( entity->editable == RDF_EDIT_GENERIC &&
1215 rdf_get_work_entity (doc, entity)) {
1216 return;
1217 }
1218 }
1219
1220 // Put the metadata from user preferences into the doc
1221 for (struct rdf_work_entity_t *entity = rdf_work_entities; entity && entity->name; entity++) {
1222 if ( entity->editable == RDF_EDIT_GENERIC ) {
1223 Glib::ustring text = prefs->getString(PREFS_METADATA + Glib::ustring(entity->name));
1224 if (text.length() > 0) {
1225 rdf_set_work_entity (doc, entity, text.c_str());
1226 }
1227 }
1228 }
1229}
1230
1231/*
1232 Local Variables:
1233 mode:c++
1234 c-file-style:"stroustrup"
1235 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1236 indent-tabs-mode:nil
1237 fill-column:99
1238 End:
1239*/
1240// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
Preference storage class.
Definition preferences.h:61
bool getBool(Glib::ustring const &pref_path, bool def=false)
Retrieve a Boolean value.
Glib::ustring getString(Glib::ustring const &pref_path, Glib::ustring const &def="")
Retrieve an UTF-8 string.
static Preferences * get()
Access the singleton Preferences object.
Interface for refcounted XML nodes.
Definition node.h:80
virtual Node * parent()=0
Get the parent of this node.
virtual Node * next()=0
Get the next sibling of this node.
virtual void appendChild(Node *child)=0
Append a node as the last child of this node.
virtual char const * name() const =0
Get the name of the element node.
void setAttribute(Util::const_char_ptr key, Util::const_char_ptr value)
Change an attribute of this node.
Definition node.cpp:25
virtual Node * firstChild()=0
Get the first child of this node.
virtual void setContent(char const *value)=0
Set the content of a text or comment node.
virtual char const * attribute(char const *key) const =0
Get the string representation of a node's attribute.
virtual char const * content() const =0
Get the content of a text or comment node.
virtual Document * document()=0
Get the node's associated document.
virtual void removeChild(Node *child)=0
Remove a child of this node.
Typed SVG document implementation.
Definition document.h:101
SPRoot * getRoot()
Returns our SPRoot.
Definition document.h:200
Inkscape::XML::Node * getReprRoot()
Definition document.h:206
Inkscape::XML::Document * getReprDoc()
Our Inkscape::XML::Document.
Definition document.h:211
bool setTitle(char const *title, bool verbatim=false)
Sets the title of this object.
Css & result
static char const *const current
Definition dir-util.cpp:71
static char const *const parent
Definition dir-util.cpp:70
SPItem * item
Inkscape::XML::Node * node
static R & anchor(R &r)
Increments the reference count of a anchored object.
Definition gc-anchored.h:92
static R & release(R &r)
Decrements the reference count of a anchored object.
Singleton class to access the preferences file in a convenient way.
Ocnode * child[8]
Definition quantize.cpp:33
struct rdf_license_t rdf_licenses[]
Definition rdf.cpp:179
struct rdf_work_entity_t rdf_work_entities[]
Definition rdf.cpp:240
unsigned int rdf_set_work_entity(SPDocument *doc, struct rdf_work_entity_t *entity, const gchar *text)
Definition rdf.cpp:914
struct rdf_work_entity_t * rdf_find_entity(gchar const *name)
Retrieves a known RDF/Work entity by name.
Definition rdf.cpp:364
struct rdf_double_t rdf_license_cc_a_nc[]
Definition rdf.cpp:119
struct rdf_double_t rdf_license_cc_a_nc_sa[]
Definition rdf.cpp:129
struct rdf_license_t * rdf_get_license(SPDocument *document, bool read_only)
Attempts to match and retrieve a known RDF/License from the document XML.
Definition rdf.cpp:1047
void rdf_add_from_preferences(SPDocument *doc)
Definition rdf.cpp:1205
struct rdf_double_t rdf_license_cc_a_nd[]
Definition rdf.cpp:111
static bool rdf_match_license(Inkscape::XML::Node const *repr, struct rdf_license_t const *license)
Definition rdf.cpp:961
struct rdf_double_t rdf_license_cc_a_sa[]
Definition rdf.cpp:101
struct rdf_double_t rdf_license_cc_a_nc_nd[]
Definition rdf.cpp:140
void rdf_set_license(SPDocument *doc, struct rdf_license_t const *license)
Stores an RDF/License XML in the document XML.
Definition rdf.cpp:1146
struct rdf_double_t rdf_license_freeart[]
Definition rdf.cpp:156
struct rdf_double_t rdf_license_cc_a[]
Definition rdf.cpp:92
void rdf_set_defaults(SPDocument *doc)
Definition rdf.cpp:1187
struct rdf_double_t rdf_license_ofl[]
Definition rdf.cpp:166
struct rdf_double_t rdf_license_pd[]
Definition rdf.cpp:149
struct rdf_double_t rdf_license_empty[]
Definition rdf.cpp:88
const gchar * rdf_get_work_entity(SPDocument const *doc, struct rdf_work_entity_t *entity)
Retrieves a known RDF/Work entity's contents from the document XML by name.
Definition rdf.cpp:885
headers for RDF types
constexpr auto PREFS_METADATA
Definition rdf.h:19
@ RDF_FORMAT_MULTILINE
Definition rdf.h:58
@ RDF_FORMAT_LINE
Definition rdf.h:57
@ RDF_CONTENT
Definition rdf.h:46
@ RDF_RESOURCE
Definition rdf.h:48
@ RDF_XML
Definition rdf.h:49
@ RDF_BAG
Definition rdf.h:50
@ RDF_AGENT
Definition rdf.h:47
@ RDF_EDIT_HARDCODED
Definition rdf.h:65
@ RDF_EDIT_GENERIC
Definition rdf.h:63
@ RDF_EDIT_SPECIAL
Definition rdf.h:64
Inkscape::XML::Node const * sp_repr_lookup_name(Inkscape::XML::Node const *repr, gchar const *name, gint maxdepth)
C facade to Inkscape::XML::Node.
void sp_repr_unparent(Inkscape::XML::Node *repr)
Remove repr from children of its parent node.
Definition repr.h:107
SPRoot: SVG <svg> implementation.
Interface for XML documents.
Definition document.h:43
virtual Node * createTextNode(char const *content)=0
virtual Node * createElement(char const *name)=0
Holds license name/resource doubles for rdf_license_t entries.
Definition rdf.h:25
char const * resource
Definition rdf.h:27
char const * name
Definition rdf.h:26
Holds license name and RDF information.
Definition rdf.h:33
char const * uri
Definition rdf.h:35
char const * name
Definition rdf.h:34
struct rdf_double_t * details
Definition rdf.h:36
Holds known RDF/Work tags.
Definition rdf.h:71
RDF_Editable editable
Definition rdf.h:78
char const * name
Definition rdf.h:72
RDFType datatype
Definition rdf.h:75
char const * tag
Definition rdf.h:74
Glib::ustring name
Definition toolbars.cpp:55