UNPKG

graph-rdfa-processor

Version:

Green turtle GraphRdfaProcessor extracted and available as a commonJS module

446 lines (425 loc) 16 kB
import Node from './node'; export class RDFaGraph { constructor() { var dataContext = this; this.curieParser = { trim: function(str) { return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }, parse: function(value,resolve) { value = this.trim(value); if (value.charAt(0)=='[' && value.charAt(value.length-1)==']') { value = value.substring(1,value.length-1); } var colon = value.indexOf(":"); if (colon>=0) { var prefix = value.substring(0,colon); if (prefix=="") { // default prefix var uri = dataContext.prefixes[""]; return uri ? uri+value.substring(colon+1) : null; } else if (prefix=="_") { // blank node return "_:"+value.substring(colon+1); } else if (DocumentData.NCNAME.test(prefix)) { var uri = dataContext.prefixes[prefix]; if (uri) { return uri+value.substring(colon+1); } } } return resolve ? dataContext.baseURI.resolve(value) : value; } }; this.base = null; this.toString = function(requestOptions) { var options = requestOptions && requestOptions.shorten ? { graph: this, shorten: true, prefixesUsed: {} } : null; if (requestOptions && requestOptions.blankNodePrefix) { options.filterBlankNode = function(id) { return "_:"+requestOptions.blankNodePrefix+id.substring(2); } } if (requestOptions && requestOptions.numericalBlankNodePrefix) { var onlyNumbers = /^[0-9]+$/; options.filterBlankNode = function(id) { var label = id.substring(2); return onlyNumbers.test(label) ? "_:"+requestOptions.numericalBlankNodePrefix+label : id; } } var s = ""; for (var subject in this.subjects) { var snode = this.subjects[subject]; s += snode.toString(options); s += "\n"; } var prolog = requestOptions && requestOptions.baseURI ? "@base <"+baseURI+"> .\n" : ""; if (options && options.shorten) { for (var prefix in options.prefixesUsed) { prolog += "@prefix "+prefix+": <"+this.prefixes[prefix]+"> .\n"; } } return prolog.length==0 ? s : prolog+"\n"+s; }; this.blankNodeCounter = 0; this.clear = function() { this.subjects = {}; this.prefixes = {}; this.terms = {}; this.blankNodeCounter = 0; } this.clear(); this.prefixes[""] = "http://www.w3.org/1999/xhtml/vocab#"; // w3c this.prefixes["grddl"] = "http://www.w3.org/2003/g/data-view#"; this.prefixes["ma"] = "http://www.w3.org/ns/ma-ont#"; this.prefixes["owl"] = "http://www.w3.org/2002/07/owl#"; this.prefixes["rdf"] = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; this.prefixes["rdfa"] = "http://www.w3.org/ns/rdfa#"; this.prefixes["rdfs"] = "http://www.w3.org/2000/01/rdf-schema#"; this.prefixes["rif"] = "http://www.w3.org/2007/rif#"; this.prefixes["skos"] = "http://www.w3.org/2004/02/skos/core#"; this.prefixes["skosxl"] = "http://www.w3.org/2008/05/skos-xl#"; this.prefixes["wdr"] = "http://www.w3.org/2007/05/powder#"; this.prefixes["void"] = "http://rdfs.org/ns/void#"; this.prefixes["wdrs"] = "http://www.w3.org/2007/05/powder-s#"; this.prefixes["xhv"] = "http://www.w3.org/1999/xhtml/vocab#"; this.prefixes["xml"] = "http://www.w3.org/XML/1998/namespace"; this.prefixes["xsd"] = "http://www.w3.org/2001/XMLSchema#"; // non-rec w3c this.prefixes["sd"] = "http://www.w3.org/ns/sparql-service-description#"; this.prefixes["org"] = "http://www.w3.org/ns/org#"; this.prefixes["gldp"] = "http://www.w3.org/ns/people#"; this.prefixes["cnt"] = "http://www.w3.org/2008/content#"; this.prefixes["dcat"] = "http://www.w3.org/ns/dcat#"; this.prefixes["earl"] = "http://www.w3.org/ns/earl#"; this.prefixes["ht"] = "http://www.w3.org/2006/http#"; this.prefixes["ptr"] = "http://www.w3.org/2009/pointers#"; // widely used this.prefixes["cc"] = "http://creativecommons.org/ns#"; this.prefixes["ctag"] = "http://commontag.org/ns#"; this.prefixes["dc"] = "http://purl.org/dc/terms/"; this.prefixes["dcterms"] = "http://purl.org/dc/terms/"; this.prefixes["foaf"] = "http://xmlns.com/foaf/0.1/"; this.prefixes["gr"] = "http://purl.org/goodrelations/v1#"; this.prefixes["ical"] = "http://www.w3.org/2002/12/cal/icaltzd#"; this.prefixes["og"] = "http://ogp.me/ns#"; this.prefixes["rev"] = "http://purl.org/stuff/rev#"; this.prefixes["sioc"] = "http://rdfs.org/sioc/ns#"; this.prefixes["v"] = "http://rdf.data-vocabulary.org/#"; this.prefixes["vcard"] = "http://www.w3.org/2006/vcard/ns#"; this.prefixes["schema"] = "http://schema.org/"; // terms this.terms["describedby"] = "http://www.w3.org/2007/05/powder-s#describedby"; this.terms["license"] = "http://www.w3.org/1999/xhtml/vocab#license"; this.terms["role"] = "http://www.w3.org/1999/xhtml/vocab#role"; Object.defineProperty(this,"tripleCount",{ enumerable: true, configurable: false, get: function() { var count = 0; for (var s in this.subjects) { var snode = this.subjects[s]; for (var p in snode.predicates) { count += snode.predicates[p].objects.length; } } return count; } }); } newBlankNode() { this.blankNodeCounter++; return "_:"+this.blankNodeCounter; } expand(curie) { return this.curieParser.parse(curie,true); } shorten(uri,prefixesUsed) { for (prefix in this.prefixes) { var mapped = this.prefixes[prefix]; if (uri.indexOf(mapped)==0) { if (prefixesUsed) { prefixesUsed[prefix] = mapped; } return prefix+":"+uri.substring(mapped.length); } } return null; } add(subject,predicate,object,options) { if (!subject || !predicate || !object) { return; } subject = this.expand(subject); predicate = this.expand(predicate); var snode = this.subjects[subject]; if (!snode) { snode = new RDFaSubject(this,subject); this.subjects[subject] = snode; } if (options && options.origin) { snode.origins.push(options.origin); } if (predicate=="http://www.w3.org/1999/02/22-rdf-syntax-ns#type") { snode.types.push(object); } var pnode = snode.predicates[predicate]; if (!pnode) { pnode = new RDFaPredicate(predicate); snode.predicates[predicate] = pnode; } if (typeof object == "string") { pnode.objects.push({ type: RDFaProcessor.PlainLiteralURI, value: object }); } else { pnode.objects.push({ type: object.type ? this.expand(object.type) : RDFaProcessor.PlainLiteralURI, value: object.value ? object.value : "", origin: object.origin, language: object.language }); } } addCollection(subject,predicate,objectList,options) { if (!subject || !predicate || !objectList) { return; } var lastSubject = subject; var lastPredicate = predicate; for (var i=0; i < objectList.length; i++) { var object = { type: options && options.type ? options.type : "rdf:PlainLiteral"}; if (options && options.language) { object.language = options.language; } if (options && options.datatype) { object.datatype = options.datatype; } if (typeof objectList[i] == "object") { object.value = objectList[i].value ? objectList[i].value : ""; if (objectList[i].type) { object.type = objectList[i].type; } if (objectList[i].language) { object.language = objectList[i].language; } if (objectList[i].datatype) { object.datatype = objectList[i].datatype; } } else { object.value = objectList[i] } var bnode = this.newBlankNode(); this.add(lastSubject,lastPredicate,{ type: "rdf:object", value: bnode}); this.add(bnode,"rdf:first",object); lastSubject = bnode; lastPredicate = "http://www.w3.org/1999/02/22-rdf-syntax-ns#rest"; } this.add(lastSubject,lastPredicate,{ type: "rdf:object", value: "http://www.w3.org/1999/02/22-rdf-syntax-ns#nil"}); } remove(subject,predicate) { if (!subject) { this.subjects = {}; return; } subject = this.expand(subject); var snode = this.subjects[snode]; if (!snode) { return; } if (!predicate) { delete this.subjects[subject]; return; } predicate = this.expand(predicate); delete snode.predicates[predicate]; } }; export class RDFaSubject { constructor(graph,subject) { this.graph = graph; // TODO: subject or id? this.subject = subject this.id = subject; this.predicates = {}; this.origins = []; this.types = []; } toString(options) { var s = null; if (this.subject.substring(0,2)=="_:") { if (options && options.filterBlankNode) { s = options.filterBlankNode(this.subject); } else { s = this.subject; } } else if (options && options.shorten) { s = this.graph.shorten(this.subject,options.prefixesUsed); if (!s) { s = "<" + this.subject + ">"; } } else { s = "<" + this.subject + ">"; } var first = true; for (var predicate in this.predicates) { if (!first) { s += ";\n"; } else { first = false; } s += " " + this.predicates[predicate].toString(options); } s += " ."; return s; } toObject() { var o = { subject: this.subject, predicates: {} }; for (var predicate in this.predicates) { var pnode = this.predicates[predicate]; var p = { predicate: predicate, objects: [] }; o.predicates[predicate] = p; for (var i=0; i < pnode.objects.length; i++) { var object = pnode.objects[i]; if (object.type == RDFaProcessor.XMLLiteralURI) { var serializer = new XMLSerializer(); var value = ""; for (var x=0; x < object.value.length; x++) { if (object.value[x].nodeType==Node.ELEMENT_NODE) { value += serializer.serializeToString(object.value[x]); } else if (object.value[x].nodeType==Node.TEXT_NODE) { value += object.value[x].nodeValue; } } p.objects.push({ type: object.type, value: value, language: object.language }); } else if (object.type==RDFaProcessor.HTMLLiteralURI) { var value = object.value.length==0 ? "" : object.value[0].parentNode.innerHTML; p.objects.push({ type: object.type, value: value, language: object.language }); } else { p.objects.push({ type: object.type, value: object.value, language: object.language }); } } } return o; } getValues() { var values = []; for (var i=0; i < arguments.length; i++) { var property = this.graph.curieParser.parse(arguments[i],true) var pnode = this.predicates[property]; if (pnode) { for (var j=0; j < pnode.objects.length; j++) { values.push(pnode.objects[j].value); } } } return values; } }; export class RDFaPredicate { constructor(predicate) { this.id = predicate; this.predicate = predicate; this.objects = []; } toString(options) { var s = null; if (options && options.shorten && options.graph) { s = options.graph.shorten(this.predicate,options.prefixesUsed); if (!s) { s = "<" + this.predicate + ">" } } else { s = "<" + this.predicate + ">" } s += " "; for (var i=0; i < this.objects.length; i++) { if (i>0) { s += ", "; } if (this.objects[i].type == "http://www.w3.org/1999/02/22-rdf-syntax-ns#object") { if (this.objects[i].value.substring(0,2) == "_:") { if (options && options.filterBlankNode) { s += options.filterBlankNode(this.objects[i].value); } else { s += this.objects[i].value; } } else if (options && options.shorten && options.graph) { u = options.graph.shorten(this.objects[i].value,options.prefixesUsed); if (u) { s += u; } else { s += "<" + this.objects[i].value + ">"; } } else { s += "<" + this.objects[i].value + ">"; } } else if (this.objects[i].type=="http://www.w3.org/2001/XMLSchema#integer" || this.objects[i].type=="http://www.w3.org/2001/XMLSchema#decimal" || this.objects[i].type=="http://www.w3.org/2001/XMLSchema#double" || this.objects[i].type=="http://www.w3.org/2001/XMLSchema#boolean") { s += '"' + this.objects[i].value + '"' + "^^<" + this.objects[i].type + ">"; } else if (this.objects[i].type=="http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral") { var serializer = new XMLSerializer(); var value = ""; for (var x=0; x < this.objects[i].value.length; x++) { if (this.objects[i].value[x].nodeType==Node.ELEMENT_NODE) { var prefixMap = RDFaPredicate.getPrefixMap(this.objects[i].value[x]); var prefixes = []; for (var prefix in prefixMap) { prefixes.push(prefix); } prefixes.sort(); var e = this.objects[i].value[x].cloneNode(true); for (var p=0; p < prefixes.length; p++) { e.setAttributeNS("http://www.w3.org/2000/xmlns/",prefixes[p].length==0 ? "xmlns" : "xmlns:"+prefixes[p],prefixMap[prefixes[p]]); } value += serializer.serializeToString(e); } else if (this.objects[i].value[x].nodeType==Node.TEXT_NODE) { value += this.objects[i].value[x].nodeValue; } } s += '"""'+value.replace(/"""/g,"\\\"\\\"\\\"")+'"""^^<http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral>'; } else if (this.objects[i].type=="http://www.w3.org/1999/02/22-rdf-syntax-ns#HTML") { // We can use innerHTML as a shortcut from the parentNode if the list is not empty if (this.objects[i].value.length==0) { s += '""""""^^<http://www.w3.org/1999/02/22-rdf-syntax-ns#HTML>'; } else { s += '"""'+this.objects[i].value[0].parentNode.innerHTML.replace(/"""/g,"\\\"\\\"\\\"")+'"""^^<http://www.w3.org/1999/02/22-rdf-syntax-ns#HTML>'; } } else { var l = this.objects[i].value.toString(); if (l.indexOf("\n")>=0 || l.indexOf("\r")>=0) { s += '"""' + l.replace(/"""/g,"\\\"\\\"\\\"") + '"""'; } else { s += '"' + l.replace(/"/g,"\\\"") + '"'; } if (this.objects[i].type!="http://www.w3.org/1999/02/22-rdf-syntax-ns#PlainLiteral") { s += "^^<"+this.objects[i].type+">"; } else if (this.objects[i].language) { s += "@"+this.objects[i].language; } } } return s; } }; RDFaPredicate.getPrefixMap = function(e) { var prefixMap = {}; while (e.attributes) { for (var i=0; i < e.attributes.length; i++) { if (e.attributes[i].namespaceURI=="http://www.w3.org/2000/xmlns/") { var prefix = e.attributes[i].localName; if (e.attributes[i].localName=="xmlns") { prefix = ""; } if (!(prefix in prefixMap)) { prefixMap[prefix] = e.attributes[i].nodeValue; } } } e = e.parentNode; } return prefixMap; };