Update to latest jsonld.js.
authorDave Longley <dlongley@digitalbazaar.com>
Mon, 30 Apr 2012 14:10:38 -0400
changeset 598 d0b88ceef5ea
parent 597 dbbf020bb9b9
child 599 682fd66c2118
Update to latest jsonld.js.
playground/jsonld.js
--- a/playground/jsonld.js	Mon Apr 30 14:09:12 2012 -0400
+++ b/playground/jsonld.js	Mon Apr 30 14:10:38 2012 -0400
@@ -423,6 +423,8 @@
  *
  * @param input the JSON-LD input.
  * @param [options] the options to use:
+ *          [format] the format to use to output a string:
+ *            'text/x-nquads' for N-Quads (default).
  *          [resolver(url, callback(err, jsonCtx))] the URL resolver to use.
  * @param callback(err, statement) called when a statement is output, with the
  *          last statement as null.
@@ -436,7 +438,7 @@
     options = arguments[1] || {};
     callbackArg += 1;
   }
-  callback = arguments[callbackArg];
+  var cb = callback = arguments[callbackArg];
 
   // set default options
   if(!('base' in options)) {
@@ -446,6 +448,26 @@
     options.resolver = jsonld.urlResolver;
   }
 
+  if('format' in options) {
+    // supported formats
+    if(options.format === 'text/x-nquads') {
+      cb = function(err, statement) {
+        if(err) {
+          return callback(err);
+        }
+        if(statement !== null) {
+          statement = _toNQuad(statement);
+        }
+        callback(null, statement);
+      };
+    }
+    else {
+      throw new JsonLdError(
+        'Unknown output format.',
+        'jsonld.UnknownFormat', {format: options.format});
+    }
+  }
+
   // expand input
   jsonld.expand(input, options, function(err, expanded) {
     if(err) {
@@ -454,9 +476,15 @@
         'jsonld.RdfError', {cause: err}));
     }
 
-    // output RDF statements
-    var namer = new UniqueNamer('_:t');
-    new Processor().toRDF(expanded, namer, null, null, null, callback);
+    try {
+      // output RDF statements
+      var namer = new UniqueNamer('_:t');
+      new Processor().toRDF(expanded, namer, null, null, null, cb);
+      cb(null, null);
+    }
+    catch(ex) {
+      cb(ex);
+    }
   });
 };
 
@@ -1730,7 +1758,7 @@
 
     // get subject @id (generate one if it is a bnode)
     var isBnode = _isBlankNode(element);
-    var id = isBnode ? namer.getName(input['@id']) : input['@id'];
+    var id = isBnode ? namer.getName(element['@id']) : element['@id'];
 
     // create object
     var object = {
@@ -1757,11 +1785,11 @@
     // recurse over subject properties in order
     var props = Object.keys(element).sort();
     for(var pi in props) {
-      var prop = props[pi];
+      var prop = p = props[pi];
 
       // convert @type to rdf:type
       if(prop === '@type') {
-        prop = RDF_TYPE;
+        p = RDF_TYPE;
       }
 
       // recurse into @graph
@@ -1771,13 +1799,13 @@
       }
 
       // skip keywords
-      if(_isKeyword(prop)) {
+      if(_isKeyword(p)) {
         continue;
       }
 
       // create new active property
       property = {
-        nominalValue: id,
+        nominalValue: p,
         interfaceName: 'IRI'
       };
 
@@ -1789,13 +1817,14 @@
   }
 
   if(_isString(element)) {
-    // emit plain literal
+    // emit IRI for rdf:type, else plain literal
     var statement = {
       subject: _clone(subject),
       property: _clone(property),
       object: {
         nominalValue: element,
-        interfaceName: 'LiteralNode'
+        interfaceName: ((property.nominalValue === RDF_TYPE) ?
+          'IRI': 'LiteralNode')
       }
     };
     if(graph !== null) {
@@ -1810,16 +1839,16 @@
       var datatype = XSD_BOOLEAN;
       var value = String(element);
     }
-    else if(_isInteger(element)) {
+    else if(_isDouble(element)) {
+      var datatype = XSD_DOUBLE;
+      // printf('%1.15e') equivalent
+      var value = element.toExponential(15).replace(
+        /(e(?:\+|-))([0-9])$/, '$10$2');
+    }
+    else {
       var datatype = XSD_INTEGER;
       var value = String(element);
     }
-    else {
-      var datatype = XSD_DOUBLE;
-      // printf('%1.16e') equivalent
-      var value = element.toExponential(16).replace(
-        /(e(?:\+|-))([0-9])$/, '$10$2');
-    }
 
     // emit typed literal
     var statement = {
@@ -2034,8 +2063,8 @@
       }
       // convert double to @value
       else if(_isDouble(o)) {
-        // do special JSON-LD double format, printf('%1.16e') JS equivalent
-        o = o.toExponential(16).replace(/(e(?:\+|-))([0-9])$/, '$10$2');
+        // do special JSON-LD double format, printf('%1.15e') JS equivalent
+        o = o.toExponential(15).replace(/(e(?:\+|-))([0-9])$/, '$10$2');
         o = {'@value': o, '@type': XSD_DOUBLE};
       }
       // convert integer to @value
@@ -3394,7 +3423,7 @@
   }
 
   // prepend base
-  value = base + value;
+  value = _prependBase(base, value);
 
   // value must now be an absolute IRI
   if(!_isAbsoluteIri(value)) {
@@ -3461,13 +3490,31 @@
 
   // prepend base to term
   if(!_isUndefined(base)) {
-    term = base + term;
+    term = _prependBase(base, term);
   }
 
   return term;
 }
 
 /**
+ * Prepends a base IRI to the given relative IRI.
+ *
+ * @param base the base IRI.
+ * @param iri the relative IRI.
+ *
+ * @return the absolute IRI.
+ */
+function _prependBase(base, iri) {
+  if(iri === '' || iri.indexOf('#') === 0) {
+    return base + iri;
+  }
+  else {
+    // prepend last directory for base
+    return base.substr(0, base.lastIndexOf('/') + 1) + iri;
+  }
+}
+
+/**
  * Gets the initial context.
  *
  * @return the initial context.
@@ -4043,6 +4090,58 @@
 }
 
 /**
+ * Converts an RDF statement to an N-Quad string (a single quad).
+ *
+ * @param statement the RDF statement to convert.
+ *
+ * @return the N-Quad string.
+ */
+function _toNQuad(statement) {
+  var s = statement.subject;
+  var p = statement.property;
+  var o = statement.object;
+  var g = statement.name || null;
+
+  var quad = '';
+
+  // subject is an IRI or bnode
+  if(s.interfaceName === 'IRI') {
+    quad += '<' + s.nominalValue + '>';
+  }
+  else {
+    quad += s.nominalValue;
+  }
+
+  // property is always an IRI
+  quad += ' <' + p.nominalValue + '> ';
+
+  // object is IRI, bnode, or literal
+  if(o.interfaceName === 'IRI') {
+    quad += '<' + o.nominalValue + '>';
+  }
+  else if(o.interfaceName === 'BlankNode') {
+    quad += o.nominalValue;
+  }
+  else {
+    quad += '"' + o.nominalValue + '"';
+    if('datatype' in o) {
+      quad += '^^<' + o.datatype.nominalValue + '>';
+    }
+    else if('language' in o) {
+      quad += '@' + o.language;
+    }
+  }
+
+  // graph
+  if(g !== null) {
+    quad += ' <' + g.nominalValue + '>';
+  }
+
+  quad += ' .\n';
+  return quad;
+}
+
+/**
  * Creates a new UniqueNamer. A UniqueNamer issues unique names, keeping
  * track of any previously issued names.
  *