1 /*
  2  * jQuery RDFa @VERSION
  3  *
  4  * Copyright (c) 2008,2009 Jeni Tennison
  5  * Licensed under the MIT (MIT-LICENSE.txt)
  6  *
  7  * Depends:
  8  *  jquery.uri.js
  9  *  jquery.xmlns.js
 10  *  jquery.curie.js
 11  *  jquery.datatype.js
 12  *  jquery.rdf.js
 13  */
 14 /**
 15  * @fileOverview jQuery RDFa processing
 16  * @author <a href="mailto:jeni@jenitennison.com">Jeni Tennison</a>
 17  * @copyright (c) 2008,2009 Jeni Tennison
 18  * @license MIT license (MIT-LICENSE.txt)
 19  * @version 1.0
 20  * @requires jquery.uri.js
 21  * @requires jquery.xmlns.js
 22  * @requires jquery.curie.js
 23  * @requires jquery.datatype.js
 24  * @requires jquery.rdf.js
 25  */
 26 (function ($) {
 27 
 28   var
 29     ns = {
 30       rdf: "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
 31       xsd: "http://www.w3.org/2001/XMLSchema#",
 32       xml: 'http://www.w3.org/XML/1998/namespace',
 33       xmlns: 'http://www.w3.org/2000/xmlns/'
 34     },
 35 
 36     rdfXMLLiteral = ns.rdf + 'XMLLiteral',
 37 
 38     rdfaCurieDefaults = $.fn.curie.defaults,
 39     relReserved = [
 40       'alternate', 'appendix', 'bookmark', 'cite', 'chapter', 'contents', 'copyright',
 41       'first', 'glossary', 'help', 'icon', 'index', 'last', 'license', 'meta', 'next',
 42       'p3pv1', 'prev', 'role', 'section', 'stylesheet', 'subsection', 'start', 'top', 'up'
 43     ],
 44 
 45     attRegex = /\s([^ =]+)\s*=\s*(?:"([^"]*)"|'([^']*)'|([^ >]+))/g,
 46     
 47     ncNameChar = '[-A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u10000-\uEFFFF\.0-9\u00B7\u0300-\u036F\u203F-\u2040]',
 48     ncNameStartChar = '[\u0041-\u005A\u0061-\u007A\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\u0131\u0134-\u013E\u0141-\u0148\u014A-\u017E\u0180-\u01C3\u01CD-\u01F0\u01F4-\u01F5\u01FA-\u0217\u0250-\u02A8\u02BB-\u02C1\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03CE\u03D0-\u03D6\u03DA\u03DC\u03DE\u03E0\u03E2-\u03F3\u0401-\u040C\u040E-\u044F\u0451-\u045C\u045E-\u0481\u0490-\u04C4\u04C7-\u04C8\u04CB-\u04CC\u04D0-\u04EB\u04EE-\u04F5\u04F8-\u04F9\u0531-\u0556\u0559\u0561-\u0586\u05D0-\u05EA\u05F0-\u05F2\u0621-\u063A\u0641-\u064A\u0671-\u06B7\u06BA-\u06BE\u06C0-\u06CE\u06D0-\u06D3\u06D5\u06E5-\u06E6\u0905-\u0939\u093D\u0958-\u0961\u0985-\u098C\u098F-\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09DC-\u09DD\u09DF-\u09E1\u09F0-\u09F1\u0A05-\u0A0A\u0A0F-\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32-\u0A33\u0A35-\u0A36\u0A38-\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8B\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2-\u0AB3\u0AB5-\u0AB9\u0ABD\u0AE0\u0B05-\u0B0C\u0B0F-\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32-\u0B33\u0B36-\u0B39\u0B3D\u0B5C-\u0B5D\u0B5F-\u0B61\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99-\u0B9A\u0B9C\u0B9E-\u0B9F\u0BA3-\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB5\u0BB7-\u0BB9\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C60-\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CDE\u0CE0-\u0CE1\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D28\u0D2A-\u0D39\u0D60-\u0D61\u0E01-\u0E2E\u0E30\u0E32-\u0E33\u0E40-\u0E45\u0E81-\u0E82\u0E84\u0E87-\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA-\u0EAB\u0EAD-\u0EAE\u0EB0\u0EB2-\u0EB3\u0EBD\u0EC0-\u0EC4\u0F40-\u0F47\u0F49-\u0F69\u10A0-\u10C5\u10D0-\u10F6\u1100\u1102-\u1103\u1105-\u1107\u1109\u110B-\u110C\u110E-\u1112\u113C\u113E\u1140\u114C\u114E\u1150\u1154-\u1155\u1159\u115F-\u1161\u1163\u1165\u1167\u1169\u116D-\u116E\u1172-\u1173\u1175\u119E\u11A8\u11AB\u11AE-\u11AF\u11B7-\u11B8\u11BA\u11BC-\u11C2\u11EB\u11F0\u11F9\u1E00-\u1E9B\u1EA0-\u1EF9\u1F00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2126\u212A-\u212B\u212E\u2180-\u2182\u3041-\u3094\u30A1-\u30FA\u3105-\u312C\uAC00-\uD7A3\u4E00-\u9FA5\u3007\u3021-\u3029_]',
 49     ncNameRegex = new RegExp('^' + ncNameStartChar + ncNameChar + '*$'),
 50 
 51     docResource = $.rdf.resource('<>'),
 52 
 53     parseEntities = function (string) {
 54       var result = "", m, entity;
 55       if (!/&/.test(string)) {
 56          return string;
 57       }
 58       while (string.length > 0) {
 59         m = /([^&]*)(&([^;]+);)(.*)/g.exec(string);
 60         if (m === null) {
 61           result += string;
 62           break;
 63         }
 64         result += m[1];
 65         entity = m[3];
 66         string = m[4];
 67         if (entity.charAt(0) === '#') {
 68           if (entity.charAt(1) === 'x') {
 69               result += String.fromCharCode(parseInt(entity.substring(2), 16));
 70           } else {
 71               result += String.fromCharCode(parseInt(entity.substring(1), 10));
 72           }
 73         } else {
 74           switch(entity) {
 75             case 'amp':
 76               result += '&';
 77               break;
 78             case 'nbsp':
 79               result += String.fromCharCode(160);
 80               break;
 81             case 'quot':
 82               result += '"';
 83               break;
 84             case 'apos':
 85               result += "'";
 86               break;
 87             default:
 88               result += '&' + entity + ';';
 89           }
 90         }
 91       }
 92       return result;
 93     },
 94 
 95     getAttributes = function (elem) {
 96       var i, e, a, tag, name, value, attMap, prefix,
 97         atts = {},
 98         nsMap = {};
 99       e = elem[0];
100       nsMap[':length'] = 0;
101       if (e.attributes && e.attributes.getNamedItemNS) {
102         attMap = e.attributes;
103         for (i = 0; i < attMap.length; i += 1) {
104           a = attMap[i];
105           if (/^xmlns(:(.+))?$/.test(a.nodeName) && a.nodeValue !== '') {
106             prefix = /^xmlns(:(.+))?$/.exec(a.nodeName)[2] || '';
107             if (ncNameRegex.test(prefix) && (prefix !== 'xml' || a.nodeValue === ns.xml) && (a.nodeValue !== ns.xml || prefix === 'xml') && prefix !== 'xmlns' && a.nodeValue !== ns.xmlns) {
108               nsMap[prefix] = $.uri(a.nodeValue);
109               nsMap[':length'] += 1;
110             }
111 //          } else if (/rel|rev|lang|xml:lang/.test(a.nodeName)) {
112 //            atts[a.nodeName] = a.nodeValue === '' ? undefined : a.nodeValue;
113           } else if (/rel|rev|lang|xml:lang|about|href|src|resource|property|typeof|content|datatype/.test(a.nodeName)) {
114             atts[a.nodeName] = a.nodeValue === null ? undefined : a.nodeValue;
115           }
116         }
117       } else {
118         tag = /<[^>]+>/.exec(e.outerHTML);
119         a = attRegex.exec(tag);
120         while (a !== null) {
121           name = a[1];
122           value = a[2] || a[3] || a[4];
123           if (/^xmlns/.test(name) && name !== 'xmlns:' && value !== '') {
124             prefix = /^xmlns(:(.+))?$/.exec(name)[2] || '';
125             if (ncNameRegex.test(prefix) && (prefix !== 'xml' || a.nodeValue === ns.xml) && (a.nodeValue !== ns.xml || prefix === 'xml') && prefix !== 'xmlns' && a.nodeValue !== ns.xmlns) {
126               nsMap[prefix] = $.uri(value);
127               nsMap[':length'] += 1;
128             }
129           } else if (/about|href|src|resource|property|typeof|content|datatype|rel|rev|lang|xml:lang/.test(name)) {
130             atts[name] = parseEntities(value);
131           }
132           a = attRegex.exec(tag);
133         }
134         attRegex.lastIndex = 0;
135       }
136       return { atts: atts, namespaces: nsMap };
137     },
138 
139     getAttribute = function (elem, attr) {
140       var val = elem[0].getAttribute(attr);
141 //      if (attr === 'rev' || attr === 'rel' || attr === 'lang' || attr === 'xml:lang') {
142 //        val = val === '' ? undefined : val;
143 //      }
144       return val === null ? undefined : val;
145     },
146 
147     resourceFromUri = function (uri) {
148       return $.rdf.resource(uri);
149     },
150 
151     resourceFromCurie = function (curie, elem, noblanks, options) {
152       if (curie.substring(0, 2) === '_:') {
153         if (noblanks) {
154           return undefined;
155         }
156         return $.rdf.blank(curie);
157       } else {
158         try {
159           return resourceFromUri($.curie(curie, options));
160         } catch (e) {
161           return undefined;
162         }
163       }
164     },
165 
166     resourceFromSafeCurie = function (safeCurie, elem, options) {
167       var m = /^\[(.*)\]$/.exec(safeCurie),
168         base = options.base || elem.base();
169       return m ? resourceFromCurie(m[1], elem, false, options) : resourceFromUri($.uri(safeCurie, base));
170     },
171 
172     resourcesFromCuries = function (curies, elem, noblanks, options) {
173       var i, resource, resources = [];
174       curies = curies && curies.split ? curies.split(/[ \t\n\r\x0C]+/g) : [];
175       for (i = 0; i < curies.length; i += 1) {
176         if (curies[i] !== '') {
177           resource = resourceFromCurie(curies[i], elem, noblanks, options);
178           if (resource !== undefined) {
179             resources.push(resource);
180           }
181         }
182       }
183       return resources;
184     },
185 
186     removeCurie = function (curies, resource, options) {
187       var i, r, newCuries = [];
188       resource = resource.type === 'uri' ? resource : $.rdf.resource(resource, options);
189       curies = curies && curies.split ? curies.split(/\s+/) : [];
190       for (i = 0; i < curies.length; i += 1) {
191         if (curies[i] !== '') {
192           r = resourceFromCurie(curies[i], null, false, options);
193           if (r !== resource) {
194             newCuries.push(curies[i]);
195           }
196         }
197       }
198       return newCuries.reverse().join(' ');
199     },
200 
201     getObjectResource = function (elem, context, relation) {
202       var r, resource, atts, curieOptions;
203       context = context || {};
204       atts = context.atts || getAttributes(elem).atts;
205       r = relation === undefined ? atts.rel !== undefined || atts.rev !== undefined : relation;
206       resource = atts.resource;
207       resource = resource === undefined ? atts.href : resource;
208       if (resource === undefined) {
209         resource = r ? $.rdf.blank('[]') : resource;
210       } else {
211         curieOptions = context.curieOptions || $.extend({}, rdfaCurieDefaults, { namespaces: elem.xmlns() });
212         resource = resourceFromSafeCurie(resource, elem, curieOptions);
213       }
214       return resource;
215     },
216 
217     getSubject = function (elem, context, relation) {
218       var r, atts, curieOptions, subject, skip = false;
219       context = context || {};
220       atts = context.atts || getAttributes(elem).atts;
221       curieOptions = context.curieOptions || $.extend({}, rdfaCurieDefaults, { namespaces: elem.xmlns(), base: elem.base() });
222       r = relation === undefined ? atts.rel !== undefined || atts.rev !== undefined : relation;
223       if (atts.about !== undefined) {
224         subject = resourceFromSafeCurie(atts.about, elem, curieOptions);
225       }
226       if (subject === undefined && atts.src !== undefined) {
227         subject = resourceFromSafeCurie(atts.src, elem, curieOptions);
228       }
229       if (!r && subject === undefined && atts.resource !== undefined) {
230         subject = resourceFromSafeCurie(atts.resource, elem, curieOptions);
231       }
232       if (!r && subject === undefined && atts.href !== undefined) {
233         subject = resourceFromSafeCurie(atts.href, elem, curieOptions);
234       }
235       if (subject === undefined) {
236         if (/^(head|body)$/i.test(elem[0].nodeName)) {
237           subject = docResource;
238         } else if (atts['typeof'] !== undefined) {
239           subject = $.rdf.blank('[]');
240         } else if (elem[0].parentNode.nodeType === 1) {
241           subject = context.object || getObjectResource(elem.parent()) || getSubject(elem.parent()).subject;
242           skip = !r && atts.property === undefined;
243         } else {
244           subject = docResource;
245         }
246       }
247       return { subject: subject, skip: skip };
248     },
249 
250     getLang = function (elem, context) {
251       var lang;
252       context = context || {};
253       if (context.atts) {
254         lang = context.atts.lang;
255         lang = lang || context.atts['xml:lang'];
256       } else {
257         lang = elem[0].getAttribute('lang');
258         try {
259           lang = (lang === null || lang === '') ? elem[0].getAttribute('xml:lang') : lang;
260         } catch (e) {
261         }
262         lang = (lang === null || lang === '') ? undefined : lang;
263       }
264       if (lang === undefined) {
265         if (context.lang) {
266           lang = context.lang;
267         } else {
268           if (elem[0].parentNode.nodeType === 1) {
269             lang = getLang(elem.parent());
270           }
271         }
272       }
273       return lang;
274     },
275 
276     entity = function (c) {
277       switch (c) {
278       case '<':
279         return '<';
280       case '"':
281         return '"';
282       case '&':
283         return '&';
284       }
285     },
286 
287     serialize = function (elem, ignoreNs) {
288       var i, string = '', atts, a, name, ns, tag;
289       elem.contents().each(function () {
290         var j = $(this),
291           e = j[0];
292         if (e.nodeType === 1) { // tests whether the node is an element
293           name = e.nodeName.toLowerCase();
294           string += '<' + name;
295           if (e.outerHTML) {
296             tag = /<[^>]+>/.exec(e.outerHTML);
297             a = attRegex.exec(tag);
298             while (a !== null) {
299               if (!/^jQuery/.test(a[1])) {
300                 string += ' ' + a[1] + '=';
301                 string += a[2] ? a[3] : '"' + a[1] + '"';
302               }
303               a = attRegex.exec(tag);
304             }
305             attRegex.lastIndex = 0;
306           } else {
307             atts = e.attributes;
308             for (i = 0; i < atts.length; i += 1) {
309               a = atts.item(i);
310               string += ' ' + a.nodeName + '="';
311               string += a.nodeValue.replace(/[<"&]/g, entity);
312               string += '"';
313             }
314           }
315           if (!ignoreNs) {
316             ns = j.xmlns('');
317             if (ns !== undefined && j.attr('xmlns') === undefined) {
318               string += ' xmlns="' + ns + '"';
319             }
320           }
321           string += '>';
322           string += serialize(j, true);
323           string += '</' + name + '>';
324         } else if (e.nodeType === 8) { // tests whether the node is a comment
325           string += '<!--';
326           string += e.nodeValue;
327           string += '-->';
328         } else {
329           string += e.nodeValue;
330         }
331       });
332       return string;
333     },
334 
335     rdfa = function (context) {
336       var i, subject, resource, lang, datatype, content, text,
337         types, object, triple, parent,
338         properties, rels, revs,
339         forward, backward,
340         triples = [],
341         callback, relCurieOptions,
342         attsAndNs, atts, namespaces, ns,
343         children = this.children();
344       context = context || {};
345       forward = context.forward || [];
346       backward = context.backward || [];
347       callback = context.callback || function () { return this; };
348       attsAndNs = getAttributes(this);
349       atts = attsAndNs.atts;
350       context.atts = atts;
351       namespaces = context.namespaces || this.xmlns();
352       if (attsAndNs.namespaces[':length'] > 0) {
353         namespaces = $.extend({}, namespaces);
354         for (ns in attsAndNs.namespaces) {
355           if (ns !== ':length') {
356             namespaces[ns] = attsAndNs.namespaces[ns];
357           }
358         }
359       }
360       context.curieOptions = $.extend({}, rdfaCurieDefaults, { reserved: [], namespaces: namespaces, base: this.base() });
361       relCurieOptions = $.extend({}, context.curieOptions, { reserved: relReserved });
362       subject = getSubject(this, context);
363       lang = getLang(this, context);
364       if (subject.skip) {
365         rels = context.forward;
366         revs = context.backward;
367         subject = context.subject;
368         resource = context.object;
369       } else {
370         subject = subject.subject;
371         if (forward.length > 0 || backward.length > 0) {
372           parent = context.subject || getSubject(this.parent()).subject;
373           for (i = 0; i < forward.length; i += 1) {
374             triple = $.rdf.triple(parent, forward[i], subject, { source: this[0] });
375             triple = callback.call(triple, this.get(0), triple);
376             if (triple !== undefined && triple !== null) {
377               triples = triples.concat(triple);
378             }
379           }
380           for (i = 0; i < backward.length; i += 1) {
381             triple = $.rdf.triple(subject, backward[i], parent, { source: this[0] });
382             triple = callback.call(triple, this.get(0), triple);
383             if (triple !== undefined && triple !== null) {
384               triples = triples.concat(triple);
385             }
386           }
387         }
388         resource = getObjectResource(this, context);
389         types = resourcesFromCuries(atts['typeof'], this, false, context.curieOptions);
390         for (i = 0; i < types.length; i += 1) {
391           triple = $.rdf.triple(subject, $.rdf.type, types[i], { source: this[0] });
392           triple = callback.call(triple, this.get(0), triple);
393           if (triple !== undefined && triple !== null) {
394             triples = triples.concat(triple);
395           }
396         }
397         properties = resourcesFromCuries(atts.property, this, true, context.curieOptions);
398         if (properties.length > 0) {
399           datatype = atts.datatype;
400           content = atts.content;
401           text = this.text().replace(/"/g, '\\"');
402           if (datatype !== undefined && datatype !== '') {
403             datatype = $.curie(datatype, context.curieOptions);
404             if (datatype.toString() === rdfXMLLiteral) {
405               object = $.rdf.literal(serialize(this), { datatype: rdfXMLLiteral });
406             } else if (content !== undefined) {
407               object = $.rdf.literal(content, { datatype: datatype });
408             } else {
409               object = $.rdf.literal(text, { datatype: datatype });
410             }
411           } else if (content !== undefined) {
412             if (lang === undefined) {
413               object = $.rdf.literal('"' + content + '"');
414             } else {
415               object = $.rdf.literal(content, { lang: lang });
416             }
417           } else if (children.length === 0 ||
418                      datatype === '') {
419             lang = getLang(this, context);
420             if (lang === undefined) {
421               object = $.rdf.literal('"' + text + '"');
422             } else {
423               object = $.rdf.literal(text, { lang: lang });
424             }
425           } else {
426             object = $.rdf.literal(serialize(this), { datatype: rdfXMLLiteral });
427           }
428           for (i = 0; i < properties.length; i += 1) {
429             triple = $.rdf.triple(subject, properties[i], object, { source: this[0] });
430             triple = callback.call(triple, this.get(0), triple);
431             if (triple !== undefined && triple !== null) {
432               triples = triples.concat(triple);
433             }
434           }
435         }
436         rels = resourcesFromCuries(atts.rel, this, true, relCurieOptions);
437         revs = resourcesFromCuries(atts.rev, this, true, relCurieOptions);
438         if (atts.resource !== undefined || atts.href !== undefined) {
439           // make the triples immediately
440           if (rels !== undefined) {
441             for (i = 0; i < rels.length; i += 1) {
442               triple = $.rdf.triple(subject, rels[i], resource, { source: this[0] });
443               triple = callback.call(triple, this.get(0), triple);
444               if (triple !== undefined && triple !== null) {
445                 triples = triples.concat(triple);
446               }
447             }
448           }
449           rels = [];
450           if (revs !== undefined) {
451             for (i = 0; i < revs.length; i += 1) {
452               triple = $.rdf.triple(resource, revs[i], subject, { source: this[0] });
453               triple = callback.call(triple, this.get(0), triple);
454               if (triple !== undefined && triple !== null) {
455                 triples = triples.concat(triple);
456               }
457             }
458           }
459           revs = [];
460         }
461       }
462       children.each(function () {
463         triples = triples.concat(rdfa.call($(this), { forward: rels, backward: revs, subject: subject, object: resource || subject, lang: lang, namespaces: namespaces, callback: callback }));
464       });
465       return triples;
466     },
467 
468     gleaner = function (options) {
469       var type, atts;
470       if (options && options.about !== undefined) {
471         atts = getAttributes(this).atts;
472         if (options.about === null) {
473           return atts.property !== undefined ||
474                  atts.rel !== undefined ||
475                  atts.rev !== undefined ||
476                  atts['typeof'] !== undefined;
477         } else {
478           return getSubject(this, {atts: atts}).subject.value === options.about;
479         }
480       } else if (options && options.type !== undefined) {
481         type = getAttribute(this, 'typeof');
482         if (type !== undefined) {
483           return options.type === null ? true : this.curie(type) === options.type;
484         }
485         return false;
486       } else {
487         return rdfa.call(this, options);
488       }
489     },
490 
491     nsCounter = 1,
492 
493     createCurieAttr = function (elem, attr, uri) {
494       var m, curie, value;
495       try {
496         curie = elem.createCurie(uri);
497       } catch (e) {
498         if (uri.toString() === rdfXMLLiteral) {
499           elem.attr('xmlns:rdf', ns.rdf);
500           curie = 'rdf:XMLLiteral';
501         } else {
502           m = /^(.+[\/#])([^#]+)$/.exec(uri);
503           elem.attr('xmlns:ns' + nsCounter, m[1]);
504           curie = 'ns' + nsCounter + ':' + m[2];
505           nsCounter += 1;
506         }
507       }
508       value = getAttribute(elem, attr);
509       if (value !== undefined) {
510         if ($.inArray(curie, value.split(/\s+/)) === -1) {
511           elem.attr(attr, value + ' ' + curie);
512         }
513       } else {
514         elem.attr(attr, curie);
515       }
516     },
517 
518     createResourceAttr = function (elem, attr, resource) {
519       var ref;
520       if (resource.type === 'bnode') {
521         ref = '[_:' + resource.id + ']';
522       } else {
523         ref = $(elem).base().relative(resource.value);
524       }
525       elem.attr(attr, ref);
526     },
527 
528     createSubjectAttr = function (elem, subject) {
529       var s = getSubject(elem).subject;
530       if (subject !== s) {
531         createResourceAttr(elem, 'about', subject);
532       }
533       elem.removeData('rdfa.subject');
534     },
535 
536     createObjectAttr = function (elem, object) {
537       var o = getObjectResource(elem);
538       if (object !== o) {
539         createResourceAttr(elem, 'resource', object);
540       }
541       elem.removeData('rdfa.objectResource');
542     },
543 
544     resetLang = function (elem, lang) {
545       elem.wrapInner('<span></span>')
546         .children('span')
547         .attr('lang', lang);
548       return elem;
549     },
550 
551     addRDFa = function (triple) {
552       var hasContent, hasRelation, hasRDFa, overridableObject, span,
553         subject, sameSubject,
554         object, sameObject,
555         lang, content,
556         i, atts,
557         ns = this.xmlns();
558       span = this;
559       atts = getAttributes(this).atts;
560       if (typeof triple === 'string') {
561         triple = $.rdf.triple(triple, { namespaces: ns, base: this.base() });
562       } else if (triple.rdfquery) {
563         addRDFa.call(this, triple.sources().get(0));
564         return this;
565       } else if (triple.length) {
566         for (i = 0; i < triple.length; i += 1) {
567           addRDFa.call(this, triple[i]);
568         }
569         return this;
570       }
571       hasRelation = atts.rel !== undefined || atts.rev !== undefined;
572       hasRDFa = hasRelation || atts.property !== undefined || atts['typeof'] !== undefined;
573       if (triple.object.type !== 'literal') {
574         subject = getSubject(this, {atts: atts}, true).subject;
575         object = getObjectResource(this, {atts: atts}, true);
576         overridableObject = !hasRDFa && atts.resource === undefined;
577         sameSubject = subject === triple.subject;
578         sameObject = object === triple.object;
579         if (triple.property === $.rdf.type) {
580           if (sameSubject) {
581             createCurieAttr(this, 'typeof', triple.object.value);
582           } else if (hasRDFa) {
583             span = this.wrapInner('<span />').children('span');
584             createCurieAttr(span, 'typeof', triple.object.value);
585             if (object !== triple.subject) {
586               createSubjectAttr(span, triple.subject);
587             }
588           } else {
589             createCurieAttr(this, 'typeof', triple.object.value);
590             createSubjectAttr(this, triple.subject);
591           }
592         } else if (sameSubject) {
593           // use a rel
594           if (sameObject) {
595             createCurieAttr(this, 'rel', triple.property.value);
596           } else if (overridableObject || !hasRDFa) {
597             createCurieAttr(this, 'rel', triple.property.value);
598             createObjectAttr(this, triple.object);
599           } else {
600             span = this.wrap('<span />').parent();
601             createCurieAttr(span, 'rev', triple.property.value);
602             createSubjectAttr(span, triple.object);
603           }
604         } else if (subject === triple.object) {
605           if (object === triple.subject) {
606             // use a rev
607             createCurieAttr(this, 'rev', triple.property.value);
608           } else if (overridableObject || !hasRDFa) {
609             createCurieAttr(this, 'rev', triple.property.value);
610             createObjectAttr(this, triple.subject);
611           } else {
612             // wrap in a span with a rel
613             span = this.wrap('<span />').parent();
614             createCurieAttr(span, 'rel', triple.property.value);
615             createSubjectAttr(span, triple.subject);
616           }
617         } else if (sameObject) {
618           if (hasRDFa) {
619             // use a rev on a nested span
620             span = this.wrapInner('<span />').children('span');
621             createCurieAttr(span, 'rev', triple.property.value);
622             createObjectAttr(span, triple.subject);
623             span = span.wrapInner('<span />').children('span');
624             createSubjectAttr(span, triple.object);
625             span = this;
626           } else {
627             createSubjectAttr(this, triple.subject);
628             createCurieAttr(this, 'rel', triple.property.value);
629           }
630         } else if (object === triple.subject) {
631           if (hasRDFa) {
632             // wrap the contents in a span and use a rel
633             span = this.wrapInner('<span />').children('span');
634             createCurieAttr(span, 'rel', this.property.value);
635             createObjectAttr(span, triple.object);
636             span = span.wrapInner('<span />').children('span');
637             createSubjectAttr(span, object);
638             span = this;
639           } else {
640             // use a rev on this element
641             createSubjectAttr(this, triple.object);
642             createCurieAttr(this, 'rev', triple.property.value);
643           }
644         } else if (hasRDFa) {
645           span = this.wrapInner('<span />').children('span');
646           createCurieAttr(span, 'rel', triple.property.value);
647           createSubjectAttr(span, triple.subject);
648           createObjectAttr(span, triple.object);
649           if (span.children('*').length > 0) {
650             span = this.wrapInner('<span />').children('span');
651             createSubjectAttr(span, subject);
652           }
653           span = this;
654         } else {
655           createCurieAttr(span, 'rel', triple.property.value);
656           createSubjectAttr(this, triple.subject);
657           createObjectAttr(this, triple.object);
658           if (this.children('*').length > 0) {
659             span = this.wrapInner('<span />').children('span');
660             createSubjectAttr(span, subject);
661             span = this;
662           }
663         }
664       } else {
665         subject = getSubject(this, {atts: atts}).subject;
666         object = getObjectResource(this, {atts: atts});
667         sameSubject = subject === triple.subject;
668         hasContent = this.text() !== triple.object.value;
669         if (atts.property !== undefined) {
670           content = atts.content;
671           sameObject = content !== undefined ? content === triple.object.value : !hasContent;
672           if (sameSubject && sameObject) {
673             createCurieAttr(this, 'property', triple.property.value);
674           } else {
675             span = this.wrapInner('<span />').children('span');
676             return addRDFa.call(span, triple);
677           }
678         } else {
679           if (object === triple.subject) {
680             span = this.wrapInner('<span />').children('span');
681             return addRDFa.call(span, triple);
682           }
683           createCurieAttr(this, 'property', triple.property.value);
684           createSubjectAttr(this, triple.subject);
685           if (hasContent) {
686             if (triple.object.datatype && triple.object.datatype.toString() === rdfXMLLiteral) {
687               this.html(triple.object.value);
688             } else {
689               this.attr('content', triple.object.value);
690             }
691           }
692           lang = getLang(this);
693           if (triple.object.lang) {
694             if (lang !== triple.object.lang) {
695               this.attr('lang', triple.object.lang);
696               if (hasContent) {
697                 resetLang(this, lang);
698               }
699             }
700           } else if (triple.object.datatype) {
701             createCurieAttr(this, 'datatype', triple.object.datatype);
702           } else {
703             // the empty datatype ensures that any child elements that might be added won't mess up this triple
704             if (!hasContent) {
705               this.attr('datatype', '');
706             }
707             // the empty lang ensures that a language won't be assigned to the literal
708             if (lang !== undefined) {
709               this.attr('lang', '');
710               if (hasContent) {
711                 resetLang(this, lang);
712               }
713             }
714           }
715         }
716       }
717       this.parents().andSelf().trigger("rdfChange");
718       return span;
719     },
720 
721     removeRDFa = function (what) {
722       var span, atts, property, rel, rev, type,
723         ns = this.xmlns();
724       atts = getAttributes(this).atts;
725       if (what.length) {
726         for (i = 0; i < what.length; i += 1) {
727           removeRDFa.call(this, what[i]);
728         }
729         return this;
730       }
731       hasRelation = atts.rel !== undefined || atts.rev !== undefined;
732       hasRDFa = hasRelation || atts.property !== undefined || atts['typeof'] !== undefined;
733       if (hasRDFa) {
734         if (what.property !== undefined) {
735           if (atts.property !== undefined) {
736             property = removeCurie(atts.property, what.property, { namespaces: ns });
737             if (property === '') {
738               this.removeAttr('property');
739             } else {
740               this.attr('property', property);
741             }
742           }
743           if (atts.rel !== undefined) {
744             rel = removeCurie(atts.rel, what.property, { namespaces: ns });
745             if (rel === '') {
746               this.removeAttr('rel');
747             } else {
748               this.attr('rel', rel);
749             }
750           }
751           if (atts.rev !== undefined) {
752             rev = removeCurie(atts.rev, what.property, { namespaces: ns });
753             if (rev === '') {
754               this.removeAttr('rev');
755             } else {
756               this.attr('rev', rev);
757             }
758           }
759         }
760         if (what.type !== undefined) {
761           if (atts['typeof'] !== undefined) {
762             type = removeCurie(atts['typeof'], what.type, { namespaces: ns });
763             if (type === '') {
764               this.removeAttr('typeof');
765             } else {
766               this.attr('typeof', type);
767             }
768           }
769         }
770         if (atts.property === this.attr('property') && atts.rel === this.attr('rel') && atts.rev === this.attr('rev') && atts['typeof'] === this.attr('typeof')) {
771           return removeRDFa.call(this.parent(), what);
772         }
773       }
774       this.parents().andSelf().trigger("rdfChange");
775       return this;
776     };
777 
778   /**
779    * Creates a {@link jQuery.rdf} object containing the RDF triples parsed from the RDFa found in the current jQuery selection or adds the specified triple as RDFa markup on each member of the current jQuery selection. To create an {@link jQuery.rdf} object, you will usually want to use {@link jQuery#rdf} instead, as this may perform other useful processing (such as of microformats used within the page).
780    * @methodOf jQuery#
781    * @name jQuery#rdfa
782    * @param {jQuery.rdf.triple} [triple] The RDF triple to be added to each item in the jQuery selection.
783    * @returns {jQuery.rdf}
784    * @example
785    * // Extract RDFa markup from all span elements contained inside #main
786    * rdf = $('#main > span').rdfa();
787    * @example
788    * // Add RDFa markup to a particular element
789    *  var span = $('#main > p > span');
790    *  span.rdfa('<> dc:date "2008-10-19"^^xsd:date .');
791    */
792   $.fn.rdfa = function (triple) {
793     if (triple === undefined) {
794       var triples = $.map($(this), function (elem) {
795         return rdfa.call($(elem));
796       });
797       return $.rdf({ triples: triples });
798     } else {
799       $(this).each(function () {
800         addRDFa.call($(this), triple);
801       });
802       return this;
803     }
804   };
805 
806   /**
807    * Removes the specified RDFa markup from each of the items in the current jQuery selection. The input parameter can be either an object or an array of objects. The objects can either have a <code>type</code> property, in which case the specified type is removed from the RDFa provided on the selected elements, or a <code>property</code> property, in which case the specified property is removed from the RDFa provided on the selected elements.
808    * @methodOf jQuery#
809    * @name jQuery#removeRdfa
810    * @param {Object|Object[]} triple The RDFa markup items to be removed
811    * from the items in the jQuery selection.
812    * @returns {jQuery} The original jQuery object.
813    * @example 
814    * // To remove a property resource or relation from an element 
815    * $('#main > p > a').removeRdfa({ property: "dc:creator" });
816    * @example
817    * // To remove a type from an element
818    * $('#main >p > a').removeRdfa({ type: "foaf:Person" });
819    * @example
820    * // To remove multiple triples from an element
821    * $('#main > p > a').removeRdfa([{ property: "foaf:depicts" }, { property: "dc:creator" }]);
822    */
823   $.fn.removeRdfa = function (triple) {
824     $(this).each(function () {
825       removeRDFa.call($(this), triple);
826     });
827     return this;
828   };
829 
830   $.rdf.gleaners.push(gleaner);
831 
832 })(jQuery);
833