From aa845963e440341b850e794ccb4ed708314c3b62 Mon Sep 17 00:00:00 2001 From: Scott Blomquist Date: Tue, 24 Jun 2014 12:17:29 -0700 Subject: [PATCH] Clean up: whitespace, exception for PCL failures. --- src/JsonLD/Core/DocumentLoader.cs | 2 +- src/JsonLD/Core/IJSONLDTripleCallback.cs | 70 +- src/JsonLD/Core/IRDFParser.cs | 86 +- src/JsonLD/Core/JSONLDConsts.cs | 50 +- src/JsonLD/Core/JsonLdApi.cs | 4088 +++++++++++----------- src/JsonLD/Core/JsonLdError.cs | 272 +- src/JsonLD/Core/JsonLdOptions.cs | 264 +- src/JsonLD/Core/JsonLdProcessor.cs | 874 ++--- src/JsonLD/Core/JsonLdUtils.cs | 1896 +++++----- src/JsonLD/Core/NormalizeUtils.cs | 1140 +++--- src/JsonLD/Core/RDFDataset.cs | 1562 ++++----- src/JsonLD/Core/RDFDatasetUtils.cs | 1314 +++---- src/JsonLD/Core/Regex.cs | 112 +- src/JsonLD/Core/RemoteDocument.cs | 88 +- src/JsonLD/Core/UniqueNamer.cs | 128 +- src/JsonLD/Impl/NQuadRDFParser.cs | 32 +- src/JsonLD/Impl/NQuadTripleCallback.cs | 14 +- src/JsonLD/Impl/TurtleRDFParser.cs | 1380 ++++---- src/JsonLD/Impl/TurtleTripleCallback.cs | 830 ++--- src/JsonLD/Util/JSONUtils.cs | 202 +- src/JsonLD/Util/JavaCompat.cs | 2 +- src/JsonLD/Util/Obj.cs | 158 +- 22 files changed, 7292 insertions(+), 7272 deletions(-) diff --git a/src/JsonLD/Core/DocumentLoader.cs b/src/JsonLD/Core/DocumentLoader.cs index cd664b3..00cd652 100644 --- a/src/JsonLD/Core/DocumentLoader.cs +++ b/src/JsonLD/Core/DocumentLoader.cs @@ -60,7 +60,7 @@ public virtual RemoteDocument LoadDocument(string url) } return doc; #else - throw new NotImplementedException(); + throw new PlatformNotSupportedException(); #endif } diff --git a/src/JsonLD/Core/IJSONLDTripleCallback.cs b/src/JsonLD/Core/IJSONLDTripleCallback.cs index 4b580e5..06e3aab 100644 --- a/src/JsonLD/Core/IJSONLDTripleCallback.cs +++ b/src/JsonLD/Core/IJSONLDTripleCallback.cs @@ -3,39 +3,39 @@ namespace JsonLD.Core { - /// - /// Tristan - /// TODO: in the JSONLD RDF API the callback we're representing here is - /// QuadCallback which takes a list of quads (subject, predicat, object, - /// graph). for the moment i'm just going to use the dataset provided by - /// toRDF but this should probably change in the future - /// - public interface IJSONLDTripleCallback - { - /// Construct output based on internal RDF dataset format - /// - /// The format of the dataset is a Map with the following - /// structure: { GRAPH_1: [ TRIPLE_1, TRIPLE_2, ..., TRIPLE_N ], - /// GRAPH_2: [ TRIPLE_1, TRIPLE_2, ..., TRIPLE_N ], ... GRAPH_N: [ - /// TRIPLE_1, TRIPLE_2, ..., TRIPLE_N ] } - /// GRAPH: Is the graph name/IRI. if no graph is present for a - /// triple, it will be listed under the "@default" graph TRIPLE: - /// Is a map with the following structure: { "subject" : SUBJECT - /// "predicate" : PREDICATE "object" : OBJECT } - /// Each of the values in the triple map are also maps with the - /// following key-value pairs: "value" : The value of the node. - /// "subject" can be an IRI or blank node id. "predicate" should - /// only ever be an IRI "object" can be and IRI or blank node id, - /// or a literal value (represented as a string) "type" : "IRI" if - /// the value is an IRI or "blank node" if the value is a blank - /// node. "object" can also be "literal" in the case of literals. - /// The value of "object" can also contain the following optional - /// key-value pairs: "language" : the language value of a string - /// literal "datatype" : the datatype of the literal. (if not set - /// will default to XSD:string, if set to null, null will be - /// used). - /// - /// the resulting RDF object in the desired format - object Call(RDFDataset dataset); - } + /// + /// Tristan + /// TODO: in the JSONLD RDF API the callback we're representing here is + /// QuadCallback which takes a list of quads (subject, predicat, object, + /// graph). for the moment i'm just going to use the dataset provided by + /// toRDF but this should probably change in the future + /// + public interface IJSONLDTripleCallback + { + /// Construct output based on internal RDF dataset format + /// + /// The format of the dataset is a Map with the following + /// structure: { GRAPH_1: [ TRIPLE_1, TRIPLE_2, ..., TRIPLE_N ], + /// GRAPH_2: [ TRIPLE_1, TRIPLE_2, ..., TRIPLE_N ], ... GRAPH_N: [ + /// TRIPLE_1, TRIPLE_2, ..., TRIPLE_N ] } + /// GRAPH: Is the graph name/IRI. if no graph is present for a + /// triple, it will be listed under the "@default" graph TRIPLE: + /// Is a map with the following structure: { "subject" : SUBJECT + /// "predicate" : PREDICATE "object" : OBJECT } + /// Each of the values in the triple map are also maps with the + /// following key-value pairs: "value" : The value of the node. + /// "subject" can be an IRI or blank node id. "predicate" should + /// only ever be an IRI "object" can be and IRI or blank node id, + /// or a literal value (represented as a string) "type" : "IRI" if + /// the value is an IRI or "blank node" if the value is a blank + /// node. "object" can also be "literal" in the case of literals. + /// The value of "object" can also contain the following optional + /// key-value pairs: "language" : the language value of a string + /// literal "datatype" : the datatype of the literal. (if not set + /// will default to XSD:string, if set to null, null will be + /// used). + /// + /// the resulting RDF object in the desired format + object Call(RDFDataset dataset); + } } diff --git a/src/JsonLD/Core/IRDFParser.cs b/src/JsonLD/Core/IRDFParser.cs index b02fe5d..e0c0c68 100644 --- a/src/JsonLD/Core/IRDFParser.cs +++ b/src/JsonLD/Core/IRDFParser.cs @@ -3,47 +3,47 @@ namespace JsonLD.Core { - /// - /// Interface for parsing RDF into the RDF Dataset objects to be used by - /// JSONLD.fromRDF - /// - /// Tristan - public interface IRDFParser - { - /// - /// Parse the input into the internal RDF Dataset format The format is a Map - /// with the following structure: { GRAPH_1: [ TRIPLE_1, TRIPLE_2, ..., - /// TRIPLE_N ], GRAPH_2: [ TRIPLE_1, TRIPLE_2, ..., TRIPLE_N ], ... - /// - /// - /// Parse the input into the internal RDF Dataset format The format is a Map - /// with the following structure: { GRAPH_1: [ TRIPLE_1, TRIPLE_2, ..., - /// TRIPLE_N ], GRAPH_2: [ TRIPLE_1, TRIPLE_2, ..., TRIPLE_N ], ... GRAPH_N: - /// [ TRIPLE_1, TRIPLE_2, ..., TRIPLE_N ] } - /// GRAPH: Must be the graph name/IRI. if no graph is present for a triple, - /// add it to the "@default" graph TRIPLE: Must be a map with the following - /// structure: { "subject" : SUBJECT "predicate" : PREDICATE "object" : - /// OBJECT } - /// Each of the values in the triple map must also be a map with the - /// following key-value pairs: "value" : The value of the node. "subject" can - /// be an IRI or blank node id. "predicate" should only ever be an IRI - /// "object" can be and IRI or blank node id, or a literal value (represented - /// as a string) "type" : "IRI" if the value is an IRI or "blank node" if the - /// value is a blank node. "object" can also be "literal" in the case of - /// literals. The value of "object" can also contain the following optional - /// key-value pairs: "language" : the language value of a string literal - /// "datatype" : the datatype of the literal. (if not set will default to - /// XSD:string, if set to null, null will be used). - /// The RDFDatasetUtils class has the following helper methods to make - /// generating this format easier: result = getInitialRDFDatasetResult(); - /// triple = generateTriple(s,p,o); triple = - /// generateTriple(s,p,value,datatype,language); - /// addTripleToRDFDatasetResult(result, graphName, triple); - /// - /// The RDF library specific input to parse - /// input in internal RDF Dataset format - /// JsonLdError - /// - RDFDataset Parse(JToken input); - } + /// + /// Interface for parsing RDF into the RDF Dataset objects to be used by + /// JSONLD.fromRDF + /// + /// Tristan + public interface IRDFParser + { + /// + /// Parse the input into the internal RDF Dataset format The format is a Map + /// with the following structure: { GRAPH_1: [ TRIPLE_1, TRIPLE_2, ..., + /// TRIPLE_N ], GRAPH_2: [ TRIPLE_1, TRIPLE_2, ..., TRIPLE_N ], ... + /// + /// + /// Parse the input into the internal RDF Dataset format The format is a Map + /// with the following structure: { GRAPH_1: [ TRIPLE_1, TRIPLE_2, ..., + /// TRIPLE_N ], GRAPH_2: [ TRIPLE_1, TRIPLE_2, ..., TRIPLE_N ], ... GRAPH_N: + /// [ TRIPLE_1, TRIPLE_2, ..., TRIPLE_N ] } + /// GRAPH: Must be the graph name/IRI. if no graph is present for a triple, + /// add it to the "@default" graph TRIPLE: Must be a map with the following + /// structure: { "subject" : SUBJECT "predicate" : PREDICATE "object" : + /// OBJECT } + /// Each of the values in the triple map must also be a map with the + /// following key-value pairs: "value" : The value of the node. "subject" can + /// be an IRI or blank node id. "predicate" should only ever be an IRI + /// "object" can be and IRI or blank node id, or a literal value (represented + /// as a string) "type" : "IRI" if the value is an IRI or "blank node" if the + /// value is a blank node. "object" can also be "literal" in the case of + /// literals. The value of "object" can also contain the following optional + /// key-value pairs: "language" : the language value of a string literal + /// "datatype" : the datatype of the literal. (if not set will default to + /// XSD:string, if set to null, null will be used). + /// The RDFDatasetUtils class has the following helper methods to make + /// generating this format easier: result = getInitialRDFDatasetResult(); + /// triple = generateTriple(s,p,o); triple = + /// generateTriple(s,p,value,datatype,language); + /// addTripleToRDFDatasetResult(result, graphName, triple); + /// + /// The RDF library specific input to parse + /// input in internal RDF Dataset format + /// JsonLdError + /// + RDFDataset Parse(JToken input); + } } diff --git a/src/JsonLD/Core/JSONLDConsts.cs b/src/JsonLD/Core/JSONLDConsts.cs index 39f6839..916d885 100644 --- a/src/JsonLD/Core/JSONLDConsts.cs +++ b/src/JsonLD/Core/JSONLDConsts.cs @@ -2,48 +2,48 @@ namespace JsonLD.Core { - /// URI Constants used in the JSON-LD parser. - /// URI Constants used in the JSON-LD parser. - public sealed class JSONLDConsts - { - public const string RdfSyntaxNs = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; + /// URI Constants used in the JSON-LD parser. + /// URI Constants used in the JSON-LD parser. + public sealed class JSONLDConsts + { + public const string RdfSyntaxNs = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; - public const string RdfSchemaNs = "http://www.w3.org/2000/01/rdf-schema#"; + public const string RdfSchemaNs = "http://www.w3.org/2000/01/rdf-schema#"; - public const string XsdNs = "http://www.w3.org/2001/XMLSchema#"; + public const string XsdNs = "http://www.w3.org/2001/XMLSchema#"; - public const string XsdAnytype = XsdNs + "anyType"; + public const string XsdAnytype = XsdNs + "anyType"; - public const string XsdBoolean = XsdNs + "boolean"; + public const string XsdBoolean = XsdNs + "boolean"; - public const string XsdDouble = XsdNs + "double"; + public const string XsdDouble = XsdNs + "double"; - public const string XsdInteger = XsdNs + "integer"; + public const string XsdInteger = XsdNs + "integer"; - public const string XsdFloat = XsdNs + "float"; + public const string XsdFloat = XsdNs + "float"; - public const string XsdDecimal = XsdNs + "decimal"; + public const string XsdDecimal = XsdNs + "decimal"; - public const string XsdAnyuri = XsdNs + "anyURI"; + public const string XsdAnyuri = XsdNs + "anyURI"; - public const string XsdString = XsdNs + "string"; + public const string XsdString = XsdNs + "string"; - public const string RdfType = RdfSyntaxNs + "type"; + public const string RdfType = RdfSyntaxNs + "type"; - public const string RdfFirst = RdfSyntaxNs + "first"; + public const string RdfFirst = RdfSyntaxNs + "first"; - public const string RdfRest = RdfSyntaxNs + "rest"; + public const string RdfRest = RdfSyntaxNs + "rest"; - public const string RdfNil = RdfSyntaxNs + "nil"; + public const string RdfNil = RdfSyntaxNs + "nil"; - public const string RdfPlainLiteral = RdfSyntaxNs + "PlainLiteral"; + public const string RdfPlainLiteral = RdfSyntaxNs + "PlainLiteral"; - public const string RdfXmlLiteral = RdfSyntaxNs + "XMLLiteral"; + public const string RdfXmlLiteral = RdfSyntaxNs + "XMLLiteral"; - public const string RdfObject = RdfSyntaxNs + "object"; + public const string RdfObject = RdfSyntaxNs + "object"; - public const string RdfLangstring = RdfSyntaxNs + "langString"; + public const string RdfLangstring = RdfSyntaxNs + "langString"; - public const string RdfList = RdfSyntaxNs + "List"; - } + public const string RdfList = RdfSyntaxNs + "List"; + } } diff --git a/src/JsonLD/Core/JsonLdApi.cs b/src/JsonLD/Core/JsonLdApi.cs index af3e0d6..065e952 100644 --- a/src/JsonLD/Core/JsonLdApi.cs +++ b/src/JsonLD/Core/JsonLdApi.cs @@ -3,1797 +3,1798 @@ using JsonLD.Core; using JsonLD.Util; using Newtonsoft.Json.Linq; +using System; namespace JsonLD.Core { - public class JsonLdApi - { - //private static readonly ILogger Log = LoggerFactory.GetLogger(typeof(JsonLDNet.Core.JsonLdApi)); + public class JsonLdApi + { + //private static readonly ILogger Log = LoggerFactory.GetLogger(typeof(JsonLDNet.Core.JsonLdApi)); - internal JsonLdOptions opts; + internal JsonLdOptions opts; internal JToken value = null; - internal Context context = null; + internal Context context = null; - public JsonLdApi() - { - opts = new JsonLdOptions(string.Empty); - } + public JsonLdApi() + { + opts = new JsonLdOptions(string.Empty); + } - /// + /// public JsonLdApi(JToken input, JsonLdOptions opts) - { - Initialize(input, null, opts); - } + { + Initialize(input, null, opts); + } - /// + /// public JsonLdApi(JToken input, JToken context, JsonLdOptions opts) - { - Initialize(input, null, opts); - } + { + Initialize(input, null, opts); + } - public JsonLdApi(JsonLdOptions opts) - { - if (opts == null) - { - opts = new JsonLdOptions(string.Empty); - } - else - { - this.opts = opts; - } - } + public JsonLdApi(JsonLdOptions opts) + { + if (opts == null) + { + opts = new JsonLdOptions(string.Empty); + } + else + { + this.opts = opts; + } + } - /// + /// private void Initialize(JToken input, JToken context, JsonLdOptions opts) - { - // set option defaults (TODO: clone?) - // NOTE: sane defaults should be set in JsonLdOptions constructor - this.opts = opts; - if (input is JArray || input is JObject) - { - this.value = JsonLdUtils.Clone(input); - } - // TODO: string/IO input - this.context = new Context(opts); - if (!context.IsNull()) - { - this.context = this.context.Parse(context); - } - } + { + // set option defaults (TODO: clone?) + // NOTE: sane defaults should be set in JsonLdOptions constructor + this.opts = opts; + if (input is JArray || input is JObject) + { + this.value = JsonLdUtils.Clone(input); + } + // TODO: string/IO input + this.context = new Context(opts); + if (!context.IsNull()) + { + this.context = this.context.Parse(context); + } + } - /// - /// Compaction Algorithm - /// http://json-ld.org/spec/latest/json-ld-api/#compaction-algorithm - /// - /// - /// - /// - /// - /// - /// - public virtual JToken Compact(Context activeCtx, string activeProperty, JToken element - , bool compactArrays) - { - // 2) - if (element is JArray) - { - // 2.1) - JArray result = new JArray(); - // 2.2) - foreach (JToken item in element) - { - // 2.2.1) - JToken compactedItem = Compact(activeCtx, activeProperty, item, compactArrays); - // 2.2.2) - if (!compactedItem.IsNull()) - { - result.Add(compactedItem); - } - } - // 2.3) - if (compactArrays && result.Count == 1 && activeCtx.GetContainer(activeProperty) - == null) - { - return result[0]; - } - // 2.4) - return result; - } - // 3) - if (element is JObject) - { - // access helper + /// + /// Compaction Algorithm + /// http://json-ld.org/spec/latest/json-ld-api/#compaction-algorithm + /// + /// + /// + /// + /// + /// + /// + public virtual JToken Compact(Context activeCtx, string activeProperty, JToken element + , bool compactArrays) + { + // 2) + if (element is JArray) + { + // 2.1) + JArray result = new JArray(); + // 2.2) + foreach (JToken item in element) + { + // 2.2.1) + JToken compactedItem = Compact(activeCtx, activeProperty, item, compactArrays); + // 2.2.2) + if (!compactedItem.IsNull()) + { + result.Add(compactedItem); + } + } + // 2.3) + if (compactArrays && result.Count == 1 && activeCtx.GetContainer(activeProperty) + == null) + { + return result[0]; + } + // 2.4) + return result; + } + // 3) + if (element is JObject) + { + // access helper IDictionary elem = (IDictionary)element; - // 4 - if (elem.ContainsKey("@value") || elem.ContainsKey("@id")) - { - JToken compactedValue = activeCtx.CompactValue(activeProperty, (JObject)element); - if (!(compactedValue is JObject || compactedValue is JArray)) - { - return compactedValue; - } - } - // 5) - bool insideReverse = ("@reverse".Equals(activeProperty)); - // 6) - JObject result = new JObject(); - // 7) + // 4 + if (elem.ContainsKey("@value") || elem.ContainsKey("@id")) + { + JToken compactedValue = activeCtx.CompactValue(activeProperty, (JObject)element); + if (!(compactedValue is JObject || compactedValue is JArray)) + { + return compactedValue; + } + } + // 5) + bool insideReverse = ("@reverse".Equals(activeProperty)); + // 6) + JObject result = new JObject(); + // 7) JArray keys = new JArray(element.GetKeys()); - keys.SortInPlace(); - foreach (string expandedProperty in keys) - { - JToken expandedValue = elem[expandedProperty]; - // 7.1) - if ("@id".Equals(expandedProperty) || "@type".Equals(expandedProperty)) - { - JToken compactedValue; - // 7.1.1) - if (expandedValue.Type == JTokenType.String) - { - compactedValue = activeCtx.CompactIri((string)expandedValue, "@type".Equals(expandedProperty - )); - } - else - { - // 7.1.2) + keys.SortInPlace(); + foreach (string expandedProperty in keys) + { + JToken expandedValue = elem[expandedProperty]; + // 7.1) + if ("@id".Equals(expandedProperty) || "@type".Equals(expandedProperty)) + { + JToken compactedValue; + // 7.1.1) + if (expandedValue.Type == JTokenType.String) + { + compactedValue = activeCtx.CompactIri((string)expandedValue, "@type".Equals(expandedProperty + )); + } + else + { + // 7.1.2) JArray types = new JArray(); - // 7.1.2.2) - foreach (string expandedType in (JArray)expandedValue) - { - types.Add(activeCtx.CompactIri(expandedType, true)); - } - // 7.1.2.3) - if (types.Count == 1) - { - compactedValue = types[0]; - } - else - { - compactedValue = types; - } - } - // 7.1.3) - string alias = activeCtx.CompactIri(expandedProperty, true); - // 7.1.4) - result[alias] = compactedValue; - continue; - } - // TODO: old add value code, see if it's still relevant? - // addValue(rval, alias, compactedValue, - // isArray(compactedValue) - // && ((List) expandedValue).size() == 0); - // 7.2) - if ("@reverse".Equals(expandedProperty)) - { - // 7.2.1) - JObject compactedValue = (JObject)Compact(activeCtx, "@reverse", expandedValue, compactArrays); - // 7.2.2) + // 7.1.2.2) + foreach (string expandedType in (JArray)expandedValue) + { + types.Add(activeCtx.CompactIri(expandedType, true)); + } + // 7.1.2.3) + if (types.Count == 1) + { + compactedValue = types[0]; + } + else + { + compactedValue = types; + } + } + // 7.1.3) + string alias = activeCtx.CompactIri(expandedProperty, true); + // 7.1.4) + result[alias] = compactedValue; + continue; + } + // TODO: old add value code, see if it's still relevant? + // addValue(rval, alias, compactedValue, + // isArray(compactedValue) + // && ((List) expandedValue).size() == 0); + // 7.2) + if ("@reverse".Equals(expandedProperty)) + { + // 7.2.1) + JObject compactedValue = (JObject)Compact(activeCtx, "@reverse", expandedValue, compactArrays); + // 7.2.2) List properties = new List(compactedValue.GetKeys()); - foreach (string property in properties) - { - JToken value = compactedValue[property]; - // 7.2.2.1) - if (activeCtx.IsReverseProperty(property)) - { - // 7.2.2.1.1) - if (("@set".Equals(activeCtx.GetContainer(property)) || !compactArrays) && !(value - is JArray)) - { - JArray tmp = new JArray(); - tmp.Add(value); - result[property] = tmp; - } - // 7.2.2.1.2) - if (!result.ContainsKey(property)) - { - result[property] = value; - } - else - { - // 7.2.2.1.3) - if (!(result[property] is JArray)) - { + foreach (string property in properties) + { + JToken value = compactedValue[property]; + // 7.2.2.1) + if (activeCtx.IsReverseProperty(property)) + { + // 7.2.2.1.1) + if (("@set".Equals(activeCtx.GetContainer(property)) || !compactArrays) && !(value + is JArray)) + { + JArray tmp = new JArray(); + tmp.Add(value); + result[property] = tmp; + } + // 7.2.2.1.2) + if (!result.ContainsKey(property)) + { + result[property] = value; + } + else + { + // 7.2.2.1.3) + if (!(result[property] is JArray)) + { JArray tmp = new JArray(); tmp.Add(result[property]); - result[property] = tmp; - } - if (value is JArray) - { - JsonLD.Collections.AddAll(((JArray)result[property]), (JArray)value - ); - } - else - { - ((JArray)result[property]).Add(value); - } - } - // 7.2.2.1.4) TODO: this doesn't seem safe (i.e. - // modifying the map being used to drive the loop)! - JsonLD.Collections.Remove(compactedValue, property); - } - } - // 7.2.3) - if (compactedValue.Count != 0) - { - // 7.2.3.1) - string alias = activeCtx.CompactIri("@reverse", true); - // 7.2.3.2) - result[alias] = compactedValue; - } - // 7.2.4) - continue; - } - // 7.3) - if ("@index".Equals(expandedProperty) && "@index".Equals(activeCtx.GetContainer(activeProperty - ))) - { - continue; - } - else - { - // 7.4) - if ("@index".Equals(expandedProperty) || "@value".Equals(expandedProperty) || "@language" - .Equals(expandedProperty)) - { - // 7.4.1) - string alias = activeCtx.CompactIri(expandedProperty, true); - // 7.4.2) - result[alias] = expandedValue; - continue; - } - } - // NOTE: expanded value must be an array due to expansion - // algorithm. - // 7.5) - if (((JArray)expandedValue).Count == 0) - { - // 7.5.1) - string itemActiveProperty = activeCtx.CompactIri(expandedProperty, expandedValue, - true, insideReverse); - // 7.5.2) - if (!result.ContainsKey(itemActiveProperty)) - { - result[itemActiveProperty] = new JArray(); - } - else - { - JToken value = result[itemActiveProperty]; - if (!(value is JArray)) - { - JArray tmp = new JArray(); - tmp.Add(value); - result[itemActiveProperty] = tmp; - } - } - } - // 7.6) - foreach (JToken expandedItem in (JArray)expandedValue) - { - // 7.6.1) - string itemActiveProperty = activeCtx.CompactIri(expandedProperty, expandedItem, - true, insideReverse); - // 7.6.2) - string container = activeCtx.GetContainer(itemActiveProperty); - // get @list value if appropriate - bool isList = (expandedItem is JObject && ((IDictionary)expandedItem - ).ContainsKey("@list")); - JToken list = null; - if (isList) - { - list = ((IDictionary)expandedItem)["@list"]; - } - // 7.6.3) - JToken compactedItem = Compact(activeCtx, itemActiveProperty, isList ? list : expandedItem - , compactArrays); - // 7.6.4) - if (isList) - { - // 7.6.4.1) - if (!(compactedItem is JArray)) - { - JArray tmp = new JArray(); - tmp.Add(compactedItem); - compactedItem = tmp; - } - // 7.6.4.2) - if (!"@list".Equals(container)) - { - // 7.6.4.2.1) - JObject wrapper = new JObject(); - // TODO: SPEC: no mention of vocab = true - wrapper[activeCtx.CompactIri("@list", true)] = compactedItem; - compactedItem = wrapper; - // 7.6.4.2.2) - if (((IDictionary)expandedItem).ContainsKey("@index")) - { - ((IDictionary)compactedItem)[activeCtx.CompactIri("@index", true) - ] = ((IDictionary)expandedItem)["@index"]; - } - } - else - { - // TODO: SPEC: no mention of vocab = - // true - // 7.6.4.3) - if (result.ContainsKey(itemActiveProperty)) - { - throw new JsonLdError(JsonLdError.Error.CompactionToListOfLists, "There cannot be two list objects associated with an active property that has a container mapping" - ); - } - } - } - // 7.6.5) - if ("@language".Equals(container) || "@index".Equals(container)) - { - // 7.6.5.1) - JObject mapObject; - if (result.ContainsKey(itemActiveProperty)) - { - mapObject = (JObject)result[itemActiveProperty]; - } - else - { - mapObject = new JObject(); - result[itemActiveProperty] = mapObject; - } - // 7.6.5.2) - if ("@language".Equals(container) && (compactedItem is JObject && ((IDictionary - )compactedItem).ContainsKey("@value"))) - { - compactedItem = compactedItem["@value"]; - } - // 7.6.5.3) - string mapKey = (string)expandedItem[container]; - // 7.6.5.4) - if (!mapObject.ContainsKey(mapKey)) - { - mapObject[mapKey] = compactedItem; - } - else - { - JArray tmp; - if (!(mapObject[mapKey] is JArray)) - { - tmp = new JArray(); + result[property] = tmp; + } + if (value is JArray) + { + JsonLD.Collections.AddAll(((JArray)result[property]), (JArray)value + ); + } + else + { + ((JArray)result[property]).Add(value); + } + } + // 7.2.2.1.4) TODO: this doesn't seem safe (i.e. + // modifying the map being used to drive the loop)! + JsonLD.Collections.Remove(compactedValue, property); + } + } + // 7.2.3) + if (compactedValue.Count != 0) + { + // 7.2.3.1) + string alias = activeCtx.CompactIri("@reverse", true); + // 7.2.3.2) + result[alias] = compactedValue; + } + // 7.2.4) + continue; + } + // 7.3) + if ("@index".Equals(expandedProperty) && "@index".Equals(activeCtx.GetContainer(activeProperty + ))) + { + continue; + } + else + { + // 7.4) + if ("@index".Equals(expandedProperty) || "@value".Equals(expandedProperty) || "@language" + .Equals(expandedProperty)) + { + // 7.4.1) + string alias = activeCtx.CompactIri(expandedProperty, true); + // 7.4.2) + result[alias] = expandedValue; + continue; + } + } + // NOTE: expanded value must be an array due to expansion + // algorithm. + // 7.5) + if (((JArray)expandedValue).Count == 0) + { + // 7.5.1) + string itemActiveProperty = activeCtx.CompactIri(expandedProperty, expandedValue, + true, insideReverse); + // 7.5.2) + if (!result.ContainsKey(itemActiveProperty)) + { + result[itemActiveProperty] = new JArray(); + } + else + { + JToken value = result[itemActiveProperty]; + if (!(value is JArray)) + { + JArray tmp = new JArray(); + tmp.Add(value); + result[itemActiveProperty] = tmp; + } + } + } + // 7.6) + foreach (JToken expandedItem in (JArray)expandedValue) + { + // 7.6.1) + string itemActiveProperty = activeCtx.CompactIri(expandedProperty, expandedItem, + true, insideReverse); + // 7.6.2) + string container = activeCtx.GetContainer(itemActiveProperty); + // get @list value if appropriate + bool isList = (expandedItem is JObject && ((IDictionary)expandedItem + ).ContainsKey("@list")); + JToken list = null; + if (isList) + { + list = ((IDictionary)expandedItem)["@list"]; + } + // 7.6.3) + JToken compactedItem = Compact(activeCtx, itemActiveProperty, isList ? list : expandedItem + , compactArrays); + // 7.6.4) + if (isList) + { + // 7.6.4.1) + if (!(compactedItem is JArray)) + { + JArray tmp = new JArray(); + tmp.Add(compactedItem); + compactedItem = tmp; + } + // 7.6.4.2) + if (!"@list".Equals(container)) + { + // 7.6.4.2.1) + JObject wrapper = new JObject(); + // TODO: SPEC: no mention of vocab = true + wrapper[activeCtx.CompactIri("@list", true)] = compactedItem; + compactedItem = wrapper; + // 7.6.4.2.2) + if (((IDictionary)expandedItem).ContainsKey("@index")) + { + ((IDictionary)compactedItem)[activeCtx.CompactIri("@index", true) + ] = ((IDictionary)expandedItem)["@index"]; + } + } + else + { + // TODO: SPEC: no mention of vocab = + // true + // 7.6.4.3) + if (result.ContainsKey(itemActiveProperty)) + { + throw new JsonLdError(JsonLdError.Error.CompactionToListOfLists, "There cannot be two list objects associated with an active property that has a container mapping" + ); + } + } + } + // 7.6.5) + if ("@language".Equals(container) || "@index".Equals(container)) + { + // 7.6.5.1) + JObject mapObject; + if (result.ContainsKey(itemActiveProperty)) + { + mapObject = (JObject)result[itemActiveProperty]; + } + else + { + mapObject = new JObject(); + result[itemActiveProperty] = mapObject; + } + // 7.6.5.2) + if ("@language".Equals(container) && (compactedItem is JObject && ((IDictionary + )compactedItem).ContainsKey("@value"))) + { + compactedItem = compactedItem["@value"]; + } + // 7.6.5.3) + string mapKey = (string)expandedItem[container]; + // 7.6.5.4) + if (!mapObject.ContainsKey(mapKey)) + { + mapObject[mapKey] = compactedItem; + } + else + { + JArray tmp; + if (!(mapObject[mapKey] is JArray)) + { + tmp = new JArray(); tmp.Add(mapObject[mapKey]); mapObject[mapKey] = tmp; - } - else - { - tmp = (JArray)mapObject[mapKey]; - } - tmp.Add(compactedItem); - } - } - else - { - // 7.6.6) - // 7.6.6.1) - bool check = (!compactArrays || "@set".Equals(container) || "@list".Equals(container - ) || "@list".Equals(expandedProperty) || "@graph".Equals(expandedProperty)) && ( - !(compactedItem is JArray)); - if (check) - { - JArray tmp = new JArray(); - tmp.Add(compactedItem); - compactedItem = tmp; - } - // 7.6.6.2) - if (!result.ContainsKey(itemActiveProperty)) - { - result[itemActiveProperty] = compactedItem; - } - else - { + } + else + { + tmp = (JArray)mapObject[mapKey]; + } + tmp.Add(compactedItem); + } + } + else + { + // 7.6.6) + // 7.6.6.1) + bool check = (!compactArrays || "@set".Equals(container) || "@list".Equals(container + ) || "@list".Equals(expandedProperty) || "@graph".Equals(expandedProperty)) && ( + !(compactedItem is JArray)); + if (check) + { + JArray tmp = new JArray(); + tmp.Add(compactedItem); + compactedItem = tmp; + } + // 7.6.6.2) + if (!result.ContainsKey(itemActiveProperty)) + { + result[itemActiveProperty] = compactedItem; + } + else + { if (!(result[itemActiveProperty] is JArray)) - { + { JArray tmp = new JArray(); - tmp.Add(result[itemActiveProperty]); + tmp.Add(result[itemActiveProperty]); result[itemActiveProperty] = tmp; - } + } if (compactedItem is JArray) - { + { JsonLD.Collections.AddAll(((JArray)result[itemActiveProperty]), (JArray)compactedItem); - } - else - { + } + else + { ((JArray)result[itemActiveProperty]).Add(compactedItem); - } - } - } - } - } - // 8) - return result; - } - // 2) - return element; - } + } + } + } + } + } + // 8) + return result; + } + // 2) + return element; + } - /// - public virtual JToken Compact(Context activeCtx, string activeProperty, JToken element - ) - { - return Compact(activeCtx, activeProperty, element, true); - } + /// + public virtual JToken Compact(Context activeCtx, string activeProperty, JToken element + ) + { + return Compact(activeCtx, activeProperty, element, true); + } - /// - /// Expansion Algorithm - /// http://json-ld.org/spec/latest/json-ld-api/#expansion-algorithm - /// - /// - /// - /// - /// - /// JsonLdError - /// - public virtual JToken Expand(Context activeCtx, string activeProperty, JToken element - ) - { - // 1) - if (element.IsNull()) - { - return null; - } - // 3) - if (element is JArray) - { - // 3.1) + /// + /// Expansion Algorithm + /// http://json-ld.org/spec/latest/json-ld-api/#expansion-algorithm + /// + /// + /// + /// + /// + /// JsonLdError + /// + public virtual JToken Expand(Context activeCtx, string activeProperty, JToken element + ) + { + // 1) + if (element.IsNull()) + { + return null; + } + // 3) + if (element is JArray) + { + // 3.1) JArray result = new JArray(); - // 3.2) + // 3.2) foreach (JToken item in (JArray)element) - { - // 3.2.1) - JToken v = Expand(activeCtx, activeProperty, item); - // 3.2.2) - if (("@list".Equals(activeProperty) || "@list".Equals(activeCtx.GetContainer(activeProperty - ))) && (v is JArray || (v is JObject && ((IDictionary)v).ContainsKey - ("@list")))) - { - throw new JsonLdError(JsonLdError.Error.ListOfLists, "lists of lists are not permitted." - ); - } - else - { - // 3.2.3) - if (!v.IsNull()) - { - if (v is JArray) - { - JsonLD.Collections.AddAll(result, (JArray)v); - } - else - { - result.Add(v); - } - } - } - } - // 3.3) - return result; - } - else - { - // 4) - if (element is JObject) - { - // access helper + { + // 3.2.1) + JToken v = Expand(activeCtx, activeProperty, item); + // 3.2.2) + if (("@list".Equals(activeProperty) || "@list".Equals(activeCtx.GetContainer(activeProperty + ))) && (v is JArray || (v is JObject && ((IDictionary)v).ContainsKey + ("@list")))) + { + throw new JsonLdError(JsonLdError.Error.ListOfLists, "lists of lists are not permitted." + ); + } + else + { + // 3.2.3) + if (!v.IsNull()) + { + if (v is JArray) + { + JsonLD.Collections.AddAll(result, (JArray)v); + } + else + { + result.Add(v); + } + } + } + } + // 3.3) + return result; + } + else + { + // 4) + if (element is JObject) + { + // access helper IDictionary elem = (JObject)element; - // 5) - if (elem.ContainsKey("@context")) - { - activeCtx = activeCtx.Parse(elem["@context"]); - } - // 6) + // 5) + if (elem.ContainsKey("@context")) + { + activeCtx = activeCtx.Parse(elem["@context"]); + } + // 6) JObject result = new JObject(); - // 7) + // 7) JArray keys = new JArray(element.GetKeys()); - keys.SortInPlace(); - foreach (string key in keys) - { - JToken value = elem[key]; - // 7.1) - if (key.Equals("@context")) - { - continue; - } - // 7.2) - string expandedProperty = activeCtx.ExpandIri(key, false, true, null, null); + keys.SortInPlace(); + foreach (string key in keys) + { + JToken value = elem[key]; + // 7.1) + if (key.Equals("@context")) + { + continue; + } + // 7.2) + string expandedProperty = activeCtx.ExpandIri(key, false, true, null, null); JToken expandedValue = null; - // 7.3) - if (expandedProperty == null || (!expandedProperty.Contains(":") && !JsonLdUtils.IsKeyword - (expandedProperty))) - { - continue; - } - // 7.4) - if (JsonLdUtils.IsKeyword(expandedProperty)) - { - // 7.4.1) - if ("@reverse".Equals(activeProperty)) - { - throw new JsonLdError(JsonLdError.Error.InvalidReversePropertyMap, "a keyword cannot be used as a @reverse propery" - ); - } - // 7.4.2) - if (result.ContainsKey(expandedProperty)) - { - throw new JsonLdError(JsonLdError.Error.CollidingKeywords, expandedProperty + " already exists in result" - ); - } - // 7.4.3) - if ("@id".Equals(expandedProperty)) - { - if (!(value.Type == JTokenType.String)) - { - throw new JsonLdError(JsonLdError.Error.InvalidIdValue, "value of @id must be a string" - ); - } - expandedValue = activeCtx.ExpandIri((string)value, true, false, null, null); - } - else - { - // 7.4.4) - if ("@type".Equals(expandedProperty)) - { + // 7.3) + if (expandedProperty == null || (!expandedProperty.Contains(":") && !JsonLdUtils.IsKeyword + (expandedProperty))) + { + continue; + } + // 7.4) + if (JsonLdUtils.IsKeyword(expandedProperty)) + { + // 7.4.1) + if ("@reverse".Equals(activeProperty)) + { + throw new JsonLdError(JsonLdError.Error.InvalidReversePropertyMap, "a keyword cannot be used as a @reverse propery" + ); + } + // 7.4.2) + if (result.ContainsKey(expandedProperty)) + { + throw new JsonLdError(JsonLdError.Error.CollidingKeywords, expandedProperty + " already exists in result" + ); + } + // 7.4.3) + if ("@id".Equals(expandedProperty)) + { + if (!(value.Type == JTokenType.String)) + { + throw new JsonLdError(JsonLdError.Error.InvalidIdValue, "value of @id must be a string" + ); + } + expandedValue = activeCtx.ExpandIri((string)value, true, false, null, null); + } + else + { + // 7.4.4) + if ("@type".Equals(expandedProperty)) + { if (value is JArray) - { - expandedValue = new JArray(); - foreach (JToken v in (JArray)value) - { - if (v.Type != JTokenType.String) - { - throw new JsonLdError(JsonLdError.Error.InvalidTypeValue, "@type value must be a string or array of strings" - ); - } - ((JArray)expandedValue).Add(activeCtx.ExpandIri((string)v, true, true, null - , null)); - } - } - else - { - if (value.Type == JTokenType.String) - { - expandedValue = activeCtx.ExpandIri((string)value, true, true, null, null); - } - else - { - // TODO: SPEC: no mention of empty map check - if (value is JObject) - { - if (((JObject)value).Count != 0) - { - throw new JsonLdError(JsonLdError.Error.InvalidTypeValue, "@type value must be a an empty object for framing" - ); - } - expandedValue = value; - } - else - { - throw new JsonLdError(JsonLdError.Error.InvalidTypeValue, "@type value must be a string or array of strings" - ); - } - } - } - } - else - { - // 7.4.5) - if ("@graph".Equals(expandedProperty)) - { - expandedValue = Expand(activeCtx, "@graph", value); - } - else - { - // 7.4.6) - if ("@value".Equals(expandedProperty)) - { - if (!value.IsNull() && (value is JObject || value is JArray)) - { - throw new JsonLdError(JsonLdError.Error.InvalidValueObjectValue, "value of " + expandedProperty - + " must be a scalar or null"); - } - expandedValue = value; - if (expandedValue.IsNull()) - { - result["@value"] = null; - continue; - } - } - else - { - // 7.4.7) - if ("@language".Equals(expandedProperty)) - { - if (!(value.Type == JTokenType.String)) - { - throw new JsonLdError(JsonLdError.Error.InvalidLanguageTaggedString, "Value of " - + expandedProperty + " must be a string"); - } - expandedValue = ((string)value).ToLower(); - } - else - { - // 7.4.8) - if ("@index".Equals(expandedProperty)) - { - if (!(value.Type == JTokenType.String)) - { - throw new JsonLdError(JsonLdError.Error.InvalidIndexValue, "Value of " + expandedProperty - + " must be a string"); - } - expandedValue = value; - } - else - { - // 7.4.9) - if ("@list".Equals(expandedProperty)) - { - // 7.4.9.1) - if (activeProperty == null || "@graph".Equals(activeProperty)) - { - continue; - } - // 7.4.9.2) - expandedValue = Expand(activeCtx, activeProperty, value); - // NOTE: step not in the spec yet + { + expandedValue = new JArray(); + foreach (JToken v in (JArray)value) + { + if (v.Type != JTokenType.String) + { + throw new JsonLdError(JsonLdError.Error.InvalidTypeValue, "@type value must be a string or array of strings" + ); + } + ((JArray)expandedValue).Add(activeCtx.ExpandIri((string)v, true, true, null + , null)); + } + } + else + { + if (value.Type == JTokenType.String) + { + expandedValue = activeCtx.ExpandIri((string)value, true, true, null, null); + } + else + { + // TODO: SPEC: no mention of empty map check + if (value is JObject) + { + if (((JObject)value).Count != 0) + { + throw new JsonLdError(JsonLdError.Error.InvalidTypeValue, "@type value must be a an empty object for framing" + ); + } + expandedValue = value; + } + else + { + throw new JsonLdError(JsonLdError.Error.InvalidTypeValue, "@type value must be a string or array of strings" + ); + } + } + } + } + else + { + // 7.4.5) + if ("@graph".Equals(expandedProperty)) + { + expandedValue = Expand(activeCtx, "@graph", value); + } + else + { + // 7.4.6) + if ("@value".Equals(expandedProperty)) + { + if (!value.IsNull() && (value is JObject || value is JArray)) + { + throw new JsonLdError(JsonLdError.Error.InvalidValueObjectValue, "value of " + expandedProperty + + " must be a scalar or null"); + } + expandedValue = value; + if (expandedValue.IsNull()) + { + result["@value"] = null; + continue; + } + } + else + { + // 7.4.7) + if ("@language".Equals(expandedProperty)) + { + if (!(value.Type == JTokenType.String)) + { + throw new JsonLdError(JsonLdError.Error.InvalidLanguageTaggedString, "Value of " + + expandedProperty + " must be a string"); + } + expandedValue = ((string)value).ToLower(); + } + else + { + // 7.4.8) + if ("@index".Equals(expandedProperty)) + { + if (!(value.Type == JTokenType.String)) + { + throw new JsonLdError(JsonLdError.Error.InvalidIndexValue, "Value of " + expandedProperty + + " must be a string"); + } + expandedValue = value; + } + else + { + // 7.4.9) + if ("@list".Equals(expandedProperty)) + { + // 7.4.9.1) + if (activeProperty == null || "@graph".Equals(activeProperty)) + { + continue; + } + // 7.4.9.2) + expandedValue = Expand(activeCtx, activeProperty, value); + // NOTE: step not in the spec yet if (!(expandedValue is JArray)) - { + { JArray tmp = new JArray(); - tmp.Add(expandedValue); - expandedValue = tmp; - } - // 7.4.9.3) + tmp.Add(expandedValue); + expandedValue = tmp; + } + // 7.4.9.3) foreach (JToken o in (JArray)expandedValue) - { + { if (o is JObject && ((JObject)o).ContainsKey("@list")) - { - throw new JsonLdError(JsonLdError.Error.ListOfLists, "A list may not contain another list" - ); - } - } - } - else - { - // 7.4.10) - if ("@set".Equals(expandedProperty)) - { - expandedValue = Expand(activeCtx, activeProperty, value); - } - else - { - // 7.4.11) - if ("@reverse".Equals(expandedProperty)) - { - if (!(value is JObject)) - { - throw new JsonLdError(JsonLdError.Error.InvalidReverseValue, "@reverse value must be an object" - ); - } - // 7.4.11.1) - expandedValue = Expand(activeCtx, "@reverse", value); - // NOTE: algorithm assumes the result is a map - // 7.4.11.2) + { + throw new JsonLdError(JsonLdError.Error.ListOfLists, "A list may not contain another list" + ); + } + } + } + else + { + // 7.4.10) + if ("@set".Equals(expandedProperty)) + { + expandedValue = Expand(activeCtx, activeProperty, value); + } + else + { + // 7.4.11) + if ("@reverse".Equals(expandedProperty)) + { + if (!(value is JObject)) + { + throw new JsonLdError(JsonLdError.Error.InvalidReverseValue, "@reverse value must be an object" + ); + } + // 7.4.11.1) + expandedValue = Expand(activeCtx, "@reverse", value); + // NOTE: algorithm assumes the result is a map + // 7.4.11.2) if (((IDictionary)expandedValue).ContainsKey("@reverse")) - { + { JObject reverse = (JObject)((JObject)expandedValue)["@reverse"]; - foreach (string property in reverse.GetKeys()) - { + foreach (string property in reverse.GetKeys()) + { JToken item = reverse[property]; - // 7.4.11.2.1) - if (!result.ContainsKey(property)) - { - result[property] = new JArray(); - } - // 7.4.11.2.2) - if (item is JArray) - { + // 7.4.11.2.1) + if (!result.ContainsKey(property)) + { + result[property] = new JArray(); + } + // 7.4.11.2.2) + if (item is JArray) + { JsonLD.Collections.AddAll(((JArray)result[property]), (JArray)item); - } - else - { + } + else + { ((JArray)result[property]).Add(item); - } - } - } - // 7.4.11.3) + } + } + } + // 7.4.11.3) if (((JObject)expandedValue).Count > (((JObject)expandedValue).ContainsKey("@reverse") ? 1 : 0)) - { - // 7.4.11.3.1) - if (!result.ContainsKey("@reverse")) - { + { + // 7.4.11.3.1) + if (!result.ContainsKey("@reverse")) + { result["@reverse"] = new JObject(); - } - // 7.4.11.3.2) + } + // 7.4.11.3.2) JObject reverseMap = (JObject)result["@reverse"]; - // 7.4.11.3.3) + // 7.4.11.3.3) foreach (string property in expandedValue.GetKeys()) - { - if ("@reverse".Equals(property)) - { - continue; - } - // 7.4.11.3.3.1) + { + if ("@reverse".Equals(property)) + { + continue; + } + // 7.4.11.3.3.1) JArray items = (JArray)((JObject)expandedValue)[property]; - foreach (JToken item in items) - { - // 7.4.11.3.3.1.1) + foreach (JToken item in items) + { + // 7.4.11.3.3.1.1) if (item is JObject && (((JObject)item).ContainsKey("@value") || ((JObject)item).ContainsKey("@list"))) - { - throw new JsonLdError(JsonLdError.Error.InvalidReversePropertyValue); - } - // 7.4.11.3.3.1.2) - if (!reverseMap.ContainsKey(property)) - { - reverseMap[property] = new JArray(); - } - // 7.4.11.3.3.1.3) + { + throw new JsonLdError(JsonLdError.Error.InvalidReversePropertyValue); + } + // 7.4.11.3.3.1.2) + if (!reverseMap.ContainsKey(property)) + { + reverseMap[property] = new JArray(); + } + // 7.4.11.3.3.1.3) ((JArray)reverseMap[property]).Add(item); - } - } - } - // 7.4.11.4) - continue; - } - else - { - // TODO: SPEC no mention of @explicit etc in spec - if ("@explicit".Equals(expandedProperty) || "@default".Equals(expandedProperty) || - "@embed".Equals(expandedProperty) || "@embedChildren".Equals(expandedProperty) - || "@omitDefault".Equals(expandedProperty)) - { - expandedValue = Expand(activeCtx, expandedProperty, value); - } - } - } - } - } - } - } - } - } - } - // 7.4.12) - if (!expandedValue.IsNull()) - { - result[expandedProperty] = expandedValue; - } - // 7.4.13) - continue; - } - else - { - // 7.5 - if ("@language".Equals(activeCtx.GetContainer(key)) && value is JObject) - { - // 7.5.1) + } + } + } + // 7.4.11.4) + continue; + } + else + { + // TODO: SPEC no mention of @explicit etc in spec + if ("@explicit".Equals(expandedProperty) || "@default".Equals(expandedProperty) || + "@embed".Equals(expandedProperty) || "@embedChildren".Equals(expandedProperty) + || "@omitDefault".Equals(expandedProperty)) + { + expandedValue = Expand(activeCtx, expandedProperty, value); + } + } + } + } + } + } + } + } + } + } + // 7.4.12) + if (!expandedValue.IsNull()) + { + result[expandedProperty] = expandedValue; + } + // 7.4.13) + continue; + } + else + { + // 7.5 + if ("@language".Equals(activeCtx.GetContainer(key)) && value is JObject) + { + // 7.5.1) expandedValue = new JArray(); - // 7.5.2) - foreach (string language in value.GetKeys()) - { + // 7.5.2) + foreach (string language in value.GetKeys()) + { JToken languageValue = ((IDictionary)value)[language]; - // 7.5.2.1) - if (!(languageValue is JArray)) - { + // 7.5.2.1) + if (!(languageValue is JArray)) + { JToken tmp = languageValue; languageValue = new JArray(); ((JArray)languageValue).Add(tmp); - } - // 7.5.2.2) + } + // 7.5.2.2) foreach (JToken item in (JArray)languageValue) - { - // 7.5.2.2.1) - if (!(item.Type == JTokenType.String)) - { - throw new JsonLdError(JsonLdError.Error.InvalidLanguageMapValue, "Expected " + item - .ToString() + " to be a string"); - } - // 7.5.2.2.2) + { + // 7.5.2.2.1) + if (!(item.Type == JTokenType.String)) + { + throw new JsonLdError(JsonLdError.Error.InvalidLanguageMapValue, "Expected " + item + .ToString() + " to be a string"); + } + // 7.5.2.2.2) JObject tmp = new JObject(); - tmp["@value"] = item; - tmp["@language"] = language.ToLower(); - ((JArray)expandedValue).Add(tmp); - } - } - } - else - { - // 7.6) - if ("@index".Equals(activeCtx.GetContainer(key)) && value is JObject) - { - // 7.6.1) - expandedValue = new JArray(); - // 7.6.2) + tmp["@value"] = item; + tmp["@language"] = language.ToLower(); + ((JArray)expandedValue).Add(tmp); + } + } + } + else + { + // 7.6) + if ("@index".Equals(activeCtx.GetContainer(key)) && value is JObject) + { + // 7.6.1) + expandedValue = new JArray(); + // 7.6.2) JArray indexKeys = new JArray(value.GetKeys()); - indexKeys.SortInPlace(); - foreach (string index in indexKeys) - { - JToken indexValue = ((JObject)value)[index]; - // 7.6.2.1) - if (!(indexValue is JArray)) - { - JToken tmp = indexValue; - indexValue = new JArray(); - ((JArray)indexValue).Add(tmp); - } - // 7.6.2.2) - indexValue = Expand(activeCtx, key, indexValue); - // 7.6.2.3) - foreach (JObject item in (JArray)indexValue) - { - // 7.6.2.3.1) - if (!item.ContainsKey("@index")) - { - item["@index"] = index; - } - // 7.6.2.3.2) - ((JArray)expandedValue).Add(item); - } - } - } - else - { - // 7.7) - expandedValue = Expand(activeCtx, key, value); - } - } - } - // 7.8) - if (expandedValue.IsNull()) - { - continue; - } - // 7.9) - if ("@list".Equals(activeCtx.GetContainer(key))) - { - if (!(expandedValue is JObject) || !((JObject)expandedValue).ContainsKey("@list")) - { - JToken tmp = expandedValue; - if (!(tmp is JArray)) - { - tmp = new JArray(); - ((JArray)tmp).Add(expandedValue); - } - expandedValue = new JObject(); - ((JObject)expandedValue)["@list"] = tmp; - } - } - // 7.10) - if (activeCtx.IsReverseProperty(key)) - { - // 7.10.1) - if (!result.ContainsKey("@reverse")) - { - result["@reverse"] = new JObject(); - } - // 7.10.2) - JObject reverseMap = (JObject)result["@reverse"]; - // 7.10.3) + indexKeys.SortInPlace(); + foreach (string index in indexKeys) + { + JToken indexValue = ((JObject)value)[index]; + // 7.6.2.1) + if (!(indexValue is JArray)) + { + JToken tmp = indexValue; + indexValue = new JArray(); + ((JArray)indexValue).Add(tmp); + } + // 7.6.2.2) + indexValue = Expand(activeCtx, key, indexValue); + // 7.6.2.3) + foreach (JObject item in (JArray)indexValue) + { + // 7.6.2.3.1) + if (!item.ContainsKey("@index")) + { + item["@index"] = index; + } + // 7.6.2.3.2) + ((JArray)expandedValue).Add(item); + } + } + } + else + { + // 7.7) + expandedValue = Expand(activeCtx, key, value); + } + } + } + // 7.8) + if (expandedValue.IsNull()) + { + continue; + } + // 7.9) + if ("@list".Equals(activeCtx.GetContainer(key))) + { + if (!(expandedValue is JObject) || !((JObject)expandedValue).ContainsKey("@list")) + { + JToken tmp = expandedValue; + if (!(tmp is JArray)) + { + tmp = new JArray(); + ((JArray)tmp).Add(expandedValue); + } + expandedValue = new JObject(); + ((JObject)expandedValue)["@list"] = tmp; + } + } + // 7.10) + if (activeCtx.IsReverseProperty(key)) + { + // 7.10.1) + if (!result.ContainsKey("@reverse")) + { + result["@reverse"] = new JObject(); + } + // 7.10.2) + JObject reverseMap = (JObject)result["@reverse"]; + // 7.10.3) if (!(expandedValue is JArray)) - { + { JToken tmp = expandedValue; - expandedValue = new JArray(); - ((JArray)expandedValue).Add(tmp); - } - // 7.10.4) - foreach (JToken item in (JArray)expandedValue) - { - // 7.10.4.1) - if (item is JObject && (((JObject)item).ContainsKey("@value") || ((JObject)item).ContainsKey("@list"))) - { - throw new JsonLdError(JsonLdError.Error.InvalidReversePropertyValue); - } - // 7.10.4.2) - if (!reverseMap.ContainsKey(expandedProperty)) - { - reverseMap[expandedProperty] = new JArray(); - } - // 7.10.4.3) + expandedValue = new JArray(); + ((JArray)expandedValue).Add(tmp); + } + // 7.10.4) + foreach (JToken item in (JArray)expandedValue) + { + // 7.10.4.1) + if (item is JObject && (((JObject)item).ContainsKey("@value") || ((JObject)item).ContainsKey("@list"))) + { + throw new JsonLdError(JsonLdError.Error.InvalidReversePropertyValue); + } + // 7.10.4.2) + if (!reverseMap.ContainsKey(expandedProperty)) + { + reverseMap[expandedProperty] = new JArray(); + } + // 7.10.4.3) if (item is JArray) - { + { JsonLD.Collections.AddAll(((JArray)reverseMap[expandedProperty]), (JArray)item); - } - else - { - ((JArray)reverseMap[expandedProperty]).Add(item); - } - } - } - else - { - // 7.11) - // 7.11.1) - if (!result.ContainsKey(expandedProperty)) - { - result[expandedProperty] = new JArray(); - } - // 7.11.2) + } + else + { + ((JArray)reverseMap[expandedProperty]).Add(item); + } + } + } + else + { + // 7.11) + // 7.11.1) + if (!result.ContainsKey(expandedProperty)) + { + result[expandedProperty] = new JArray(); + } + // 7.11.2) if (expandedValue is JArray) - { + { JsonLD.Collections.AddAll(((JArray)result[expandedProperty]), (JArray)expandedValue); - } - else - { - ((JArray)result[expandedProperty]).Add(expandedValue); - } - } - } - // 8) - if (result.ContainsKey("@value")) - { - // 8.1) - // TODO: is this method faster than just using containsKey for - // each? - ICollection keySet = new HashSet(result.GetKeys()); - keySet.Remove("@value"); - keySet.Remove("@index"); - bool langremoved = keySet.Remove("@language"); - bool typeremoved = keySet.Remove("@type"); - if ((langremoved && typeremoved) || !keySet.IsEmpty()) - { - throw new JsonLdError(JsonLdError.Error.InvalidValueObject, "value object has unknown keys" - ); - } - // 8.2) + } + else + { + ((JArray)result[expandedProperty]).Add(expandedValue); + } + } + } + // 8) + if (result.ContainsKey("@value")) + { + // 8.1) + // TODO: is this method faster than just using containsKey for + // each? + ICollection keySet = new HashSet(result.GetKeys()); + keySet.Remove("@value"); + keySet.Remove("@index"); + bool langremoved = keySet.Remove("@language"); + bool typeremoved = keySet.Remove("@type"); + if ((langremoved && typeremoved) || !keySet.IsEmpty()) + { + throw new JsonLdError(JsonLdError.Error.InvalidValueObject, "value object has unknown keys" + ); + } + // 8.2) JToken rval = result["@value"]; - if (rval.IsNull()) - { - // nothing else is possible with result if we set it to - // null, so simply return it - return null; - } - // 8.3) - if (!(rval.Type == JTokenType.String) && result.ContainsKey("@language")) - { - throw new JsonLdError(JsonLdError.Error.InvalidLanguageTaggedValue, "when @language is used, @value must be a string" - ); - } - else - { - // 8.4) - if (result.ContainsKey("@type")) - { - // TODO: is this enough for "is an IRI" - if (!(result["@type"].Type == JTokenType.String) || ((string)result["@type"]).StartsWith("_:") || - !((string)result["@type"]).Contains(":")) - { - throw new JsonLdError(JsonLdError.Error.InvalidTypedValue, "value of @type must be an IRI" - ); - } - } - } - } - else - { - // 9) - if (result.ContainsKey("@type")) - { + if (rval.IsNull()) + { + // nothing else is possible with result if we set it to + // null, so simply return it + return null; + } + // 8.3) + if (!(rval.Type == JTokenType.String) && result.ContainsKey("@language")) + { + throw new JsonLdError(JsonLdError.Error.InvalidLanguageTaggedValue, "when @language is used, @value must be a string" + ); + } + else + { + // 8.4) + if (result.ContainsKey("@type")) + { + // TODO: is this enough for "is an IRI" + if (!(result["@type"].Type == JTokenType.String) || ((string)result["@type"]).StartsWith("_:") || + !((string)result["@type"]).Contains(":")) + { + throw new JsonLdError(JsonLdError.Error.InvalidTypedValue, "value of @type must be an IRI" + ); + } + } + } + } + else + { + // 9) + if (result.ContainsKey("@type")) + { JToken rtype = result["@type"]; - if (!(rtype is JArray)) - { - JArray tmp = new JArray(); - tmp.Add(rtype); - result["@type"] = tmp; - } - } - else - { - // 10) - if (result.ContainsKey("@set") || result.ContainsKey("@list")) - { - // 10.1) - if (result.Count > (result.ContainsKey("@index") ? 2 : 1)) - { - throw new JsonLdError(JsonLdError.Error.InvalidSetOrListObject, "@set or @list may only contain @index" - ); - } - // 10.2) - if (result.ContainsKey("@set")) - { - // result becomes an array here, thus the remaining checks - // will never be true from here on - // so simply return the value rather than have to make - // result an object and cast it with every - // other use in the function. - return result["@set"]; - } - } - } - } - // 11) - if (result.ContainsKey("@language") && result.Count == 1) - { - result = null; - } - // 12) - if (activeProperty == null || "@graph".Equals(activeProperty)) - { - // 12.1) - if (result != null && (result.Count == 0 || result.ContainsKey("@value") || result - .ContainsKey("@list"))) - { - result = null; - } - else - { - // 12.2) - if (result != null && result.ContainsKey("@id") && result.Count == 1) - { - result = null; - } - } - } - // 13) - return result; - } - else - { - // 2) If element is a scalar - // 2.1) - if (activeProperty == null || "@graph".Equals(activeProperty)) - { - return null; - } - return activeCtx.ExpandValue(activeProperty, element); - } - } - } + if (!(rtype is JArray)) + { + JArray tmp = new JArray(); + tmp.Add(rtype); + result["@type"] = tmp; + } + } + else + { + // 10) + if (result.ContainsKey("@set") || result.ContainsKey("@list")) + { + // 10.1) + if (result.Count > (result.ContainsKey("@index") ? 2 : 1)) + { + throw new JsonLdError(JsonLdError.Error.InvalidSetOrListObject, "@set or @list may only contain @index" + ); + } + // 10.2) + if (result.ContainsKey("@set")) + { + // result becomes an array here, thus the remaining checks + // will never be true from here on + // so simply return the value rather than have to make + // result an object and cast it with every + // other use in the function. + return result["@set"]; + } + } + } + } + // 11) + if (result.ContainsKey("@language") && result.Count == 1) + { + result = null; + } + // 12) + if (activeProperty == null || "@graph".Equals(activeProperty)) + { + // 12.1) + if (result != null && (result.Count == 0 || result.ContainsKey("@value") || result + .ContainsKey("@list"))) + { + result = null; + } + else + { + // 12.2) + if (result != null && result.ContainsKey("@id") && result.Count == 1) + { + result = null; + } + } + } + // 13) + return result; + } + else + { + // 2) If element is a scalar + // 2.1) + if (activeProperty == null || "@graph".Equals(activeProperty)) + { + return null; + } + return activeCtx.ExpandValue(activeProperty, element); + } + } + } - /// - public virtual JToken Expand(Context activeCtx, JToken element) - { - return Expand(activeCtx, null, element); - } + /// + public virtual JToken Expand(Context activeCtx, JToken element) + { + return Expand(activeCtx, null, element); + } - /// - /// _____ _ _ _ _ _ _ _ _ | ___| | __ _| |_| |_ ___ _ __ / \ | | __ _ ___ _ - /// __(_) |_| |__ _ __ ___ | |_ | |/ _` | __| __/ _ \ '_ \ / _ \ | |/ _` |/ _ - /// \| '__| | __| '_ \| '_ ` _ \ | _| | | (_| | |_| || __/ | | | / ___ \| | - /// (_| | (_) | | | | |_| | | | | | | | | |_| |_|\__,_|\__|\__\___|_| |_| /_/ - /// \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_| |___/ - /// - /// - internal virtual void GenerateNodeMap(JToken element, JObject - nodeMap) - { - GenerateNodeMap(element, nodeMap, "@default", null, null, null); - } + /// + /// _____ _ _ _ _ _ _ _ _ | ___| | __ _| |_| |_ ___ _ __ / \ | | __ _ ___ _ + /// __(_) |_| |__ _ __ ___ | |_ | |/ _` | __| __/ _ \ '_ \ / _ \ | |/ _` |/ _ + /// \| '__| | __| '_ \| '_ ` _ \ | _| | | (_| | |_| || __/ | | | / ___ \| | + /// (_| | (_) | | | | |_| | | | | | | | | |_| |_|\__,_|\__|\__\___|_| |_| /_/ + /// \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_| |___/ + /// + /// + internal virtual void GenerateNodeMap(JToken element, JObject + nodeMap) + { + GenerateNodeMap(element, nodeMap, "@default", null, null, null); + } - /// + /// internal virtual void GenerateNodeMap(JToken element, JObject - nodeMap, string activeGraph) - { - GenerateNodeMap(element, nodeMap, activeGraph, null, null, null); - } + nodeMap, string activeGraph) + { + GenerateNodeMap(element, nodeMap, activeGraph, null, null, null); + } - /// + /// internal virtual void GenerateNodeMap(JToken element, JObject nodeMap, string activeGraph, JToken activeSubject, string activeProperty, JObject list) - { - // 1) - if (element is JArray) - { - // 1.1) - foreach (JToken item in (JArray)element) - { - GenerateNodeMap(item, nodeMap, activeGraph, activeSubject, activeProperty, list); - } - return; - } - // for convenience + { + // 1) + if (element is JArray) + { + // 1.1) + foreach (JToken item in (JArray)element) + { + GenerateNodeMap(item, nodeMap, activeGraph, activeSubject, activeProperty, list); + } + return; + } + // for convenience IDictionary elem = (IDictionary)element; - // 2) - if (!((IDictionary)nodeMap).ContainsKey(activeGraph)) - { - nodeMap[activeGraph] = new JObject(); - } + // 2) + if (!((IDictionary)nodeMap).ContainsKey(activeGraph)) + { + nodeMap[activeGraph] = new JObject(); + } JObject graph = (JObject)nodeMap[activeGraph - ]; + ]; JObject node = (JObject)((activeSubject.IsNull() || activeSubject.Type != JTokenType.String) ? null : graph[(string)activeSubject]); - // 3) - if (elem.ContainsKey("@type")) - { - // 3.1) - JArray oldTypes; + // 3) + if (elem.ContainsKey("@type")) + { + // 3.1) + JArray oldTypes; JArray newTypes = new JArray(); if (elem["@type"] is JArray) - { + { oldTypes = (JArray)elem["@type"]; - } - else - { + } + else + { oldTypes = new JArray(); - oldTypes.Add((string)elem["@type"]); - } - foreach (string item in oldTypes) - { - if (item.StartsWith("_:")) - { - newTypes.Add(GenerateBlankNodeIdentifier(item)); - } - else - { - newTypes.Add(item); - } - } - if (elem["@type"] is JArray) - { - elem["@type"] = newTypes; - } - else - { - elem["@type"] = newTypes[0]; - } - } - // 4) - if (elem.ContainsKey("@value")) - { - // 4.1) - if (list == null) - { - JsonLdUtils.MergeValue(node, activeProperty, (JObject)elem); - } - else - { - // 4.2) - JsonLdUtils.MergeValue(list, "@list", (JObject)elem); - } - } - else - { - // 5) - if (elem.ContainsKey("@list")) - { - // 5.1) - JObject result = new JObject(); - result["@list"] = new JArray(); - // 5.2) - //for (final Object item : (List) elem.get("@list")) { - // generateNodeMap(item, nodeMap, activeGraph, activeSubject, activeProperty, result); - //} - GenerateNodeMap(elem["@list"], nodeMap, activeGraph, activeSubject, activeProperty - , result); - // 5.3) - JsonLdUtils.MergeValue(node, activeProperty, result); - } - else - { - // 6) - // 6.1) - string id = (string)JsonLD.Collections.Remove(elem, "@id"); - if (id != null) - { - if (id.StartsWith("_:")) - { - id = GenerateBlankNodeIdentifier(id); - } - } - else - { - // 6.2) - id = GenerateBlankNodeIdentifier(null); - } - // 6.3) - if (!graph.ContainsKey(id)) - { - JObject tmp = new JObject(); - tmp["@id"] = id; - graph[id] = tmp; - } - // 6.4) TODO: SPEC this line is asked for by the spec, but it breaks various tests - //node = (Map) graph.get(id); - // 6.5) - if (activeSubject is JObject) - { - // 6.5.1) - JsonLdUtils.MergeValue((JObject)graph[id], activeProperty, activeSubject - ); - } - else - { - // 6.6) - if (activeProperty != null) - { + oldTypes.Add((string)elem["@type"]); + } + foreach (string item in oldTypes) + { + if (item.StartsWith("_:")) + { + newTypes.Add(GenerateBlankNodeIdentifier(item)); + } + else + { + newTypes.Add(item); + } + } + if (elem["@type"] is JArray) + { + elem["@type"] = newTypes; + } + else + { + elem["@type"] = newTypes[0]; + } + } + // 4) + if (elem.ContainsKey("@value")) + { + // 4.1) + if (list == null) + { + JsonLdUtils.MergeValue(node, activeProperty, (JObject)elem); + } + else + { + // 4.2) + JsonLdUtils.MergeValue(list, "@list", (JObject)elem); + } + } + else + { + // 5) + if (elem.ContainsKey("@list")) + { + // 5.1) + JObject result = new JObject(); + result["@list"] = new JArray(); + // 5.2) + //for (final Object item : (List) elem.get("@list")) { + // generateNodeMap(item, nodeMap, activeGraph, activeSubject, activeProperty, result); + //} + GenerateNodeMap(elem["@list"], nodeMap, activeGraph, activeSubject, activeProperty + , result); + // 5.3) + JsonLdUtils.MergeValue(node, activeProperty, result); + } + else + { + // 6) + // 6.1) + string id = (string)JsonLD.Collections.Remove(elem, "@id"); + if (id != null) + { + if (id.StartsWith("_:")) + { + id = GenerateBlankNodeIdentifier(id); + } + } + else + { + // 6.2) + id = GenerateBlankNodeIdentifier(null); + } + // 6.3) + if (!graph.ContainsKey(id)) + { + JObject tmp = new JObject(); + tmp["@id"] = id; + graph[id] = tmp; + } + // 6.4) TODO: SPEC this line is asked for by the spec, but it breaks various tests + //node = (Map) graph.get(id); + // 6.5) + if (activeSubject is JObject) + { + // 6.5.1) + JsonLdUtils.MergeValue((JObject)graph[id], activeProperty, activeSubject + ); + } + else + { + // 6.6) + if (activeProperty != null) + { JObject reference = new JObject(); - reference["@id"] = id; - // 6.6.2) - if (list == null) - { - // 6.6.2.1+2) - JsonLdUtils.MergeValue(node, activeProperty, reference); - } - else - { - // 6.6.3) TODO: SPEC says to add ELEMENT to @list member, should - // be REFERENCE - JsonLdUtils.MergeValue(list, "@list", reference); - } - } - } - // TODO: SPEC this is removed in the spec now, but it's still needed (see 6.4) + reference["@id"] = id; + // 6.6.2) + if (list == null) + { + // 6.6.2.1+2) + JsonLdUtils.MergeValue(node, activeProperty, reference); + } + else + { + // 6.6.3) TODO: SPEC says to add ELEMENT to @list member, should + // be REFERENCE + JsonLdUtils.MergeValue(list, "@list", reference); + } + } + } + // TODO: SPEC this is removed in the spec now, but it's still needed (see 6.4) node = (JObject)graph[id]; - // 6.7) - if (elem.ContainsKey("@type")) - { - foreach (JToken type in (JArray)JsonLD.Collections.Remove(elem, "@type" - )) - { - JsonLdUtils.MergeValue(node, "@type", type); - } - } - // 6.8) - if (elem.ContainsKey("@index")) - { - JToken elemIndex = JsonLD.Collections.Remove(elem, "@index"); - if (node.ContainsKey("@index")) - { - if (!JsonLdUtils.DeepCompare(node["@index"], elemIndex)) - { - throw new JsonLdError(JsonLdError.Error.ConflictingIndexes); - } - } - else - { - node["@index"] = elemIndex; - } - } - // 6.9) - if (elem.ContainsKey("@reverse")) - { - // 6.9.1) + // 6.7) + if (elem.ContainsKey("@type")) + { + foreach (JToken type in (JArray)JsonLD.Collections.Remove(elem, "@type" + )) + { + JsonLdUtils.MergeValue(node, "@type", type); + } + } + // 6.8) + if (elem.ContainsKey("@index")) + { + JToken elemIndex = JsonLD.Collections.Remove(elem, "@index"); + if (node.ContainsKey("@index")) + { + if (!JsonLdUtils.DeepCompare(node["@index"], elemIndex)) + { + throw new JsonLdError(JsonLdError.Error.ConflictingIndexes); + } + } + else + { + node["@index"] = elemIndex; + } + } + // 6.9) + if (elem.ContainsKey("@reverse")) + { + // 6.9.1) JObject referencedNode = new JObject(); - referencedNode["@id"] = id; - // 6.9.2+6.9.4) + referencedNode["@id"] = id; + // 6.9.2+6.9.4) JObject reverseMap = (JObject)JsonLD.Collections.Remove - (elem, "@reverse"); - // 6.9.3) - foreach (string property in reverseMap.GetKeys()) - { - JArray values = (JArray)reverseMap[property]; - // 6.9.3.1) - foreach (JToken value in values) - { - // 6.9.3.1.1) - GenerateNodeMap(value, nodeMap, activeGraph, referencedNode, property, null); - } - } - } - // 6.10) - if (elem.ContainsKey("@graph")) - { - GenerateNodeMap(JsonLD.Collections.Remove(elem, "@graph"), nodeMap, id, null, - null, null); - } - // 6.11) - JArray keys = new JArray(element.GetKeys()); - keys.SortInPlace(); - foreach (string property_1 in keys) - { + (elem, "@reverse"); + // 6.9.3) + foreach (string property in reverseMap.GetKeys()) + { + JArray values = (JArray)reverseMap[property]; + // 6.9.3.1) + foreach (JToken value in values) + { + // 6.9.3.1.1) + GenerateNodeMap(value, nodeMap, activeGraph, referencedNode, property, null); + } + } + } + // 6.10) + if (elem.ContainsKey("@graph")) + { + GenerateNodeMap(JsonLD.Collections.Remove(elem, "@graph"), nodeMap, id, null, + null, null); + } + // 6.11) + JArray keys = new JArray(element.GetKeys()); + keys.SortInPlace(); + foreach (string property_1 in keys) + { var eachProperty_1 = property_1; - JToken value = elem[eachProperty_1]; - // 6.11.1) - if (eachProperty_1.StartsWith("_:")) - { - eachProperty_1 = GenerateBlankNodeIdentifier(eachProperty_1); - } - // 6.11.2) - if (!node.ContainsKey(eachProperty_1)) - { - node[eachProperty_1] = new JArray(); - } - // 6.11.3) - GenerateNodeMap(value, nodeMap, activeGraph, id, eachProperty_1, null); - } - } - } - } + JToken value = elem[eachProperty_1]; + // 6.11.1) + if (eachProperty_1.StartsWith("_:")) + { + eachProperty_1 = GenerateBlankNodeIdentifier(eachProperty_1); + } + // 6.11.2) + if (!node.ContainsKey(eachProperty_1)) + { + node[eachProperty_1] = new JArray(); + } + // 6.11.3) + GenerateNodeMap(value, nodeMap, activeGraph, id, eachProperty_1, null); + } + } + } + } - private readonly JObject blankNodeIdentifierMap = new JObject(); + private readonly JObject blankNodeIdentifierMap = new JObject(); - private int blankNodeCounter = 0; + private int blankNodeCounter = 0; - internal virtual string GenerateBlankNodeIdentifier(string id) - { - if (id != null && blankNodeIdentifierMap.ContainsKey(id)) - { - return (string)blankNodeIdentifierMap[id]; - } - string bnid = "_:b" + blankNodeCounter++; - if (id != null) - { - blankNodeIdentifierMap[id] = bnid; - } - return bnid; - } + internal virtual string GenerateBlankNodeIdentifier(string id) + { + if (id != null && blankNodeIdentifierMap.ContainsKey(id)) + { + return (string)blankNodeIdentifierMap[id]; + } + string bnid = "_:b" + blankNodeCounter++; + if (id != null) + { + blankNodeIdentifierMap[id] = bnid; + } + return bnid; + } - internal virtual string GenerateBlankNodeIdentifier() - { - return GenerateBlankNodeIdentifier(null); - } + internal virtual string GenerateBlankNodeIdentifier() + { + return GenerateBlankNodeIdentifier(null); + } - /// - /// _____ _ _ _ _ _ _ | ___| __ __ _ _ __ ___ (_)_ __ __ _ / \ | | __ _ ___ _ - /// __(_) |_| |__ _ __ ___ | |_ | '__/ _` | '_ ` _ \| | '_ \ / _` | / _ \ | - /// |/ _` |/ _ \| '__| | __| '_ \| '_ ` _ \ | _|| | | (_| | | | | | | | | | | - /// (_| | / ___ \| | (_| | (_) | | | | |_| | | | | | | | | |_| |_| \__,_|_| - /// |_| |_|_|_| |_|\__, | /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_| - /// |___/ |___/ - /// - private class FramingContext - { - public bool embed; + /// + /// _____ _ _ _ _ _ _ | ___| __ __ _ _ __ ___ (_)_ __ __ _ / \ | | __ _ ___ _ + /// __(_) |_| |__ _ __ ___ | |_ | '__/ _` | '_ ` _ \| | '_ \ / _` | / _ \ | + /// |/ _` |/ _ \| '__| | __| '_ \| '_ ` _ \ | _|| | | (_| | | | | | | | | | | + /// (_| | / ___ \| | (_| | (_) | | | | |_| | | | | | | | | |_| |_| \__,_|_| + /// |_| |_|_|_| |_|\__, | /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_| + /// |___/ |___/ + /// + private class FramingContext + { + public bool embed; - public bool @explicit; + public bool @explicit; - public bool omitDefault; + public bool omitDefault; - public FramingContext(JsonLdApi _enclosing) - { - this._enclosing = _enclosing; - this.embed = true; - this.@explicit = false; - this.omitDefault = false; - this.embeds = null; - } + public FramingContext(JsonLdApi _enclosing) + { + this._enclosing = _enclosing; + this.embed = true; + this.@explicit = false; + this.omitDefault = false; + this.embeds = null; + } - public IDictionary embeds = null; + public IDictionary embeds = null; - private readonly JsonLdApi _enclosing; - } + private readonly JsonLdApi _enclosing; + } - private class EmbedNode - { - public JToken parent = null; + private class EmbedNode + { + public JToken parent = null; - public string property = null; + public string property = null; - internal EmbedNode(JsonLdApi _enclosing) - { - this._enclosing = _enclosing; - } + internal EmbedNode(JsonLdApi _enclosing) + { + this._enclosing = _enclosing; + } - private readonly JsonLdApi _enclosing; - } + private readonly JsonLdApi _enclosing; + } - private JObject nodeMap; + private JObject nodeMap; - /// Performs JSON-LD framing. - /// Performs JSON-LD framing. - /// the expanded JSON-LD to frame. - /// the expanded JSON-LD frame to use. - /// the framing options. - /// the framed output. - /// JSONLDProcessingError - /// - public virtual JArray Frame(JToken input, JArray frame) - { - // create framing state - JsonLdApi.FramingContext state = new JsonLdApi.FramingContext(this); - if (this.opts.GetEmbed() != null) - { - state.embed = this.opts.GetEmbed().Value; - } - if (this.opts.GetExplicit() != null) - { - state.@explicit = this.opts.GetExplicit().Value; - } - if (this.opts.GetOmitDefault() != null) - { - state.omitDefault = this.opts.GetOmitDefault().Value; - } - // use tree map so keys are sotred by default + /// Performs JSON-LD framing. + /// Performs JSON-LD framing. + /// the expanded JSON-LD to frame. + /// the expanded JSON-LD frame to use. + /// the framing options. + /// the framed output. + /// JSONLDProcessingError + /// + public virtual JArray Frame(JToken input, JArray frame) + { + // create framing state + JsonLdApi.FramingContext state = new JsonLdApi.FramingContext(this); + if (this.opts.GetEmbed() != null) + { + state.embed = this.opts.GetEmbed().Value; + } + if (this.opts.GetExplicit() != null) + { + state.@explicit = this.opts.GetExplicit().Value; + } + if (this.opts.GetOmitDefault() != null) + { + state.omitDefault = this.opts.GetOmitDefault().Value; + } + // use tree map so keys are sotred by default // XXX BUG BUG BUG XXX (sblom) Figure out where this needs to be sorted and use extension methods to return sorted enumerators or something! - JObject nodes = new JObject(); - GenerateNodeMap(input, nodes); - this.nodeMap = (JObject)nodes["@default"]; - JArray framed = new JArray(); - // NOTE: frame validation is done by the function not allowing anything - // other than list to me passed - Frame(state, this.nodeMap, (frame != null && frame.Count > 0 ? (JObject)frame[0] : new JObject()), framed, null); - return framed; - } + JObject nodes = new JObject(); + GenerateNodeMap(input, nodes); + this.nodeMap = (JObject)nodes["@default"]; + JArray framed = new JArray(); + // NOTE: frame validation is done by the function not allowing anything + // other than list to me passed + Frame(state, this.nodeMap, (frame != null && frame.Count > 0 ? (JObject)frame[0] : new JObject()), framed, null); + return framed; + } - /// Frames subjects according to the given frame. - /// Frames subjects according to the given frame. - /// the current framing state. - /// the subjects to filter. - /// the frame. - /// the parent subject or top-level array. - /// the parent property, initialized to null. - /// JSONLDProcessingError - /// - private void Frame(JsonLdApi.FramingContext state, JObject nodes - , JObject frame, JToken parent, string property) - { - // filter out subjects that match the frame - JObject matches = FilterNodes(state, nodes, frame); - // get flags for current frame - bool embedOn = GetFrameFlag(frame, "@embed", state.embed); - bool explicitOn = GetFrameFlag(frame, "@explicit", state.@explicit); - // add matches to output - JArray ids = new JArray(matches.GetKeys()); - ids.SortInPlace(); - foreach (string id in ids) - { - if (property == null) - { - state.embeds = new Dictionary(); - } - // start output - JObject output = new JObject(); - output["@id"] = id; - // prepare embed meta info - JsonLdApi.EmbedNode embeddedNode = new JsonLdApi.EmbedNode(this); - embeddedNode.parent = parent; - embeddedNode.property = property; - // if embed is on and there is an existing embed - if (embedOn && state.embeds.ContainsKey(id)) - { - JsonLdApi.EmbedNode existing = state.embeds[id]; - embedOn = false; - if (existing.parent is JArray) - { - foreach (JToken p in (JArray)(existing.parent)) - { - if (JsonLdUtils.CompareValues(output, p)) - { - embedOn = true; - break; - } - } - } - else - { - // existing embed's parent is an object - if (((JObject)existing.parent).ContainsKey(existing.property)) - { - foreach (JToken v in (JArray)((JObject)existing.parent)[existing.property]) - { - if (v is JObject && ((JObject)v)["@id"].SafeCompare(id)) - { - embedOn = true; - break; - } - } - } - } - // existing embed has already been added, so allow an overwrite - if (embedOn) - { - RemoveEmbed(state, id); - } - } - // not embedding, add output without any other properties - if (!embedOn) - { - AddFrameOutput(state, parent, property, output); - } - else - { - // add embed meta info - state.embeds[id] = embeddedNode; - // iterate over subject properties - JObject element = (JObject)matches[id]; - JArray props = new JArray(element.GetKeys()); - props.SortInPlace(); - foreach (string prop in props) - { - // copy keywords to output - if (JsonLdUtils.IsKeyword(prop)) - { - output[prop] = JsonLdUtils.Clone(element[prop]); - continue; - } - // if property isn't in the frame - if (!frame.ContainsKey(prop)) - { - // if explicit is off, embed values - if (!explicitOn) - { - EmbedValues(state, element, prop, output); - } - continue; - } - // add objects - JArray value = (JArray)element[prop]; - foreach (JToken item in value) - { - // recurse into list + /// Frames subjects according to the given frame. + /// Frames subjects according to the given frame. + /// the current framing state. + /// the subjects to filter. + /// the frame. + /// the parent subject or top-level array. + /// the parent property, initialized to null. + /// JSONLDProcessingError + /// + private void Frame(JsonLdApi.FramingContext state, JObject nodes + , JObject frame, JToken parent, string property) + { + // filter out subjects that match the frame + JObject matches = FilterNodes(state, nodes, frame); + // get flags for current frame + bool embedOn = GetFrameFlag(frame, "@embed", state.embed); + bool explicitOn = GetFrameFlag(frame, "@explicit", state.@explicit); + // add matches to output + JArray ids = new JArray(matches.GetKeys()); + ids.SortInPlace(); + foreach (string id in ids) + { + if (property == null) + { + state.embeds = new Dictionary(); + } + // start output + JObject output = new JObject(); + output["@id"] = id; + // prepare embed meta info + JsonLdApi.EmbedNode embeddedNode = new JsonLdApi.EmbedNode(this); + embeddedNode.parent = parent; + embeddedNode.property = property; + // if embed is on and there is an existing embed + if (embedOn && state.embeds.ContainsKey(id)) + { + JsonLdApi.EmbedNode existing = state.embeds[id]; + embedOn = false; + if (existing.parent is JArray) + { + foreach (JToken p in (JArray)(existing.parent)) + { + if (JsonLdUtils.CompareValues(output, p)) + { + embedOn = true; + break; + } + } + } + else + { + // existing embed's parent is an object + if (((JObject)existing.parent).ContainsKey(existing.property)) + { + foreach (JToken v in (JArray)((JObject)existing.parent)[existing.property]) + { + if (v is JObject && ((JObject)v)["@id"].SafeCompare(id)) + { + embedOn = true; + break; + } + } + } + } + // existing embed has already been added, so allow an overwrite + if (embedOn) + { + RemoveEmbed(state, id); + } + } + // not embedding, add output without any other properties + if (!embedOn) + { + AddFrameOutput(state, parent, property, output); + } + else + { + // add embed meta info + state.embeds[id] = embeddedNode; + // iterate over subject properties + JObject element = (JObject)matches[id]; + JArray props = new JArray(element.GetKeys()); + props.SortInPlace(); + foreach (string prop in props) + { + // copy keywords to output + if (JsonLdUtils.IsKeyword(prop)) + { + output[prop] = JsonLdUtils.Clone(element[prop]); + continue; + } + // if property isn't in the frame + if (!frame.ContainsKey(prop)) + { + // if explicit is off, embed values + if (!explicitOn) + { + EmbedValues(state, element, prop, output); + } + continue; + } + // add objects + JArray value = (JArray)element[prop]; + foreach (JToken item in value) + { + // recurse into list if ((item is JObject) && ((JObject)item).ContainsKey("@list")) - { - // add empty list - JObject list = new JObject(); - list["@list"] = new JArray(); - AddFrameOutput(state, output, prop, list); - // add list objects + { + // add empty list + JObject list = new JObject(); + list["@list"] = new JArray(); + AddFrameOutput(state, output, prop, list); + // add list objects foreach (JToken listitem in (JArray)((JObject)item)["@list" - ]) - { - // recurse into subject reference - if (JsonLdUtils.IsNodeReference(listitem)) - { - JObject tmp = new JObject(); + ]) + { + // recurse into subject reference + if (JsonLdUtils.IsNodeReference(listitem)) + { + JObject tmp = new JObject(); string itemid = (string)((IDictionary)listitem)["@id"]; - // TODO: nodes may need to be node_map, - // which is global - tmp[itemid] = this.nodeMap[itemid]; + // TODO: nodes may need to be node_map, + // which is global + tmp[itemid] = this.nodeMap[itemid]; Frame(state, tmp, (JObject)((JArray)frame[prop])[0], list - , "@list"); - } - else - { - // include other values automatcially (TODO: - // may need JsonLdUtils.clone(n)) - AddFrameOutput(state, list, "@list", listitem); - } - } - } - else - { - // recurse into subject reference - if (JsonLdUtils.IsNodeReference(item)) - { + , "@list"); + } + else + { + // include other values automatcially (TODO: + // may need JsonLdUtils.clone(n)) + AddFrameOutput(state, list, "@list", listitem); + } + } + } + else + { + // recurse into subject reference + if (JsonLdUtils.IsNodeReference(item)) + { JObject tmp = new JObject(); string itemid = (string)((JObject)item)["@id"]; - // TODO: nodes may need to be node_map, which is - // global - tmp[itemid] = this.nodeMap[itemid]; - Frame(state, tmp, (JObject)((JArray)frame[prop])[0], output - , prop); - } - else - { - // include other values automatically (TODO: may - // need JsonLdUtils.clone(o)) - AddFrameOutput(state, output, prop, item); - } - } - } - } - // handle defaults - props = new JArray(frame.GetKeys()); - props.SortInPlace(); - foreach (string prop_1 in props) - { - // skip keywords - if (JsonLdUtils.IsKeyword(prop_1)) - { - continue; - } - JArray pf = (JArray)frame[prop_1]; - JObject propertyFrame = pf.Count > 0 ? (JObject)pf[0] : null; - if (propertyFrame == null) - { - propertyFrame = new JObject(); - } - bool omitDefaultOn = GetFrameFlag(propertyFrame, "@omitDefault", state.omitDefault - ); - if (!omitDefaultOn && !output.ContainsKey(prop_1)) - { - JToken def = "@null"; - if (propertyFrame.ContainsKey("@default")) - { - def = JsonLdUtils.Clone(propertyFrame["@default"]); - } - if (!(def is JArray)) - { - JArray tmp = new JArray(); - tmp.Add(def); - def = tmp; - } - JObject tmp1 = new JObject(); - tmp1["@preserve"] = def; - JArray tmp2 = new JArray(); - tmp2.Add(tmp1); - output[prop_1] = tmp2; - } - } - // add output to parent - AddFrameOutput(state, parent, property, output); - } - } - } + // TODO: nodes may need to be node_map, which is + // global + tmp[itemid] = this.nodeMap[itemid]; + Frame(state, tmp, (JObject)((JArray)frame[prop])[0], output + , prop); + } + else + { + // include other values automatically (TODO: may + // need JsonLdUtils.clone(o)) + AddFrameOutput(state, output, prop, item); + } + } + } + } + // handle defaults + props = new JArray(frame.GetKeys()); + props.SortInPlace(); + foreach (string prop_1 in props) + { + // skip keywords + if (JsonLdUtils.IsKeyword(prop_1)) + { + continue; + } + JArray pf = (JArray)frame[prop_1]; + JObject propertyFrame = pf.Count > 0 ? (JObject)pf[0] : null; + if (propertyFrame == null) + { + propertyFrame = new JObject(); + } + bool omitDefaultOn = GetFrameFlag(propertyFrame, "@omitDefault", state.omitDefault + ); + if (!omitDefaultOn && !output.ContainsKey(prop_1)) + { + JToken def = "@null"; + if (propertyFrame.ContainsKey("@default")) + { + def = JsonLdUtils.Clone(propertyFrame["@default"]); + } + if (!(def is JArray)) + { + JArray tmp = new JArray(); + tmp.Add(def); + def = tmp; + } + JObject tmp1 = new JObject(); + tmp1["@preserve"] = def; + JArray tmp2 = new JArray(); + tmp2.Add(tmp1); + output[prop_1] = tmp2; + } + } + // add output to parent + AddFrameOutput(state, parent, property, output); + } + } + } - private bool GetFrameFlag(JObject frame, string name, bool thedefault - ) - { - JToken value = frame[name]; - if (value is JArray) - { - if (((JArray)value).Count > 0) - { - value = ((JArray)value)[0]; - } - } - if (value is JObject && ((JObject)value).ContainsKey("@value" - )) - { - value = ((JObject)value)["@value"]; - } - if (value != null && value.Type == JTokenType.Boolean) - { - return (bool)value; - } - return thedefault; - } + private bool GetFrameFlag(JObject frame, string name, bool thedefault + ) + { + JToken value = frame[name]; + if (value is JArray) + { + if (((JArray)value).Count > 0) + { + value = ((JArray)value)[0]; + } + } + if (value is JObject && ((JObject)value).ContainsKey("@value" + )) + { + value = ((JObject)value)["@value"]; + } + if (value != null && value.Type == JTokenType.Boolean) + { + return (bool)value; + } + return thedefault; + } - /// Removes an existing embed. - /// Removes an existing embed. - /// the current framing state. - /// the @id of the embed to remove. - private static void RemoveEmbed(JsonLdApi.FramingContext state, string id) - { - // get existing embed - IDictionary embeds = state.embeds; - JsonLdApi.EmbedNode embed = embeds[id]; + /// Removes an existing embed. + /// Removes an existing embed. + /// the current framing state. + /// the @id of the embed to remove. + private static void RemoveEmbed(JsonLdApi.FramingContext state, string id) + { + // get existing embed + IDictionary embeds = state.embeds; + JsonLdApi.EmbedNode embed = embeds[id]; JToken parent = embed.parent; - string property = embed.property; - // create reference to replace embed - JObject node = new JObject(); - node["@id"] = id; - // remove existing embed - if (JsonLdUtils.IsNode(parent)) - { - // replace subject with reference - JArray newvals = new JArray(); - JArray oldvals = (JArray)((JObject)parent)[property - ]; - foreach (JToken v in oldvals) - { - if (v is JObject && ((JObject)v)["@id"].SafeCompare(id)) - { - newvals.Add(node); - } - else - { - newvals.Add(v); - } - } - ((JObject)parent)[property] = newvals; - } - // recursively remove dependent dangling embeds - RemoveDependents(embeds, id); - } + string property = embed.property; + // create reference to replace embed + JObject node = new JObject(); + node["@id"] = id; + // remove existing embed + if (JsonLdUtils.IsNode(parent)) + { + // replace subject with reference + JArray newvals = new JArray(); + JArray oldvals = (JArray)((JObject)parent)[property + ]; + foreach (JToken v in oldvals) + { + if (v is JObject && ((JObject)v)["@id"].SafeCompare(id)) + { + newvals.Add(node); + } + else + { + newvals.Add(v); + } + } + ((JObject)parent)[property] = newvals; + } + // recursively remove dependent dangling embeds + RemoveDependents(embeds, id); + } - private static void RemoveDependents(IDictionary embeds - , string id) - { - // get embed keys as a separate array to enable deleting keys in map - foreach (string id_dep in embeds.Keys) - { - JsonLdApi.EmbedNode e = embeds[id_dep]; + private static void RemoveDependents(IDictionary embeds + , string id) + { + // get embed keys as a separate array to enable deleting keys in map + foreach (string id_dep in embeds.Keys) + { + JsonLdApi.EmbedNode e = embeds[id_dep]; JToken p = !e.parent.IsNull() ? e.parent : new JObject(); - if (!(p is JObject)) - { - continue; - } - string pid = (string)((JObject)p)["@id"]; - if (Obj.Equals(id, pid)) - { - JsonLD.Collections.Remove(embeds, id_dep); - RemoveDependents(embeds, id_dep); - } - } - } + if (!(p is JObject)) + { + continue; + } + string pid = (string)((JObject)p)["@id"]; + if (Obj.Equals(id, pid)) + { + JsonLD.Collections.Remove(embeds, id_dep); + RemoveDependents(embeds, id_dep); + } + } + } - /// - private JObject FilterNodes(JsonLdApi.FramingContext state, JObject nodes, JObject frame) - { - JObject rval = new JObject(); - foreach (string id in nodes.GetKeys()) - { - JObject element = (JObject)nodes[id]; - if (element != null && FilterNode(state, element, frame)) - { - rval[id] = element; - } - } - return rval; - } + /// + private JObject FilterNodes(JsonLdApi.FramingContext state, JObject nodes, JObject frame) + { + JObject rval = new JObject(); + foreach (string id in nodes.GetKeys()) + { + JObject element = (JObject)nodes[id]; + if (element != null && FilterNode(state, element, frame)) + { + rval[id] = element; + } + } + return rval; + } - /// - private bool FilterNode(JsonLdApi.FramingContext state, JObject node, JObject frame) - { - JToken types = frame["@type"]; - if (!types.IsNull()) - { - if (!(types is JArray)) - { - throw new JsonLdError(JsonLdError.Error.SyntaxError, "frame @type must be an array" - ); - } + /// + private bool FilterNode(JsonLdApi.FramingContext state, JObject node, JObject frame) + { + JToken types = frame["@type"]; + if (!types.IsNull()) + { + if (!(types is JArray)) + { + throw new JsonLdError(JsonLdError.Error.SyntaxError, "frame @type must be an array" + ); + } JToken nodeTypes = node["@type"]; - if (nodeTypes.IsNull()) - { - nodeTypes = new JArray(); - } - else - { - if (!(nodeTypes is JArray)) - { - throw new JsonLdError(JsonLdError.Error.SyntaxError, "node @type must be an array" - ); - } - } - if (((JArray)types).Count == 1 && ((JArray)types)[0] is JObject - && ((JObject)((JArray)types)[0]).Count == 0) - { - return !((JArray)nodeTypes).IsEmpty(); - } - else - { - foreach (JToken i in (JArray)nodeTypes) - { + if (nodeTypes.IsNull()) + { + nodeTypes = new JArray(); + } + else + { + if (!(nodeTypes is JArray)) + { + throw new JsonLdError(JsonLdError.Error.SyntaxError, "node @type must be an array" + ); + } + } + if (((JArray)types).Count == 1 && ((JArray)types)[0] is JObject + && ((JObject)((JArray)types)[0]).Count == 0) + { + return !((JArray)nodeTypes).IsEmpty(); + } + else + { + foreach (JToken i in (JArray)nodeTypes) + { foreach (JToken j in (JArray)types) - { - if (JsonLdUtils.DeepCompare(i, j)) - { - return true; - } - } - } - return false; - } - } - else - { - foreach (string key in frame.GetKeys()) - { - if ("@id".Equals(key) || !JsonLdUtils.IsKeyword(key) && !(node.ContainsKey(key))) - { - return false; - } - } - return true; - } - } + { + if (JsonLdUtils.DeepCompare(i, j)) + { + return true; + } + } + } + return false; + } + } + else + { + foreach (string key in frame.GetKeys()) + { + if ("@id".Equals(key) || !JsonLdUtils.IsKeyword(key) && !(node.ContainsKey(key))) + { + return false; + } + } + return true; + } + } - /// Adds framing output to the given parent. - /// Adds framing output to the given parent. - /// the current framing state. - /// the parent to add to. - /// the parent property. - /// the output to add. - private static void AddFrameOutput(JsonLdApi.FramingContext state, JToken parent, - string property, JToken output) - { + /// Adds framing output to the given parent. + /// Adds framing output to the given parent. + /// the current framing state. + /// the parent to add to. + /// the parent property. + /// the output to add. + private static void AddFrameOutput(JsonLdApi.FramingContext state, JToken parent, + string property, JToken output) + { if (parent is JObject) - { - JArray prop = (JArray)((JObject)parent)[property]; - if (prop == null) - { - prop = new JArray(); - ((JObject)parent)[property] = prop; - } - prop.Add(output); - } - else - { - ((JArray)parent).Add(output); - } - } + { + JArray prop = (JArray)((JObject)parent)[property]; + if (prop == null) + { + prop = new JArray(); + ((JObject)parent)[property] = prop; + } + prop.Add(output); + } + else + { + ((JArray)parent).Add(output); + } + } - /// - /// Embeds values for the given subject and property into the given output - /// during the framing algorithm. - /// - /// - /// Embeds values for the given subject and property into the given output - /// during the framing algorithm. - /// - /// the current framing state. - /// the subject. - /// the property. - /// the output. - private void EmbedValues(JsonLdApi.FramingContext state, JObject element, string property, JToken output) - { - // embed subject properties in output - JArray objects = (JArray)element[property]; - foreach (JToken o in objects) - { + /// + /// Embeds values for the given subject and property into the given output + /// during the framing algorithm. + /// + /// + /// Embeds values for the given subject and property into the given output + /// during the framing algorithm. + /// + /// the current framing state. + /// the subject. + /// the property. + /// the output. + private void EmbedValues(JsonLdApi.FramingContext state, JObject element, string property, JToken output) + { + // embed subject properties in output + JArray objects = (JArray)element[property]; + foreach (JToken o in objects) + { var eachObj = o; if (eachObj is JObject && ((JObject)eachObj).ContainsKey("@list")) @@ -1811,407 +1812,410 @@ private void EmbedValues(JsonLdApi.FramingContext state, JObject element, string } // handle subject reference else if (JsonLdUtils.IsNodeReference(eachObj)) - { - string sid = (string)((JObject)eachObj)["@id"]; - // embed full subject if isn't already embedded - if (!state.embeds.ContainsKey(sid)) - { - // add embed - JsonLdApi.EmbedNode embed = new JsonLdApi.EmbedNode(this); - embed.parent = output; - embed.property = property; - state.embeds[sid] = embed; - // recurse into subject - eachObj = new JObject(); - JObject s = (JObject)this.nodeMap[sid]; - if (s == null) - { - s = new JObject(); - s["@id"] = sid; - } - foreach (string prop in s.GetKeys()) - { - // copy keywords - if (JsonLdUtils.IsKeyword(prop)) - { - ((JObject)eachObj)[prop] = JsonLdUtils.Clone(s[prop]); - continue; - } - EmbedValues(state, s, prop, eachObj); - } - } - AddFrameOutput(state, output, property, eachObj); - } - else - { - // copy non-subject value - AddFrameOutput(state, output, property, JsonLdUtils.Clone(eachObj)); - } - } - } + { + string sid = (string)((JObject)eachObj)["@id"]; + // embed full subject if isn't already embedded + if (!state.embeds.ContainsKey(sid)) + { + // add embed + JsonLdApi.EmbedNode embed = new JsonLdApi.EmbedNode(this); + embed.parent = output; + embed.property = property; + state.embeds[sid] = embed; + // recurse into subject + eachObj = new JObject(); + JObject s = (JObject)this.nodeMap[sid]; + if (s == null) + { + s = new JObject(); + s["@id"] = sid; + } + foreach (string prop in s.GetKeys()) + { + // copy keywords + if (JsonLdUtils.IsKeyword(prop)) + { + ((JObject)eachObj)[prop] = JsonLdUtils.Clone(s[prop]); + continue; + } + EmbedValues(state, s, prop, eachObj); + } + } + AddFrameOutput(state, output, property, eachObj); + } + else + { + // copy non-subject value + AddFrameOutput(state, output, property, JsonLdUtils.Clone(eachObj)); + } + } + } - /// Helper class for node usages - /// tristan - private class UsagesNode - { - public UsagesNode(JsonLdApi _enclosing, JsonLdApi.NodeMapNode node, string property - , JObject value) - { - this._enclosing = _enclosing; - this.node = node; - this.property = property; - this.value = value; - } + /// Helper class for node usages + /// tristan + private class UsagesNode + { + public UsagesNode(JsonLdApi _enclosing, JsonLdApi.NodeMapNode node, string property + , JObject value) + { + this._enclosing = _enclosing; + this.node = node; + this.property = property; + this.value = value; + } - public JsonLdApi.NodeMapNode node = null; + public JsonLdApi.NodeMapNode node = null; - public string property = null; + public string property = null; - public JObject value = null; + public JObject value = null; - private readonly JsonLdApi _enclosing; - } + private readonly JsonLdApi _enclosing; + } - //[System.Serializable] - private class NodeMapNode : JObject - { + //[System.Serializable] + private class NodeMapNode : JObject + { public IList usages = new List(); - public NodeMapNode(JsonLdApi _enclosing, string id) : base() - { - this._enclosing = _enclosing; - this["@id"] = id; - } + public NodeMapNode(JsonLdApi _enclosing, string id) : base() + { + this._enclosing = _enclosing; + this["@id"] = id; + } - // helper fucntion for 4.3.3 - public virtual bool IsWellFormedListNode() - { - if (this.usages.Count != 1) - { - return false; - } - int keys = 0; - if (this.ContainsKey(JSONLDConsts.RdfFirst)) - { - keys++; - if (!(this[JSONLDConsts.RdfFirst] is JArray && ((JArray)this[JSONLDConsts.RdfFirst - ]).Count == 1)) - { - return false; - } - } - if (this.ContainsKey(JSONLDConsts.RdfRest)) - { - keys++; - if (!(this[JSONLDConsts.RdfRest] is JArray && ((JArray)this[JSONLDConsts.RdfRest - ]).Count == 1)) - { - return false; - } - } - if (this.ContainsKey("@type")) - { - keys++; - if (!(this["@type"] is JArray && ((JArray)this["@type"]).Count == 1) && JSONLDConsts - .RdfList.Equals(((JArray)this["@type"])[0])) - { - return false; - } - } - // TODO: SPEC: 4.3.3 has no mention of @id - if (this.ContainsKey("@id")) - { - keys++; - } - if (keys < Count) - { - return false; - } - return true; - } + // helper fucntion for 4.3.3 + public virtual bool IsWellFormedListNode() + { + if (this.usages.Count != 1) + { + return false; + } + int keys = 0; + if (this.ContainsKey(JSONLDConsts.RdfFirst)) + { + keys++; + if (!(this[JSONLDConsts.RdfFirst] is JArray && ((JArray)this[JSONLDConsts.RdfFirst + ]).Count == 1)) + { + return false; + } + } + if (this.ContainsKey(JSONLDConsts.RdfRest)) + { + keys++; + if (!(this[JSONLDConsts.RdfRest] is JArray && ((JArray)this[JSONLDConsts.RdfRest + ]).Count == 1)) + { + return false; + } + } + if (this.ContainsKey("@type")) + { + keys++; + if (!(this["@type"] is JArray && ((JArray)this["@type"]).Count == 1) && JSONLDConsts + .RdfList.Equals(((JArray)this["@type"])[0])) + { + return false; + } + } + // TODO: SPEC: 4.3.3 has no mention of @id + if (this.ContainsKey("@id")) + { + keys++; + } + if (keys < Count) + { + return false; + } + return true; + } - // return this node without the usages variable - public virtual JObject Serialize() - { - return new JObject(this); - } + // return this node without the usages variable + public virtual JObject Serialize() + { + return new JObject(this); + } - private readonly JsonLdApi _enclosing; - } + private readonly JsonLdApi _enclosing; + } - /// Converts RDF statements into JSON-LD. - /// Converts RDF statements into JSON-LD. - /// the RDF statements. - /// the RDF conversion options. - /// (err, output) called once the operation completes. - /// JSONLDProcessingError - /// - public virtual JArray FromRDF(RDFDataset dataset) - { - // 1) - JObject defaultGraph = new JObject(); - // 2) - JObject graphMap = new JObject(); - graphMap["@default"] = defaultGraph; - // 3/3.1) - foreach (string name in dataset.GraphNames()) - { - IList graph = dataset.GetQuads(name); - // 3.2+3.4) - JObject nodeMap; - if (!graphMap.ContainsKey(name)) - { - nodeMap = new JObject(); - graphMap[name] = nodeMap; - } - else - { - nodeMap = (JObject)graphMap[name]; - } - // 3.3) - if (!"@default".Equals(name) && !Obj.Contains(defaultGraph, name)) - { - defaultGraph[name] = new JsonLdApi.NodeMapNode(this, name); - } - // 3.5) - foreach (RDFDataset.Quad triple in graph) - { - string subject = triple.GetSubject().GetValue(); - string predicate = triple.GetPredicate().GetValue(); - RDFDataset.Node @object = triple.GetObject(); - // 3.5.1+3.5.2) - JsonLdApi.NodeMapNode node; - if (!nodeMap.ContainsKey(subject)) - { - node = new JsonLdApi.NodeMapNode(this, subject); - nodeMap[subject] = node; - } - else - { - node = (NodeMapNode)nodeMap[subject]; - } - // 3.5.3) - if ((@object.IsIRI() || @object.IsBlankNode()) && !nodeMap.ContainsKey(@object.GetValue - ())) - { - nodeMap[@object.GetValue()] = new JsonLdApi.NodeMapNode(this, @object.GetValue()); - } - // 3.5.4) - if (JSONLDConsts.RdfType.Equals(predicate) && (@object.IsIRI() || @object.IsBlankNode - ()) && !opts.GetUseRdfType()) - { - JsonLdUtils.MergeValue(node, "@type", @object.GetValue()); - continue; - } - // 3.5.5) - JObject value = @object.ToObject(opts.GetUseNativeTypes()); - // 3.5.6+7) - JsonLdUtils.MergeValue(node, predicate, value); - // 3.5.8) - if (@object.IsBlankNode() || @object.IsIRI()) - { - // 3.5.8.1-3) - ((NodeMapNode)nodeMap[@object.GetValue()]).usages.Add(new JsonLdApi.UsagesNode(this, node, predicate - , value)); - } - } - } - // 4) - foreach (string name_1 in graphMap.GetKeys()) - { - JObject graph = (JObject)graphMap[name_1]; - // 4.1) - if (!graph.ContainsKey(JSONLDConsts.RdfNil)) - { - continue; - } - // 4.2) - JsonLdApi.NodeMapNode nil = (NodeMapNode)graph[JSONLDConsts.RdfNil]; - // 4.3) - foreach (JsonLdApi.UsagesNode usage in nil.usages) - { - // 4.3.1) - JsonLdApi.NodeMapNode node = usage.node; - string property = usage.property; - JObject head = usage.value; - // 4.3.2) - JArray list = new JArray(); - JArray listNodes = new JArray(); - // 4.3.3) - while (JSONLDConsts.RdfRest.Equals(property) && node.IsWellFormedListNode()) - { - // 4.3.3.1) - list.Add(((JArray)node[JSONLDConsts.RdfFirst])[0]); - // 4.3.3.2) - listNodes.Add((string)node["@id"]); - // 4.3.3.3) - JsonLdApi.UsagesNode nodeUsage = node.usages[0]; - // 4.3.3.4) - node = nodeUsage.node; - property = nodeUsage.property; - head = nodeUsage.value; - // 4.3.3.5) - if (!JsonLdUtils.IsBlankNode(node)) - { - break; - } - } - // 4.3.4) - if (JSONLDConsts.RdfFirst.Equals(property)) - { - // 4.3.4.1) - if (JSONLDConsts.RdfNil.Equals(node["@id"])) - { - continue; - } - // 4.3.4.3) - string headId = (string)head["@id"]; - // 4.3.4.4-5) - head = (JObject)((JArray)graph[headId][JSONLDConsts.RdfRest - ])[0]; - // 4.3.4.6) - list.RemoveAt(list.Count - 1); - listNodes.RemoveAt(listNodes.Count - 1); - } - // 4.3.5) - JsonLD.Collections.Remove(head, "@id"); - // 4.3.6) - JsonLD.Collections.Reverse(list); - // 4.3.7) - head["@list"] = list; - // 4.3.8) - foreach (string nodeId in listNodes) - { - JsonLD.Collections.Remove(graph, nodeId); - } - } - } - // 5) - JArray result = new JArray(); - // 6) + /// Converts RDF statements into JSON-LD. + /// Converts RDF statements into JSON-LD. + /// the RDF statements. + /// the RDF conversion options. + /// (err, output) called once the operation completes. + /// JSONLDProcessingError + /// + public virtual JArray FromRDF(RDFDataset dataset) + { + // 1) + JObject defaultGraph = new JObject(); + // 2) + JObject graphMap = new JObject(); + graphMap["@default"] = defaultGraph; + // 3/3.1) + foreach (string name in dataset.GraphNames()) + { + IList graph = dataset.GetQuads(name); + // 3.2+3.4) + JObject nodeMap; + if (!graphMap.ContainsKey(name)) + { + nodeMap = new JObject(); + graphMap[name] = nodeMap; + } + else + { + nodeMap = (JObject)graphMap[name]; + } + // 3.3) + if (!"@default".Equals(name) && !Obj.Contains(defaultGraph, name)) + { + defaultGraph[name] = new JsonLdApi.NodeMapNode(this, name); + } + // 3.5) + foreach (RDFDataset.Quad triple in graph) + { + string subject = triple.GetSubject().GetValue(); + string predicate = triple.GetPredicate().GetValue(); + RDFDataset.Node @object = triple.GetObject(); + // 3.5.1+3.5.2) + JsonLdApi.NodeMapNode node; + if (!nodeMap.ContainsKey(subject)) + { + node = new JsonLdApi.NodeMapNode(this, subject); + nodeMap[subject] = node; + } + else + { + node = (NodeMapNode)nodeMap[subject]; + } + // 3.5.3) + if ((@object.IsIRI() || @object.IsBlankNode()) && !nodeMap.ContainsKey(@object.GetValue + ())) + { + nodeMap[@object.GetValue()] = new JsonLdApi.NodeMapNode(this, @object.GetValue()); + } + // 3.5.4) + if (JSONLDConsts.RdfType.Equals(predicate) && (@object.IsIRI() || @object.IsBlankNode + ()) && !opts.GetUseRdfType()) + { + JsonLdUtils.MergeValue(node, "@type", @object.GetValue()); + continue; + } + // 3.5.5) + JObject value = @object.ToObject(opts.GetUseNativeTypes()); + // 3.5.6+7) + JsonLdUtils.MergeValue(node, predicate, value); + // 3.5.8) + if (@object.IsBlankNode() || @object.IsIRI()) + { + // 3.5.8.1-3) + ((NodeMapNode)nodeMap[@object.GetValue()]).usages.Add(new JsonLdApi.UsagesNode(this, node, predicate + , value)); + } + } + } + // 4) + foreach (string name_1 in graphMap.GetKeys()) + { + JObject graph = (JObject)graphMap[name_1]; + // 4.1) + if (!graph.ContainsKey(JSONLDConsts.RdfNil)) + { + continue; + } + // 4.2) + JsonLdApi.NodeMapNode nil = (NodeMapNode)graph[JSONLDConsts.RdfNil]; + // 4.3) + foreach (JsonLdApi.UsagesNode usage in nil.usages) + { + // 4.3.1) + JsonLdApi.NodeMapNode node = usage.node; + string property = usage.property; + JObject head = usage.value; + // 4.3.2) + JArray list = new JArray(); + JArray listNodes = new JArray(); + // 4.3.3) + while (JSONLDConsts.RdfRest.Equals(property) && node.IsWellFormedListNode()) + { + // 4.3.3.1) + list.Add(((JArray)node[JSONLDConsts.RdfFirst])[0]); + // 4.3.3.2) + listNodes.Add((string)node["@id"]); + // 4.3.3.3) + JsonLdApi.UsagesNode nodeUsage = node.usages[0]; + // 4.3.3.4) + node = nodeUsage.node; + property = nodeUsage.property; + head = nodeUsage.value; + // 4.3.3.5) + if (!JsonLdUtils.IsBlankNode(node)) + { + break; + } + } + // 4.3.4) + if (JSONLDConsts.RdfFirst.Equals(property)) + { + // 4.3.4.1) + if (JSONLDConsts.RdfNil.Equals(node["@id"])) + { + continue; + } + // 4.3.4.3) + string headId = (string)head["@id"]; + // 4.3.4.4-5) + head = (JObject)((JArray)graph[headId][JSONLDConsts.RdfRest + ])[0]; + // 4.3.4.6) + list.RemoveAt(list.Count - 1); + listNodes.RemoveAt(listNodes.Count - 1); + } + // 4.3.5) + JsonLD.Collections.Remove(head, "@id"); + // 4.3.6) + JsonLD.Collections.Reverse(list); + // 4.3.7) + head["@list"] = list; + // 4.3.8) + foreach (string nodeId in listNodes) + { + JsonLD.Collections.Remove(graph, nodeId); + } + } + } + // 5) + JArray result = new JArray(); + // 6) JArray ids = new JArray(defaultGraph.GetKeys()); - ids.SortInPlace(); - foreach (string subject_1 in ids) - { - JsonLdApi.NodeMapNode node = (NodeMapNode)defaultGraph[subject_1]; - // 6.1) - if (graphMap.ContainsKey(subject_1)) - { - // 6.1.1) + ids.SortInPlace(); + foreach (string subject_1 in ids) + { + JsonLdApi.NodeMapNode node = (NodeMapNode)defaultGraph[subject_1]; + // 6.1) + if (graphMap.ContainsKey(subject_1)) + { + // 6.1.1) node["@graph"] = new JArray(); - // 6.1.2) + // 6.1.2) JArray keys = new JArray(graphMap[subject_1].GetKeys()); - keys.SortInPlace(); - foreach (string s in keys) - { - JsonLdApi.NodeMapNode n = (NodeMapNode)graphMap[subject_1][s]; - if (n.Count == 1 && n.ContainsKey("@id")) - { - continue; - } - ((JArray)node["@graph"]).Add(n.Serialize()); - } - } - // 6.2) - if (node.Count == 1 && node.ContainsKey("@id")) - { - continue; - } - result.Add(node.Serialize()); - } - return result; - } + keys.SortInPlace(); + foreach (string s in keys) + { + JsonLdApi.NodeMapNode n = (NodeMapNode)graphMap[subject_1][s]; + if (n.Count == 1 && n.ContainsKey("@id")) + { + continue; + } + ((JArray)node["@graph"]).Add(n.Serialize()); + } + } + // 6.2) + if (node.Count == 1 && node.ContainsKey("@id")) + { + continue; + } + result.Add(node.Serialize()); + } + return result; + } + + /// Adds RDF triples for each graph in the given node map to an RDF dataset. + /// + /// Adds RDF triples for each graph in the given node map to an RDF dataset. + /// + /// the RDF dataset. + /// JsonLdError + /// + public virtual RDFDataset ToRDF() + { + // TODO: make the default generateNodeMap call (i.e. without a + // graphName) create and return the nodeMap + JObject nodeMap = new JObject(); + nodeMap["@default"] = new JObject(); + GenerateNodeMap(this.value, nodeMap); + RDFDataset dataset = new RDFDataset(this); + foreach (string graphName in nodeMap.GetKeys()) + { + // 4.1) + if (JsonLdUtils.IsRelativeIri(graphName)) + { + continue; + } + JObject graph = (JObject)nodeMap[graphName + ]; + dataset.GraphToRDF(graphName, graph); + } + return dataset; + } - /// Adds RDF triples for each graph in the given node map to an RDF dataset. - /// - /// Adds RDF triples for each graph in the given node map to an RDF dataset. - /// - /// the RDF dataset. - /// JsonLdError - /// - public virtual RDFDataset ToRDF() - { - // TODO: make the default generateNodeMap call (i.e. without a - // graphName) create and return the nodeMap - JObject nodeMap = new JObject(); - nodeMap["@default"] = new JObject(); - GenerateNodeMap(this.value, nodeMap); - RDFDataset dataset = new RDFDataset(this); - foreach (string graphName in nodeMap.GetKeys()) - { - // 4.1) - if (JsonLdUtils.IsRelativeIri(graphName)) - { - continue; - } - JObject graph = (JObject)nodeMap[graphName - ]; - dataset.GraphToRDF(graphName, graph); - } - return dataset; - } + /// Performs RDF normalization on the given JSON-LD input. + /// Performs RDF normalization on the given JSON-LD input. + /// the expanded JSON-LD object to normalize. + /// the normalization options. + /// (err, normalized) called once the operation completes. + /// JSONLDProcessingError + /// + public virtual object Normalize(RDFDataset dataset) + { #if !PORTABLE - /// Performs RDF normalization on the given JSON-LD input. - /// Performs RDF normalization on the given JSON-LD input. - /// the expanded JSON-LD object to normalize. - /// the normalization options. - /// (err, normalized) called once the operation completes. - /// JSONLDProcessingError - /// - public virtual object Normalize(RDFDataset dataset) - { - // create quads and map bnodes to their associated quads - IList quads = new List(); - IDictionary> bnodes = new Dictionary>(); - foreach (string graphName in dataset.Keys) - { + // create quads and map bnodes to their associated quads + IList quads = new List(); + IDictionary> bnodes = new Dictionary>(); + foreach (string graphName in dataset.Keys) + { var eachGraphName = graphName; IList triples = (IList)dataset[eachGraphName]; - if ("@default".Equals(eachGraphName)) - { - eachGraphName = null; - } + if ("@default".Equals(eachGraphName)) + { + eachGraphName = null; + } foreach (RDFDataset.Quad quad in triples) - { - if (eachGraphName != null) - { - if (eachGraphName.IndexOf("_:") == 0) - { + { + if (eachGraphName != null) + { + if (eachGraphName.IndexOf("_:") == 0) + { IDictionary tmp = new Dictionary(); - tmp["type"] = "blank node"; - tmp["value"] = eachGraphName; - quad["name"] = tmp; - } - else - { + tmp["type"] = "blank node"; + tmp["value"] = eachGraphName; + quad["name"] = tmp; + } + else + { IDictionary tmp = new Dictionary(); - tmp["type"] = "IRI"; - tmp["value"] = eachGraphName; - quad["name"] = tmp; - } - } - quads.Add(quad); - string[] attrs = new string[] { "subject", "object", "name" }; - foreach (string attr in attrs) - { - if (quad.ContainsKey(attr) && (string)((IDictionary)quad[attr])["type"] == "blank node") - { + tmp["type"] = "IRI"; + tmp["value"] = eachGraphName; + quad["name"] = tmp; + } + } + quads.Add(quad); + string[] attrs = new string[] { "subject", "object", "name" }; + foreach (string attr in attrs) + { + if (quad.ContainsKey(attr) && (string)((IDictionary)quad[attr])["type"] == "blank node") + { string id = (string)((IDictionary)quad[attr])["value"]; - if (!bnodes.ContainsKey(id)) - { - bnodes[id] = new Dictionary { {"quads", new List()} }; - } - ((IList)bnodes[id]["quads"]).Add(quad); - } - } - } - } - // mapping complete, start canonical naming - NormalizeUtils normalizeUtils = new NormalizeUtils(quads, bnodes, new UniqueNamer - ("_:c14n"), opts); - return normalizeUtils.HashBlankNodes(bnodes.Keys); - } + if (!bnodes.ContainsKey(id)) + { + bnodes[id] = new Dictionary { {"quads", new List()} }; + } + ((IList)bnodes[id]["quads"]).Add(quad); + } + } + } + } + // mapping complete, start canonical naming + NormalizeUtils normalizeUtils = new NormalizeUtils(quads, bnodes, new UniqueNamer + ("_:c14n"), opts); + return normalizeUtils.HashBlankNodes(bnodes.Keys); +#else + throw new PlatformNotSupportedException(); #endif - } + } + } } diff --git a/src/JsonLD/Core/JsonLdError.cs b/src/JsonLD/Core/JsonLdError.cs index a036a6e..b0d27cb 100644 --- a/src/JsonLD/Core/JsonLdError.cs +++ b/src/JsonLD/Core/JsonLdError.cs @@ -5,192 +5,192 @@ namespace JsonLD.Core { - //[System.Serializable] - public class JsonLdError : Exception - { + //[System.Serializable] + public class JsonLdError : Exception + { internal JObject details; - private JsonLdError.Error type; + private JsonLdError.Error type; - public JsonLdError(JsonLdError.Error type, object detail) : base(detail == null ? - string.Empty : detail.ToString()) - { - // TODO: pretty toString (e.g. print whole json objects) - this.type = type; - } + public JsonLdError(JsonLdError.Error type, object detail) : base(detail == null ? + string.Empty : detail.ToString()) + { + // TODO: pretty toString (e.g. print whole json objects) + this.type = type; + } - public JsonLdError(JsonLdError.Error type) : base(string.Empty) - { - this.type = type; - } + public JsonLdError(JsonLdError.Error type) : base(string.Empty) + { + this.type = type; + } - //[System.Serializable] - public sealed class Error - { - public static readonly JsonLdError.Error LoadingDocumentFailed = new JsonLdError.Error - ("loading document failed"); + //[System.Serializable] + public sealed class Error + { + public static readonly JsonLdError.Error LoadingDocumentFailed = new JsonLdError.Error + ("loading document failed"); - public static readonly JsonLdError.Error ListOfLists = new JsonLdError.Error("list of lists" - ); + public static readonly JsonLdError.Error ListOfLists = new JsonLdError.Error("list of lists" + ); - public static readonly JsonLdError.Error InvalidIndexValue = new JsonLdError.Error - ("invalid @index value"); + public static readonly JsonLdError.Error InvalidIndexValue = new JsonLdError.Error + ("invalid @index value"); - public static readonly JsonLdError.Error ConflictingIndexes = new JsonLdError.Error - ("conflicting indexes"); + public static readonly JsonLdError.Error ConflictingIndexes = new JsonLdError.Error + ("conflicting indexes"); - public static readonly JsonLdError.Error InvalidIdValue = new JsonLdError.Error("invalid @id value" - ); + public static readonly JsonLdError.Error InvalidIdValue = new JsonLdError.Error("invalid @id value" + ); - public static readonly JsonLdError.Error InvalidLocalContext = new JsonLdError.Error - ("invalid local context"); + public static readonly JsonLdError.Error InvalidLocalContext = new JsonLdError.Error + ("invalid local context"); - public static readonly JsonLdError.Error MultipleContextLinkHeaders = new JsonLdError.Error - ("multiple context link headers"); + public static readonly JsonLdError.Error MultipleContextLinkHeaders = new JsonLdError.Error + ("multiple context link headers"); - public static readonly JsonLdError.Error LoadingRemoteContextFailed = new JsonLdError.Error - ("loading remote context failed"); + public static readonly JsonLdError.Error LoadingRemoteContextFailed = new JsonLdError.Error + ("loading remote context failed"); - public static readonly JsonLdError.Error InvalidRemoteContext = new JsonLdError.Error - ("invalid remote context"); + public static readonly JsonLdError.Error InvalidRemoteContext = new JsonLdError.Error + ("invalid remote context"); - public static readonly JsonLdError.Error RecursiveContextInclusion = new JsonLdError.Error - ("recursive context inclusion"); + public static readonly JsonLdError.Error RecursiveContextInclusion = new JsonLdError.Error + ("recursive context inclusion"); - public static readonly JsonLdError.Error InvalidBaseIri = new JsonLdError.Error("invalid base IRI" - ); + public static readonly JsonLdError.Error InvalidBaseIri = new JsonLdError.Error("invalid base IRI" + ); - public static readonly JsonLdError.Error InvalidVocabMapping = new JsonLdError.Error - ("invalid vocab mapping"); + public static readonly JsonLdError.Error InvalidVocabMapping = new JsonLdError.Error + ("invalid vocab mapping"); - public static readonly JsonLdError.Error InvalidDefaultLanguage = new JsonLdError.Error - ("invalid default language"); + public static readonly JsonLdError.Error InvalidDefaultLanguage = new JsonLdError.Error + ("invalid default language"); - public static readonly JsonLdError.Error KeywordRedefinition = new JsonLdError.Error - ("keyword redefinition"); + public static readonly JsonLdError.Error KeywordRedefinition = new JsonLdError.Error + ("keyword redefinition"); - public static readonly JsonLdError.Error InvalidTermDefinition = new JsonLdError.Error - ("invalid term definition"); + public static readonly JsonLdError.Error InvalidTermDefinition = new JsonLdError.Error + ("invalid term definition"); - public static readonly JsonLdError.Error InvalidReverseProperty = new JsonLdError.Error - ("invalid reverse property"); + public static readonly JsonLdError.Error InvalidReverseProperty = new JsonLdError.Error + ("invalid reverse property"); - public static readonly JsonLdError.Error InvalidIriMapping = new JsonLdError.Error - ("invalid IRI mapping"); + public static readonly JsonLdError.Error InvalidIriMapping = new JsonLdError.Error + ("invalid IRI mapping"); - public static readonly JsonLdError.Error CyclicIriMapping = new JsonLdError.Error - ("cyclic IRI mapping"); + public static readonly JsonLdError.Error CyclicIriMapping = new JsonLdError.Error + ("cyclic IRI mapping"); - public static readonly JsonLdError.Error InvalidKeywordAlias = new JsonLdError.Error - ("invalid keyword alias"); + public static readonly JsonLdError.Error InvalidKeywordAlias = new JsonLdError.Error + ("invalid keyword alias"); - public static readonly JsonLdError.Error InvalidTypeMapping = new JsonLdError.Error - ("invalid type mapping"); + public static readonly JsonLdError.Error InvalidTypeMapping = new JsonLdError.Error + ("invalid type mapping"); - public static readonly JsonLdError.Error InvalidLanguageMapping = new JsonLdError.Error - ("invalid language mapping"); + public static readonly JsonLdError.Error InvalidLanguageMapping = new JsonLdError.Error + ("invalid language mapping"); - public static readonly JsonLdError.Error CollidingKeywords = new JsonLdError.Error - ("colliding keywords"); + public static readonly JsonLdError.Error CollidingKeywords = new JsonLdError.Error + ("colliding keywords"); - public static readonly JsonLdError.Error InvalidContainerMapping = new JsonLdError.Error - ("invalid container mapping"); + public static readonly JsonLdError.Error InvalidContainerMapping = new JsonLdError.Error + ("invalid container mapping"); - public static readonly JsonLdError.Error InvalidTypeValue = new JsonLdError.Error - ("invalid type value"); + public static readonly JsonLdError.Error InvalidTypeValue = new JsonLdError.Error + ("invalid type value"); - public static readonly JsonLdError.Error InvalidValueObject = new JsonLdError.Error - ("invalid value object"); + public static readonly JsonLdError.Error InvalidValueObject = new JsonLdError.Error + ("invalid value object"); - public static readonly JsonLdError.Error InvalidValueObjectValue = new JsonLdError.Error - ("invalid value object value"); + public static readonly JsonLdError.Error InvalidValueObjectValue = new JsonLdError.Error + ("invalid value object value"); - public static readonly JsonLdError.Error InvalidLanguageTaggedString = new JsonLdError.Error - ("invalid language-tagged string"); + public static readonly JsonLdError.Error InvalidLanguageTaggedString = new JsonLdError.Error + ("invalid language-tagged string"); - public static readonly JsonLdError.Error InvalidLanguageTaggedValue = new JsonLdError.Error - ("invalid language-tagged value"); + public static readonly JsonLdError.Error InvalidLanguageTaggedValue = new JsonLdError.Error + ("invalid language-tagged value"); - public static readonly JsonLdError.Error InvalidTypedValue = new JsonLdError.Error - ("invalid typed value"); + public static readonly JsonLdError.Error InvalidTypedValue = new JsonLdError.Error + ("invalid typed value"); - public static readonly JsonLdError.Error InvalidSetOrListObject = new JsonLdError.Error - ("invalid set or list object"); + public static readonly JsonLdError.Error InvalidSetOrListObject = new JsonLdError.Error + ("invalid set or list object"); - public static readonly JsonLdError.Error InvalidLanguageMapValue = new JsonLdError.Error - ("invalid language map value"); + public static readonly JsonLdError.Error InvalidLanguageMapValue = new JsonLdError.Error + ("invalid language map value"); - public static readonly JsonLdError.Error CompactionToListOfLists = new JsonLdError.Error - ("compaction to list of lists"); + public static readonly JsonLdError.Error CompactionToListOfLists = new JsonLdError.Error + ("compaction to list of lists"); - public static readonly JsonLdError.Error InvalidReversePropertyMap = new JsonLdError.Error - ("invalid reverse property map"); + public static readonly JsonLdError.Error InvalidReversePropertyMap = new JsonLdError.Error + ("invalid reverse property map"); - public static readonly JsonLdError.Error InvalidReverseValue = new JsonLdError.Error - ("invalid @reverse value"); + public static readonly JsonLdError.Error InvalidReverseValue = new JsonLdError.Error + ("invalid @reverse value"); - public static readonly JsonLdError.Error InvalidReversePropertyValue = new JsonLdError.Error - ("invalid reverse property value"); + public static readonly JsonLdError.Error InvalidReversePropertyValue = new JsonLdError.Error + ("invalid reverse property value"); - public static readonly JsonLdError.Error SyntaxError = new JsonLdError.Error("syntax error" - ); + public static readonly JsonLdError.Error SyntaxError = new JsonLdError.Error("syntax error" + ); - public static readonly JsonLdError.Error NotImplemented = new JsonLdError.Error("not implemnted" - ); + public static readonly JsonLdError.Error NotImplemented = new JsonLdError.Error("not implemnted" + ); - public static readonly JsonLdError.Error UnknownFormat = new JsonLdError.Error("unknown format" - ); + public static readonly JsonLdError.Error UnknownFormat = new JsonLdError.Error("unknown format" + ); - public static readonly JsonLdError.Error InvalidInput = new JsonLdError.Error("invalid input" - ); + public static readonly JsonLdError.Error InvalidInput = new JsonLdError.Error("invalid input" + ); - public static readonly JsonLdError.Error ParseError = new JsonLdError.Error("parse error" - ); + public static readonly JsonLdError.Error ParseError = new JsonLdError.Error("parse error" + ); - public static readonly JsonLdError.Error UnknownError = new JsonLdError.Error("unknown error" - ); + public static readonly JsonLdError.Error UnknownError = new JsonLdError.Error("unknown error" + ); - private readonly string error; + private readonly string error; - private Error(string error) - { - // non spec related errors - this.error = error; - } + private Error(string error) + { + // non spec related errors + this.error = error; + } - public override string ToString() - { - return error; - } - } + public override string ToString() + { + return error; + } + } - public virtual JsonLdError SetType(JsonLdError.Error error) - { - this.type = error; - return this; - } + public virtual JsonLdError SetType(JsonLdError.Error error) + { + this.type = error; + return this; + } - public virtual JsonLdError.Error GetType() - { - return type; - } + public virtual JsonLdError.Error GetType() + { + return type; + } - public virtual JObject GetDetails() - { - return details; - } + public virtual JObject GetDetails() + { + return details; + } - public override string Message - { - get - { - string msg = base.Message; - if (msg != null && !string.Empty.Equals(msg)) - { - return type.ToString() + ": " + msg; - } - return type.ToString(); - } - } - } + public override string Message + { + get + { + string msg = base.Message; + if (msg != null && !string.Empty.Equals(msg)) + { + return type.ToString() + ": " + msg; + } + return type.ToString(); + } + } + } } diff --git a/src/JsonLD/Core/JsonLdOptions.cs b/src/JsonLD/Core/JsonLdOptions.cs index 3136b07..2478481 100644 --- a/src/JsonLD/Core/JsonLdOptions.cs +++ b/src/JsonLD/Core/JsonLdOptions.cs @@ -3,158 +3,158 @@ namespace JsonLD.Core { - /// http://json-ld.org/spec/latest/json-ld-api/#the-jsonldoptions-type - /// tristan - public class JsonLdOptions - { - public JsonLdOptions() - { - this.SetBase(string.Empty); - } + /// http://json-ld.org/spec/latest/json-ld-api/#the-jsonldoptions-type + /// tristan + public class JsonLdOptions + { + public JsonLdOptions() + { + this.SetBase(string.Empty); + } - public JsonLdOptions(string @base) - { - this.SetBase(@base); - } + public JsonLdOptions(string @base) + { + this.SetBase(@base); + } - public virtual JsonLD.Core.JsonLdOptions Clone() - { - JsonLD.Core.JsonLdOptions rval = new JsonLD.Core.JsonLdOptions(GetBase()); - return rval; - } + public virtual JsonLD.Core.JsonLdOptions Clone() + { + JsonLD.Core.JsonLdOptions rval = new JsonLD.Core.JsonLdOptions(GetBase()); + return rval; + } - private string @base = null; + private string @base = null; - private bool compactArrays = true; + private bool compactArrays = true; - private JObject expandContext = null; + private JObject expandContext = null; - private string processingMode = "json-ld-1.0"; + private string processingMode = "json-ld-1.0"; - private bool? embed = null; + private bool? embed = null; - private bool? @explicit = null; + private bool? @explicit = null; - private bool? omitDefault = null; + private bool? omitDefault = null; - internal bool useRdfType = false; + internal bool useRdfType = false; - internal bool useNativeTypes = false; + internal bool useNativeTypes = false; - private bool produceGeneralizedRdf = false; + private bool produceGeneralizedRdf = false; - // base options - // frame options - // rdf conversion options - public virtual bool? GetEmbed() - { - return embed; - } + // base options + // frame options + // rdf conversion options + public virtual bool? GetEmbed() + { + return embed; + } - public virtual void SetEmbed(bool? embed) - { - this.embed = embed; - } + public virtual void SetEmbed(bool? embed) + { + this.embed = embed; + } - public virtual bool? GetExplicit() - { - return @explicit; - } + public virtual bool? GetExplicit() + { + return @explicit; + } - public virtual void SetExplicit(bool? @explicit) - { - this.@explicit = @explicit; - } + public virtual void SetExplicit(bool? @explicit) + { + this.@explicit = @explicit; + } - public virtual bool? GetOmitDefault() - { - return omitDefault; - } + public virtual bool? GetOmitDefault() + { + return omitDefault; + } - public virtual void SetOmitDefault(bool? omitDefault) - { - this.omitDefault = omitDefault; - } + public virtual void SetOmitDefault(bool? omitDefault) + { + this.omitDefault = omitDefault; + } - public virtual bool GetCompactArrays() - { - return compactArrays; - } + public virtual bool GetCompactArrays() + { + return compactArrays; + } - public virtual void SetCompactArrays(bool compactArrays) - { - this.compactArrays = compactArrays; - } + public virtual void SetCompactArrays(bool compactArrays) + { + this.compactArrays = compactArrays; + } public virtual JObject GetExpandContext() - { - return expandContext; - } - - public virtual void SetExpandContext(JObject expandContext) - { - this.expandContext = expandContext; - } - - public virtual string GetProcessingMode() - { - return processingMode; - } - - public virtual void SetProcessingMode(string processingMode) - { - this.processingMode = processingMode; - } - - public virtual string GetBase() - { - return @base; - } - - public virtual void SetBase(string @base) - { - this.@base = @base; - } - - public virtual bool GetUseRdfType() - { - return useRdfType; - } - - public virtual void SetUseRdfType(bool useRdfType) - { - this.useRdfType = useRdfType; - } - - public virtual bool GetUseNativeTypes() - { - return useNativeTypes; - } - - public virtual void SetUseNativeTypes(bool useNativeTypes) - { - this.useNativeTypes = useNativeTypes; - } - - public virtual bool GetProduceGeneralizedRdf() - { - // TODO Auto-generated method stub - return this.produceGeneralizedRdf; - } - - public virtual void SetProduceGeneralizedRdf(bool produceGeneralizedRdf) - { - this.produceGeneralizedRdf = produceGeneralizedRdf; - } - - public string format = null; - - public bool useNamespaces = false; - - public string outputForm = null; - - public DocumentLoader documentLoader = new DocumentLoader(); - // TODO: THE FOLLOWING ONLY EXIST SO I DON'T HAVE TO DELETE A LOT OF CODE, - // REMOVE IT WHEN DONE - } + { + return expandContext; + } + + public virtual void SetExpandContext(JObject expandContext) + { + this.expandContext = expandContext; + } + + public virtual string GetProcessingMode() + { + return processingMode; + } + + public virtual void SetProcessingMode(string processingMode) + { + this.processingMode = processingMode; + } + + public virtual string GetBase() + { + return @base; + } + + public virtual void SetBase(string @base) + { + this.@base = @base; + } + + public virtual bool GetUseRdfType() + { + return useRdfType; + } + + public virtual void SetUseRdfType(bool useRdfType) + { + this.useRdfType = useRdfType; + } + + public virtual bool GetUseNativeTypes() + { + return useNativeTypes; + } + + public virtual void SetUseNativeTypes(bool useNativeTypes) + { + this.useNativeTypes = useNativeTypes; + } + + public virtual bool GetProduceGeneralizedRdf() + { + // TODO Auto-generated method stub + return this.produceGeneralizedRdf; + } + + public virtual void SetProduceGeneralizedRdf(bool produceGeneralizedRdf) + { + this.produceGeneralizedRdf = produceGeneralizedRdf; + } + + public string format = null; + + public bool useNamespaces = false; + + public string outputForm = null; + + public DocumentLoader documentLoader = new DocumentLoader(); + // TODO: THE FOLLOWING ONLY EXIST SO I DON'T HAVE TO DELETE A LOT OF CODE, + // REMOVE IT WHEN DONE + } } diff --git a/src/JsonLD/Core/JsonLdProcessor.cs b/src/JsonLD/Core/JsonLdProcessor.cs index 630d31f..b5a7eab 100644 --- a/src/JsonLD/Core/JsonLdProcessor.cs +++ b/src/JsonLD/Core/JsonLdProcessor.cs @@ -7,479 +7,485 @@ namespace JsonLD.Core { - /// http://json-ld.org/spec/latest/json-ld-api/#the-jsonldprocessor-interface - /// - /// tristan - public class JsonLdProcessor - { - /// + /// http://json-ld.org/spec/latest/json-ld-api/#the-jsonldprocessor-interface + /// + /// tristan + public class JsonLdProcessor + { + /// public static JObject Compact(JToken input, JToken context, JsonLdOptions - opts) - { - // 1) - // TODO: look into java futures/promises - // 2-6) NOTE: these are all the same steps as in expand - JToken expanded = Expand(input, opts); - // 7) - if (context is JObject && ((IDictionary)context).ContainsKey( - "@context")) - { - context = ((JObject)context)["@context"]; - } - Context activeCtx = new Context(opts); - activeCtx = activeCtx.Parse(context); - // 8) - JToken compacted = new JsonLdApi(opts).Compact(activeCtx, null, expanded, opts.GetCompactArrays - ()); - // final step of Compaction Algorithm - // TODO: SPEC: the result result is a NON EMPTY array, - if (compacted is JArray) - { - if (((JArray)compacted).IsEmpty()) - { - compacted = new JObject(); - } - else - { - JObject tmp = new JObject(); - // TODO: SPEC: doesn't specify to use vocab = true here - tmp[activeCtx.CompactIri("@graph", true)] = compacted; - compacted = tmp; - } - } - if (!compacted.IsNull() && !context.IsNull()) - { - // TODO: figure out if we can make "@context" appear at the start of - // the keySet - if ((context is JObject && !((JObject)context).IsEmpty()) - || (context is JArray && !((JArray)context).IsEmpty())) - { - compacted["@context"] = context; - } - } - // 9) - return (JObject)compacted; - } + opts) + { + // 1) + // TODO: look into java futures/promises + // 2-6) NOTE: these are all the same steps as in expand + JToken expanded = Expand(input, opts); + // 7) + if (context is JObject && ((IDictionary)context).ContainsKey( + "@context")) + { + context = ((JObject)context)["@context"]; + } + Context activeCtx = new Context(opts); + activeCtx = activeCtx.Parse(context); + // 8) + JToken compacted = new JsonLdApi(opts).Compact(activeCtx, null, expanded, opts.GetCompactArrays + ()); + // final step of Compaction Algorithm + // TODO: SPEC: the result result is a NON EMPTY array, + if (compacted is JArray) + { + if (((JArray)compacted).IsEmpty()) + { + compacted = new JObject(); + } + else + { + JObject tmp = new JObject(); + // TODO: SPEC: doesn't specify to use vocab = true here + tmp[activeCtx.CompactIri("@graph", true)] = compacted; + compacted = tmp; + } + } + if (!compacted.IsNull() && !context.IsNull()) + { + // TODO: figure out if we can make "@context" appear at the start of + // the keySet + if ((context is JObject && !((JObject)context).IsEmpty()) + || (context is JArray && !((JArray)context).IsEmpty())) + { + compacted["@context"] = context; + } + } + // 9) + return (JObject)compacted; + } - /// - public static JArray Expand(JToken input, JsonLdOptions opts) - { - // 1) - // TODO: look into java futures/promises - // 2) TODO: better verification of DOMString IRI - if (input.Type == JTokenType.String && ((string)input).Contains(":")) - { - try - { + /// + public static JArray Expand(JToken input, JsonLdOptions opts) + { + // 1) + // TODO: look into java futures/promises + // 2) TODO: better verification of DOMString IRI + if (input.Type == JTokenType.String && ((string)input).Contains(":")) + { + try + { RemoteDocument tmp = opts.documentLoader.LoadDocument((string)input); - input = tmp.document; - } - catch (Exception e) - { - // TODO: figure out how to deal with remote context - throw new JsonLdError(JsonLdError.Error.LoadingDocumentFailed, e.Message); - } - // if set the base in options should override the base iri in the - // active context - // thus only set this as the base iri if it's not already set in - // options - if (opts.GetBase() == null) - { - opts.SetBase((string)input); - } - } - // 3) - Context activeCtx = new Context(opts); - // 4) - if (opts.GetExpandContext() != null) - { - JObject exCtx = opts.GetExpandContext(); - if (exCtx is JObject && ((IDictionary)exCtx).ContainsKey("@context" - )) - { + input = tmp.document; + } + catch (Exception e) + { + // TODO: figure out how to deal with remote context + throw new JsonLdError(JsonLdError.Error.LoadingDocumentFailed, e.Message); + } + // if set the base in options should override the base iri in the + // active context + // thus only set this as the base iri if it's not already set in + // options + if (opts.GetBase() == null) + { + opts.SetBase((string)input); + } + } + // 3) + Context activeCtx = new Context(opts); + // 4) + if (opts.GetExpandContext() != null) + { + JObject exCtx = opts.GetExpandContext(); + if (exCtx is JObject && ((IDictionary)exCtx).ContainsKey("@context" + )) + { exCtx = (JObject)((IDictionary)exCtx)["@context"]; - } - activeCtx = activeCtx.Parse(exCtx); - } - // 5) - // TODO: add support for getting a context from HTTP when content-type - // is set to a jsonld compatable format - // 6) - JToken expanded = new JsonLdApi(opts).Expand(activeCtx, input); - // final step of Expansion Algorithm - if (expanded is JObject && ((IDictionary)expanded).ContainsKey("@graph") && ( + } + activeCtx = activeCtx.Parse(exCtx); + } + // 5) + // TODO: add support for getting a context from HTTP when content-type + // is set to a jsonld compatable format + // 6) + JToken expanded = new JsonLdApi(opts).Expand(activeCtx, input); + // final step of Expansion Algorithm + if (expanded is JObject && ((IDictionary)expanded).ContainsKey("@graph") && ( (IDictionary)expanded).Count == 1) - { - expanded = ((JObject)expanded)["@graph"]; - } - else - { - if (expanded.IsNull()) - { - expanded = new JArray(); - } - } - // normalize to an array - if (!(expanded is JArray)) - { - JArray tmp = new JArray(); - tmp.Add(expanded); - expanded = tmp; - } - return (JArray)expanded; - } + { + expanded = ((JObject)expanded)["@graph"]; + } + else + { + if (expanded.IsNull()) + { + expanded = new JArray(); + } + } + // normalize to an array + if (!(expanded is JArray)) + { + JArray tmp = new JArray(); + tmp.Add(expanded); + expanded = tmp; + } + return (JArray)expanded; + } - /// - public static JArray Expand(JToken input) - { - return Expand(input, new JsonLdOptions(string.Empty)); - } + /// + public static JArray Expand(JToken input) + { + return Expand(input, new JsonLdOptions(string.Empty)); + } - /// + /// public static JToken Flatten(JToken input, JToken context, JsonLdOptions opts) - { - // 2-6) NOTE: these are all the same steps as in expand + { + // 2-6) NOTE: these are all the same steps as in expand JArray expanded = Expand(input, opts); - // 7) - if (context is JObject && ((IDictionary)context).ContainsKey( - "@context")) - { - context = context["@context"]; - } - // 8) NOTE: blank node generation variables are members of JsonLdApi - // 9) NOTE: the next block is the Flattening Algorithm described in - // http://json-ld.org/spec/latest/json-ld-api/#flattening-algorithm - // 1) - JObject nodeMap = new JObject(); - nodeMap["@default"] = new JObject(); - // 2) - new JsonLdApi(opts).GenerateNodeMap(expanded, nodeMap); - // 3) - JObject defaultGraph = (JObject)JsonLD.Collections.Remove - (nodeMap, "@default"); - // 4) - foreach (string graphName in nodeMap.GetKeys()) - { - JObject graph = (JObject)nodeMap[graphName]; - // 4.1+4.2) - JObject entry; - if (!defaultGraph.ContainsKey(graphName)) - { - entry = new JObject(); - entry["@id"] = graphName; - defaultGraph[graphName] = entry; - } - else - { - entry = (JObject)defaultGraph[graphName]; - } - // 4.3) - // TODO: SPEC doesn't specify that this should only be added if it - // doesn't exists - if (!entry.ContainsKey("@graph")) - { - entry["@graph"] = new JArray(); - } - JArray keys = new JArray(graph.GetKeys()); - keys.SortInPlace(); - foreach (string id in keys) - { - JObject node = (JObject)graph[id]; - if (!(node.ContainsKey("@id") && node.Count == 1)) - { - ((JArray)entry["@graph"]).Add(node); - } - } - } - // 5) - JArray flattened = new JArray(); - // 6) - JArray keys_1 = new JArray(defaultGraph.GetKeys()); - keys_1.SortInPlace(); - foreach (string id_1 in keys_1) - { - JObject node = (JObject)defaultGraph[id_1 - ]; - if (!(node.ContainsKey("@id") && node.Count == 1)) - { - flattened.Add(node); - } - } - // 8) - if (!context.IsNull() && !flattened.IsEmpty()) - { - Context activeCtx = new Context(opts); - activeCtx = activeCtx.Parse(context); - // TODO: only instantiate one jsonldapi - JToken compacted = new JsonLdApi(opts).Compact(activeCtx, null, flattened, opts.GetCompactArrays - ()); - if (!(compacted is JArray)) - { - JArray tmp = new JArray(); - tmp.Add(compacted); - compacted = tmp; - } - string alias = activeCtx.CompactIri("@graph"); - JObject rval = activeCtx.Serialize(); - rval[alias] = compacted; - return rval; - } - return flattened; - } + // 7) + if (context is JObject && ((IDictionary)context).ContainsKey( + "@context")) + { + context = context["@context"]; + } + // 8) NOTE: blank node generation variables are members of JsonLdApi + // 9) NOTE: the next block is the Flattening Algorithm described in + // http://json-ld.org/spec/latest/json-ld-api/#flattening-algorithm + // 1) + JObject nodeMap = new JObject(); + nodeMap["@default"] = new JObject(); + // 2) + new JsonLdApi(opts).GenerateNodeMap(expanded, nodeMap); + // 3) + JObject defaultGraph = (JObject)JsonLD.Collections.Remove + (nodeMap, "@default"); + // 4) + foreach (string graphName in nodeMap.GetKeys()) + { + JObject graph = (JObject)nodeMap[graphName]; + // 4.1+4.2) + JObject entry; + if (!defaultGraph.ContainsKey(graphName)) + { + entry = new JObject(); + entry["@id"] = graphName; + defaultGraph[graphName] = entry; + } + else + { + entry = (JObject)defaultGraph[graphName]; + } + // 4.3) + // TODO: SPEC doesn't specify that this should only be added if it + // doesn't exists + if (!entry.ContainsKey("@graph")) + { + entry["@graph"] = new JArray(); + } + JArray keys = new JArray(graph.GetKeys()); + keys.SortInPlace(); + foreach (string id in keys) + { + JObject node = (JObject)graph[id]; + if (!(node.ContainsKey("@id") && node.Count == 1)) + { + ((JArray)entry["@graph"]).Add(node); + } + } + } + // 5) + JArray flattened = new JArray(); + // 6) + JArray keys_1 = new JArray(defaultGraph.GetKeys()); + keys_1.SortInPlace(); + foreach (string id_1 in keys_1) + { + JObject node = (JObject)defaultGraph[id_1 + ]; + if (!(node.ContainsKey("@id") && node.Count == 1)) + { + flattened.Add(node); + } + } + // 8) + if (!context.IsNull() && !flattened.IsEmpty()) + { + Context activeCtx = new Context(opts); + activeCtx = activeCtx.Parse(context); + // TODO: only instantiate one jsonldapi + JToken compacted = new JsonLdApi(opts).Compact(activeCtx, null, flattened, opts.GetCompactArrays + ()); + if (!(compacted is JArray)) + { + JArray tmp = new JArray(); + tmp.Add(compacted); + compacted = tmp; + } + string alias = activeCtx.CompactIri("@graph"); + JObject rval = activeCtx.Serialize(); + rval[alias] = compacted; + return rval; + } + return flattened; + } - /// + /// public static JToken Flatten(JToken input, JsonLdOptions opts) - { - return Flatten(input, null, opts); - } + { + return Flatten(input, null, opts); + } - /// + /// public static JObject Frame(JToken input, JToken frame, JsonLdOptions - options) - { - if (frame is JObject) - { - frame = JsonLdUtils.Clone((JObject)frame); - } - // TODO string/IO input - JToken expandedInput = Expand(input, options); - JArray expandedFrame = Expand(frame, options); - JsonLdApi api = new JsonLdApi(expandedInput, options); - JArray framed = api.Frame(expandedInput, expandedFrame); - Context activeCtx = api.context.Parse(frame["@context" - ]); - JToken compacted = api.Compact(activeCtx, null, framed); - if (!(compacted is JArray)) - { + options) + { + if (frame is JObject) + { + frame = JsonLdUtils.Clone((JObject)frame); + } + // TODO string/IO input + JToken expandedInput = Expand(input, options); + JArray expandedFrame = Expand(frame, options); + JsonLdApi api = new JsonLdApi(expandedInput, options); + JArray framed = api.Frame(expandedInput, expandedFrame); + Context activeCtx = api.context.Parse(frame["@context" + ]); + JToken compacted = api.Compact(activeCtx, null, framed); + if (!(compacted is JArray)) + { JArray tmp = new JArray(); - tmp.Add(compacted); - compacted = tmp; - } - string alias = activeCtx.CompactIri("@graph"); - JObject rval = activeCtx.Serialize(); - rval[alias] = compacted; - JsonLdUtils.RemovePreserve(activeCtx, rval, options); - return rval; - } + tmp.Add(compacted); + compacted = tmp; + } + string alias = activeCtx.CompactIri("@graph"); + JObject rval = activeCtx.Serialize(); + rval[alias] = compacted; + JsonLdUtils.RemovePreserve(activeCtx, rval, options); + return rval; + } - private sealed class _Dictionary_242 : Dictionary - { - public _Dictionary_242() - { - { - // automatically register nquad serializer - this["application/nquads"] = new NQuadRDFParser(); - this["text/turtle"] = new TurtleRDFParser(); - } - } - } + private sealed class _Dictionary_242 : Dictionary + { + public _Dictionary_242() + { + { + // automatically register nquad serializer + this["application/nquads"] = new NQuadRDFParser(); + this["text/turtle"] = new TurtleRDFParser(); + } + } + } - /// - /// a registry for RDF Parsers (in this case, JSONLDSerializers) used by - /// fromRDF if no specific serializer is specified and options.format is set. - /// - /// - /// a registry for RDF Parsers (in this case, JSONLDSerializers) used by - /// fromRDF if no specific serializer is specified and options.format is set. - /// TODO: this would fit better in the document loader class - /// - private static IDictionary rdfParsers = new _Dictionary_242(); + /// + /// a registry for RDF Parsers (in this case, JSONLDSerializers) used by + /// fromRDF if no specific serializer is specified and options.format is set. + /// + /// + /// a registry for RDF Parsers (in this case, JSONLDSerializers) used by + /// fromRDF if no specific serializer is specified and options.format is set. + /// TODO: this would fit better in the document loader class + /// + private static IDictionary rdfParsers = new _Dictionary_242(); - public static void RegisterRDFParser(string format, IRDFParser parser) - { - rdfParsers[format] = parser; - } + public static void RegisterRDFParser(string format, IRDFParser parser) + { + rdfParsers[format] = parser; + } - public static void RemoveRDFParser(string format) - { - JsonLD.Collections.Remove(rdfParsers, format); - } + public static void RemoveRDFParser(string format) + { + JsonLD.Collections.Remove(rdfParsers, format); + } - /// Converts an RDF dataset to JSON-LD. - /// Converts an RDF dataset to JSON-LD. - /// - /// a serialized string of RDF in a format specified by the format - /// option or an RDF dataset to convert. - /// - /// - /// (err, output) called once the operation completes. - /// + /// Converts an RDF dataset to JSON-LD. + /// Converts an RDF dataset to JSON-LD. + /// + /// a serialized string of RDF in a format specified by the format + /// option or an RDF dataset to convert. + /// + /// + /// (err, output) called once the operation completes. + /// public static JToken FromRDF(JToken dataset, JsonLdOptions options) - { - // handle non specified serializer case - IRDFParser parser = null; - if (options.format == null && dataset.Type == JTokenType.String) - { - // attempt to parse the input as nquads - options.format = "application/nquads"; - } - if (rdfParsers.ContainsKey(options.format)) - { - parser = rdfParsers[options.format]; - } - else - { - throw new JsonLdError(JsonLdError.Error.UnknownFormat, options.format); - } - // convert from RDF - return FromRDF(dataset, options, parser); - } + { + // handle non specified serializer case + IRDFParser parser = null; + if (options.format == null && dataset.Type == JTokenType.String) + { + // attempt to parse the input as nquads + options.format = "application/nquads"; + } + if (rdfParsers.ContainsKey(options.format)) + { + parser = rdfParsers[options.format]; + } + else + { + throw new JsonLdError(JsonLdError.Error.UnknownFormat, options.format); + } + // convert from RDF + return FromRDF(dataset, options, parser); + } - /// + /// public static JToken FromRDF(JToken dataset) - { - return FromRDF(dataset, new JsonLdOptions(string.Empty)); - } + { + return FromRDF(dataset, new JsonLdOptions(string.Empty)); + } - /// Uses a specific serializer. - /// Uses a specific serializer. - /// + /// Uses a specific serializer. + /// Uses a specific serializer. + /// public static JToken FromRDF(JToken input, JsonLdOptions options, IRDFParser parser - ) - { - RDFDataset dataset = parser.Parse(input); - // convert from RDF - JToken rval = new JsonLdApi(options).FromRDF(dataset); - // re-process using the generated context if outputForm is set - if (options.outputForm != null) - { - if ("expanded".Equals(options.outputForm)) - { - return rval; - } - else - { - if ("compacted".Equals(options.outputForm)) - { - return Compact(rval, dataset.GetContext(), options); - } - else - { - if ("flattened".Equals(options.outputForm)) - { - return Flatten(rval, dataset.GetContext(), options); - } - else - { - throw new JsonLdError(JsonLdError.Error.UnknownError); - } - } - } - } - return rval; - } + ) + { + RDFDataset dataset = parser.Parse(input); + // convert from RDF + JToken rval = new JsonLdApi(options).FromRDF(dataset); + // re-process using the generated context if outputForm is set + if (options.outputForm != null) + { + if ("expanded".Equals(options.outputForm)) + { + return rval; + } + else + { + if ("compacted".Equals(options.outputForm)) + { + return Compact(rval, dataset.GetContext(), options); + } + else + { + if ("flattened".Equals(options.outputForm)) + { + return Flatten(rval, dataset.GetContext(), options); + } + else + { + throw new JsonLdError(JsonLdError.Error.UnknownError); + } + } + } + } + return rval; + } - /// + /// public static JToken FromRDF(JToken input, IRDFParser parser) - { - return FromRDF(input, new JsonLdOptions(string.Empty), parser); - } + { + return FromRDF(input, new JsonLdOptions(string.Empty), parser); + } - /// Outputs the RDF dataset found in the given JSON-LD object. - /// Outputs the RDF dataset found in the given JSON-LD object. - /// the JSON-LD input. - /// - /// A callback that is called when the input has been converted to - /// Quads (null to use options.format instead). - /// - /// - /// (err, dataset) called once the operation completes. - /// - public static object ToRDF(JToken input, IJSONLDTripleCallback callback, JsonLdOptions - options) - { - JToken expandedInput = Expand(input, options); - JsonLdApi api = new JsonLdApi(expandedInput, options); - RDFDataset dataset = api.ToRDF(); - // generate namespaces from context - if (options.useNamespaces) - { - JArray _input; + /// Outputs the RDF dataset found in the given JSON-LD object. + /// Outputs the RDF dataset found in the given JSON-LD object. + /// the JSON-LD input. + /// + /// A callback that is called when the input has been converted to + /// Quads (null to use options.format instead). + /// + /// + /// (err, dataset) called once the operation completes. + /// + public static object ToRDF(JToken input, IJSONLDTripleCallback callback, JsonLdOptions + options) + { + JToken expandedInput = Expand(input, options); + JsonLdApi api = new JsonLdApi(expandedInput, options); + RDFDataset dataset = api.ToRDF(); + // generate namespaces from context + if (options.useNamespaces) + { + JArray _input; if (input is JArray) - { + { _input = (JArray)input; - } - else - { + } + else + { _input = new JArray(); - _input.Add((JObject)input); - } - foreach (JToken e in _input) - { - if (((JObject)e).ContainsKey("@context")) - { - dataset.ParseContext((JObject)e["@context"]); - } - } - } - if (callback != null) - { - return callback.Call(dataset); - } - if (options.format != null) - { - if ("application/nquads".Equals(options.format)) - { - return new NQuadTripleCallback().Call(dataset); - } - else - { - if ("text/turtle".Equals(options.format)) - { - return new TurtleTripleCallback().Call(dataset); - } - else - { - throw new JsonLdError(JsonLdError.Error.UnknownFormat, options.format); - } - } - } - return dataset; - } + _input.Add((JObject)input); + } + foreach (JToken e in _input) + { + if (((JObject)e).ContainsKey("@context")) + { + dataset.ParseContext((JObject)e["@context"]); + } + } + } + if (callback != null) + { + return callback.Call(dataset); + } + if (options.format != null) + { + if ("application/nquads".Equals(options.format)) + { + return new NQuadTripleCallback().Call(dataset); + } + else + { + if ("text/turtle".Equals(options.format)) + { + return new TurtleTripleCallback().Call(dataset); + } + else + { + throw new JsonLdError(JsonLdError.Error.UnknownFormat, options.format); + } + } + } + return dataset; + } - /// + /// public static object ToRDF(JToken input, JsonLdOptions options) - { - return ToRDF(input, null, options); - } + { + return ToRDF(input, null, options); + } - /// + /// public static object ToRDF(JToken input, IJSONLDTripleCallback callback) - { - return ToRDF(input, callback, new JsonLdOptions(string.Empty)); - } + { + return ToRDF(input, callback, new JsonLdOptions(string.Empty)); + } - /// + /// public static object ToRDF(JToken input) - { - return ToRDF(input, new JsonLdOptions(string.Empty)); - } + { + return ToRDF(input, new JsonLdOptions(string.Empty)); + } -#if !PORTABLE - /// Performs RDF dataset normalization on the given JSON-LD input. - /// - /// Performs RDF dataset normalization on the given JSON-LD input. The output - /// is an RDF dataset unless the 'format' option is used. - /// - /// the JSON-LD input to normalize. - /// - /// (err, normalized) called once the operation completes. - /// JSONLDProcessingError - /// + + /// Performs RDF dataset normalization on the given JSON-LD input. + /// + /// Performs RDF dataset normalization on the given JSON-LD input. The output + /// is an RDF dataset unless the 'format' option is used. + /// + /// the JSON-LD input to normalize. + /// + /// (err, normalized) called once the operation completes. + /// JSONLDProcessingError + /// public static object Normalize(JToken input, JsonLdOptions options) - { - JsonLdOptions opts = options.Clone(); - opts.format = null; - RDFDataset dataset = (RDFDataset)ToRDF(input, opts); - return new JsonLdApi(options).Normalize(dataset); - } + { +#if !PORTABLE + JsonLdOptions opts = options.Clone(); + opts.format = null; + RDFDataset dataset = (RDFDataset)ToRDF(input, opts); + return new JsonLdApi(options).Normalize(dataset); +#else + throw new PlatformNotSupportedException(); +#endif + } - /// + /// public static object Normalize(JToken input) - { - return Normalize(input, new JsonLdOptions(string.Empty)); - } - + { +#if !PORTABLE + return Normalize(input, new JsonLdOptions(string.Empty)); +#else + throw new PlatformNotSupportedException(); #endif - } + } + } } diff --git a/src/JsonLD/Core/JsonLdUtils.cs b/src/JsonLD/Core/JsonLdUtils.cs index dc0add0..e8d466e 100644 --- a/src/JsonLD/Core/JsonLdUtils.cs +++ b/src/JsonLD/Core/JsonLdUtils.cs @@ -8,9 +8,9 @@ namespace JsonLD.Core { - public class JsonLdUtils - { - private const int MaxContextUrls = 10; + public class JsonLdUtils + { + private const int MaxContextUrls = 10; private static readonly IList keywords = new[] { "@base", @@ -33,911 +33,911 @@ public class JsonLdUtils "@vocab" }; - /// Returns whether or not the given value is a keyword (or a keyword alias). - /// - /// Returns whether or not the given value is a keyword (or a keyword alias). - /// - /// the value to check. - /// - /// true if the value is a keyword, false if not. - internal static bool IsKeyword(JToken key) - { - if (!IsString(key)) - { - return false; - } + /// Returns whether or not the given value is a keyword (or a keyword alias). + /// + /// Returns whether or not the given value is a keyword (or a keyword alias). + /// + /// the value to check. + /// + /// true if the value is a keyword, false if not. + internal static bool IsKeyword(JToken key) + { + if (!IsString(key)) + { + return false; + } var keyString = (string)key; return keywords.Contains(keyString); - } + } - public static bool DeepCompare(JToken v1, JToken v2, bool listOrderMatters) - { - if (v1 == null) - { - return v2 == null; - } - else - { - if (v2 == null) - { - return v1 == null; - } - else - { - if (v1 is JObject && v2 is JObject) - { + public static bool DeepCompare(JToken v1, JToken v2, bool listOrderMatters) + { + if (v1 == null) + { + return v2 == null; + } + else + { + if (v2 == null) + { + return v1 == null; + } + else + { + if (v1 is JObject && v2 is JObject) + { JObject m1 = (JObject)v1; JObject m2 = (JObject)v2; - if (m1.Count != m2.Count) - { - return false; - } - foreach (string key in m1.GetKeys()) - { - if (!((IDictionary)m2).ContainsKey(key) || + if (m1.Count != m2.Count) + { + return false; + } + foreach (string key in m1.GetKeys()) + { + if (!((IDictionary)m2).ContainsKey(key) || !DeepCompare(m1[key], m2[key], listOrderMatters)) - { - return false; - } - } - return true; - } - else - { + { + return false; + } + } + return true; + } + else + { if (v1 is JArray && v2 is JArray) - { + { JArray l1 = (JArray)v1; JArray l2 = (JArray)v2; - if (l1.Count != l2.Count) - { - return false; - } - // used to mark members of l2 that we have already matched to avoid - // matching the same item twice for lists that have duplicates - bool[] alreadyMatched = new bool[l2.Count]; - for (int i = 0; i < l1.Count; i++) - { - JToken o1 = l1[i]; - bool gotmatch = false; - if (listOrderMatters) - { - gotmatch = DeepCompare(o1, l2[i], listOrderMatters); - } - else - { - for (int j = 0; j < l2.Count; j++) - { - if (!alreadyMatched[j] && DeepCompare(o1, l2[j], listOrderMatters)) - { - alreadyMatched[j] = true; - gotmatch = true; - break; - } - } - } - if (!gotmatch) - { - return false; - } - } - return true; - } - else - { - return v1.Equals(v2); - } - } - } - } - } + if (l1.Count != l2.Count) + { + return false; + } + // used to mark members of l2 that we have already matched to avoid + // matching the same item twice for lists that have duplicates + bool[] alreadyMatched = new bool[l2.Count]; + for (int i = 0; i < l1.Count; i++) + { + JToken o1 = l1[i]; + bool gotmatch = false; + if (listOrderMatters) + { + gotmatch = DeepCompare(o1, l2[i], listOrderMatters); + } + else + { + for (int j = 0; j < l2.Count; j++) + { + if (!alreadyMatched[j] && DeepCompare(o1, l2[j], listOrderMatters)) + { + alreadyMatched[j] = true; + gotmatch = true; + break; + } + } + } + if (!gotmatch) + { + return false; + } + } + return true; + } + else + { + return v1.Equals(v2); + } + } + } + } + } public static bool DeepCompare(JToken v1, JToken v2) - { - return DeepCompare(v1, v2, false); - } + { + return DeepCompare(v1, v2, false); + } - public static bool DeepContains(JArray values, JToken value) - { - foreach (JToken item in values) - { - if (DeepCompare(item, value, false)) - { - return true; - } - } - return false; - } + public static bool DeepContains(JArray values, JToken value) + { + foreach (JToken item in values) + { + if (DeepCompare(item, value, false)) + { + return true; + } + } + return false; + } - internal static void MergeValue(JObject obj, string key, JToken - value) - { - if (obj == null) - { - return; - } - JArray values = (JArray)obj[key]; - if (values == null) - { - values = new JArray(); - obj[key] = values; - } - if ("@list".Equals(key) || (value is JObject && ((IDictionary - )value).ContainsKey("@list")) || !DeepContains(values, (JToken)value)) - { - values.Add(value); - } - } + internal static void MergeValue(JObject obj, string key, JToken + value) + { + if (obj == null) + { + return; + } + JArray values = (JArray)obj[key]; + if (values == null) + { + values = new JArray(); + obj[key] = values; + } + if ("@list".Equals(key) || (value is JObject && ((IDictionary + )value).ContainsKey("@list")) || !DeepContains(values, (JToken)value)) + { + values.Add(value); + } + } - internal static void MergeCompactedValue(JObject obj, string - key, JToken value) - { - if (obj == null) - { - return; - } - JToken prop = obj[key]; - if (prop.IsNull()) - { - obj[key] = value; - return; - } - if (!(prop is JArray)) - { + internal static void MergeCompactedValue(JObject obj, string + key, JToken value) + { + if (obj == null) + { + return; + } + JToken prop = obj[key]; + if (prop.IsNull()) + { + obj[key] = value; + return; + } + if (!(prop is JArray)) + { JArray tmp = new JArray(); - tmp.Add(prop); - } + tmp.Add(prop); + } if (value is JArray) - { + { JsonLD.Collections.AddAll(((JArray)prop), (JArray)value); - } - else - { + } + else + { ((JArray)prop).Add(value); - } - } + } + } - public static bool IsAbsoluteIri(string value) - { - // TODO: this is a bit simplistic! - return value.Contains(":"); - } + public static bool IsAbsoluteIri(string value) + { + // TODO: this is a bit simplistic! + return value.Contains(":"); + } - /// Returns true if the given value is a subject with properties. - /// Returns true if the given value is a subject with properties. - /// the value to check. - /// true if the value is a subject with properties, false if not. - internal static bool IsNode(JToken v) - { - // Note: A value is a subject if all of these hold true: - // 1. It is an Object. - // 2. It is not a @value, @set, or @list. - // 3. It has more than 1 key OR any existing key is not @id. + /// Returns true if the given value is a subject with properties. + /// Returns true if the given value is a subject with properties. + /// the value to check. + /// true if the value is a subject with properties, false if not. + internal static bool IsNode(JToken v) + { + // Note: A value is a subject if all of these hold true: + // 1. It is an Object. + // 2. It is not a @value, @set, or @list. + // 3. It has more than 1 key OR any existing key is not @id. if (v is JObject && !(((IDictionary)v).ContainsKey("@value") || ((IDictionary )v).ContainsKey("@set") || ((IDictionary)v).ContainsKey("@list"))) - { + { return ((IDictionary)v).Count > 1 || !((IDictionary)v).ContainsKey - ("@id"); - } - return false; - } + ("@id"); + } + return false; + } - /// Returns true if the given value is a subject reference. - /// Returns true if the given value is a subject reference. - /// the value to check. - /// true if the value is a subject reference, false if not. - internal static bool IsNodeReference(JToken v) - { - // Note: A value is a subject reference if all of these hold true: - // 1. It is an Object. - // 2. It has a single key: @id. + /// Returns true if the given value is a subject reference. + /// Returns true if the given value is a subject reference. + /// the value to check. + /// true if the value is a subject reference, false if not. + internal static bool IsNodeReference(JToken v) + { + // Note: A value is a subject reference if all of these hold true: + // 1. It is an Object. + // 2. It has a single key: @id. return (v is JObject && ((IDictionary)v).Count == 1 && ((IDictionary )v).ContainsKey("@id")); - } + } - // TODO: fix this test - public static bool IsRelativeIri(string value) - { - if (!(IsKeyword(value) || IsAbsoluteIri(value))) - { - return true; - } - return false; - } + // TODO: fix this test + public static bool IsRelativeIri(string value) + { + if (!(IsKeyword(value) || IsAbsoluteIri(value))) + { + return true; + } + return false; + } - // //////////////////////////////////////////////////// OLD CODE BELOW - /// Adds a value to a subject. - /// - /// Adds a value to a subject. If the value is an array, all values in the - /// array will be added. - /// Note: If the value is a subject that already exists as a property of the - /// given subject, this method makes no attempt to deeply merge properties. - /// Instead, the value will not be added. - /// - /// the subject to add the value to. - /// the property that relates the value to the subject. - /// the value to add. - /// - /// - internal static void AddValue(JObject subject, string property - , JToken value, bool propertyIsArray, bool allowDuplicate) - { - if (IsArray(value)) - { - if (((JArray)value).Count == 0 && propertyIsArray && !subject.ContainsKey(property - )) - { - subject[property] = new JArray(); - } + // //////////////////////////////////////////////////// OLD CODE BELOW + /// Adds a value to a subject. + /// + /// Adds a value to a subject. If the value is an array, all values in the + /// array will be added. + /// Note: If the value is a subject that already exists as a property of the + /// given subject, this method makes no attempt to deeply merge properties. + /// Instead, the value will not be added. + /// + /// the subject to add the value to. + /// the property that relates the value to the subject. + /// the value to add. + /// + /// + internal static void AddValue(JObject subject, string property + , JToken value, bool propertyIsArray, bool allowDuplicate) + { + if (IsArray(value)) + { + if (((JArray)value).Count == 0 && propertyIsArray && !subject.ContainsKey(property + )) + { + subject[property] = new JArray(); + } foreach (JToken val in (JArray)value) - { - AddValue(subject, property, val, propertyIsArray, allowDuplicate); - } - } - else - { - if (subject.ContainsKey(property)) - { - // check if subject already has the value if duplicates not allowed - bool hasValue = !allowDuplicate && HasValue(subject, property, value); - // make property an array if value not present or always an array - if (!IsArray(subject[property]) && (!hasValue || propertyIsArray)) - { + { + AddValue(subject, property, val, propertyIsArray, allowDuplicate); + } + } + else + { + if (subject.ContainsKey(property)) + { + // check if subject already has the value if duplicates not allowed + bool hasValue = !allowDuplicate && HasValue(subject, property, value); + // make property an array if value not present or always an array + if (!IsArray(subject[property]) && (!hasValue || propertyIsArray)) + { JArray tmp = new JArray(); - tmp.Add(subject[property]); - subject[property] = tmp; - } - // add new value - if (!hasValue) - { + tmp.Add(subject[property]); + subject[property] = tmp; + } + // add new value + if (!hasValue) + { ((JArray)subject[property]).Add(value); - } - } - else - { - // add new value as a set or single value - JToken tmp; - if (propertyIsArray) - { + } + } + else + { + // add new value as a set or single value + JToken tmp; + if (propertyIsArray) + { tmp = new JArray(); ((JArray)tmp).Add(value); - } - else - { - tmp = value; - } - subject[property] = tmp; - } - } - } + } + else + { + tmp = value; + } + subject[property] = tmp; + } + } + } - internal static void AddValue(JObject subject, string property - , JToken value, bool propertyIsArray) - { - AddValue(subject, property, value, propertyIsArray, true); - } + internal static void AddValue(JObject subject, string property + , JToken value, bool propertyIsArray) + { + AddValue(subject, property, value, propertyIsArray, true); + } - internal static void AddValue(JObject subject, string property - , JToken value) - { - AddValue(subject, property, value, false, true); - } + internal static void AddValue(JObject subject, string property + , JToken value) + { + AddValue(subject, property, value, false, true); + } - /// Prepends a base IRI to the given relative IRI. - /// Prepends a base IRI to the given relative IRI. - /// the base IRI. - /// the relative IRI. - /// - /// the absolute IRI. - /// TODO: the URL class isn't as forgiving as the Node.js url parser, - /// we may need to re-implement the parser here to support the - /// flexibility required - /// - private static string PrependBase(JToken baseobj, string iri) - { - // already an absolute IRI - if (iri.IndexOf(":") != -1) - { - return iri; - } - // parse base if it is a string - URL @base; - if (IsString(baseobj)) - { - @base = URL.Parse((string)baseobj); - } - else - { - // assume base is already a URL - @base = baseobj.Value(); - } - URL rel = URL.Parse(iri); - // start hierarchical part - string hierPart = @base.protocol; - if (!string.Empty.Equals(rel.authority)) - { - hierPart += "//" + rel.authority; - } - else - { - if (!string.Empty.Equals(@base.href)) - { - hierPart += "//" + @base.authority; - } - } - // per RFC3986 normalize - string path; - // IRI represents an absolute path - if (rel.pathname.IndexOf("/") == 0) - { - path = rel.pathname; - } - else - { - path = @base.pathname; - // append relative path to the end of the last directory from base - if (!string.Empty.Equals(rel.pathname)) - { - path = JsonLD.JavaCompat.Substring(path, 0, path.LastIndexOf("/") + 1); - if (path.Length > 0 && !path.EndsWith("/")) - { - path += "/"; - } - path += rel.pathname; - } - } - // remove slashes anddots in path - path = URL.RemoveDotSegments(path, !string.Empty.Equals(hierPart)); - // add query and hash - if (!string.Empty.Equals(rel.query)) - { - path += "?" + rel.query; - } - if (!string.Empty.Equals(rel.hash)) - { - path += rel.hash; - } - string rval = hierPart + path; - if (string.Empty.Equals(rval)) - { - return "./"; - } - return rval; - } + /// Prepends a base IRI to the given relative IRI. + /// Prepends a base IRI to the given relative IRI. + /// the base IRI. + /// the relative IRI. + /// + /// the absolute IRI. + /// TODO: the URL class isn't as forgiving as the Node.js url parser, + /// we may need to re-implement the parser here to support the + /// flexibility required + /// + private static string PrependBase(JToken baseobj, string iri) + { + // already an absolute IRI + if (iri.IndexOf(":") != -1) + { + return iri; + } + // parse base if it is a string + URL @base; + if (IsString(baseobj)) + { + @base = URL.Parse((string)baseobj); + } + else + { + // assume base is already a URL + @base = baseobj.Value(); + } + URL rel = URL.Parse(iri); + // start hierarchical part + string hierPart = @base.protocol; + if (!string.Empty.Equals(rel.authority)) + { + hierPart += "//" + rel.authority; + } + else + { + if (!string.Empty.Equals(@base.href)) + { + hierPart += "//" + @base.authority; + } + } + // per RFC3986 normalize + string path; + // IRI represents an absolute path + if (rel.pathname.IndexOf("/") == 0) + { + path = rel.pathname; + } + else + { + path = @base.pathname; + // append relative path to the end of the last directory from base + if (!string.Empty.Equals(rel.pathname)) + { + path = JsonLD.JavaCompat.Substring(path, 0, path.LastIndexOf("/") + 1); + if (path.Length > 0 && !path.EndsWith("/")) + { + path += "/"; + } + path += rel.pathname; + } + } + // remove slashes anddots in path + path = URL.RemoveDotSegments(path, !string.Empty.Equals(hierPart)); + // add query and hash + if (!string.Empty.Equals(rel.query)) + { + path += "?" + rel.query; + } + if (!string.Empty.Equals(rel.hash)) + { + path += rel.hash; + } + string rval = hierPart + path; + if (string.Empty.Equals(rval)) + { + return "./"; + } + return rval; + } - /// Expands a language map. - /// Expands a language map. - /// the language map to expand. - /// the expanded language map. - /// JsonLdError - /// - internal static JArray ExpandLanguageMap(JObject languageMap - ) - { + /// Expands a language map. + /// Expands a language map. + /// the language map to expand. + /// the expanded language map. + /// JsonLdError + /// + internal static JArray ExpandLanguageMap(JObject languageMap + ) + { JArray rval = new JArray(); IList keys = new List(languageMap.GetKeys()); - keys.SortInPlace(); - // lexicographically sort languages - foreach (string key in keys) - { - JToken val; - if (!IsArray(languageMap[key])) - { - val = new JArray(); - ((JArray)val).Add(languageMap[key]); - } - else - { - val = (JArray)languageMap[key]; - } - foreach (JToken item in val) - { - if (!IsString(item)) - { - throw new JsonLdError(JsonLdError.Error.SyntaxError); - } - JObject tmp = new JObject(); - tmp["@value"] = item; - tmp["@language"] = key.ToLower(); - rval.Add(tmp); - } - } - return rval; - } + keys.SortInPlace(); + // lexicographically sort languages + foreach (string key in keys) + { + JToken val; + if (!IsArray(languageMap[key])) + { + val = new JArray(); + ((JArray)val).Add(languageMap[key]); + } + else + { + val = (JArray)languageMap[key]; + } + foreach (JToken item in val) + { + if (!IsString(item)) + { + throw new JsonLdError(JsonLdError.Error.SyntaxError); + } + JObject tmp = new JObject(); + tmp["@value"] = item; + tmp["@language"] = key.ToLower(); + rval.Add(tmp); + } + } + return rval; + } - /// Throws an exception if the given value is not a valid @type value. - /// Throws an exception if the given value is not a valid @type value. - /// the value to check. - /// JsonLdError - /// - internal static bool ValidateTypeValue(JToken v) - { - if (v.IsNull()) - { - throw new ArgumentNullException("\"@type\" value cannot be null"); - } - // must be a string, subject reference, or empty object - if (v.Type == JTokenType.String || (v is JObject && (((JObject)v).ContainsKey + /// Throws an exception if the given value is not a valid @type value. + /// Throws an exception if the given value is not a valid @type value. + /// the value to check. + /// JsonLdError + /// + internal static bool ValidateTypeValue(JToken v) + { + if (v.IsNull()) + { + throw new ArgumentNullException("\"@type\" value cannot be null"); + } + // must be a string, subject reference, or empty object + if (v.Type == JTokenType.String || (v is JObject && (((JObject)v).ContainsKey ("@id") || ((JArray)v).Count == 0))) - { - return true; - } - // must be an array - bool isValid = false; - if (v is JArray) - { - isValid = true; + { + return true; + } + // must be an array + bool isValid = false; + if (v is JArray) + { + isValid = true; foreach (JToken i in (JArray)v) - { + { if (!(i.Type == JTokenType.String || i is JObject && ((JObject)i).ContainsKey - ("@id"))) - { - isValid = false; - break; - } - } - } - if (!isValid) - { - throw new JsonLdError(JsonLdError.Error.SyntaxError); - } - return true; - } + ("@id"))) + { + isValid = false; + break; + } + } + } + if (!isValid) + { + throw new JsonLdError(JsonLdError.Error.SyntaxError); + } + return true; + } - /// Removes a base IRI from the given absolute IRI. - /// Removes a base IRI from the given absolute IRI. - /// the base IRI. - /// the absolute IRI. - /// the relative IRI if relative to base, otherwise the absolute IRI. - private static string RemoveBase(JToken baseobj, string iri) - { - URL @base; - if (IsString(baseobj)) - { - @base = URL.Parse((string)baseobj); - } - else - { - @base = baseobj.Value(); - } - // establish base root - string root = string.Empty; - if (!string.Empty.Equals(@base.href)) - { - root += (@base.protocol) + "//" + @base.authority; - } - else - { - // support network-path reference with empty base - if (iri.IndexOf("//") != 0) - { - root += "//"; - } - } - // IRI not relative to base - if (iri.IndexOf(root) != 0) - { - return iri; - } - // remove root from IRI and parse remainder - URL rel = URL.Parse(JsonLD.JavaCompat.Substring(iri, root.Length)); - // remove path segments that match - IList baseSegments = _split(@base.normalizedPath, "/"); - IList iriSegments = _split(rel.normalizedPath, "/"); - while (baseSegments.Count > 0 && iriSegments.Count > 0) - { - if (!baseSegments[0].Equals(iriSegments[0])) - { - break; - } - if (baseSegments.Count > 0) - { - baseSegments.RemoveAt(0); - } - if (iriSegments.Count > 0) - { - iriSegments.RemoveAt(0); - } - } - // use '../' for each non-matching base segment - string rval = string.Empty; - if (baseSegments.Count > 0) - { - // don't count the last segment if it isn't a path (doesn't end in - // '/') - // don't count empty first segment, it means base began with '/' - if (!@base.normalizedPath.EndsWith("/") || string.Empty.Equals(baseSegments[0])) - { - baseSegments.RemoveAt(baseSegments.Count - 1); - } - for (int i = 0; i < baseSegments.Count; ++i) - { - rval += "../"; - } - } - // prepend remaining segments - rval += _join(iriSegments, "/"); - // add query and hash - if (!string.Empty.Equals(rel.query)) - { - rval += "?" + rel.query; - } - if (!string.Empty.Equals(rel.hash)) - { - rval += rel.hash; - } - if (string.Empty.Equals(rval)) - { - rval = "./"; - } - return rval; - } + /// Removes a base IRI from the given absolute IRI. + /// Removes a base IRI from the given absolute IRI. + /// the base IRI. + /// the absolute IRI. + /// the relative IRI if relative to base, otherwise the absolute IRI. + private static string RemoveBase(JToken baseobj, string iri) + { + URL @base; + if (IsString(baseobj)) + { + @base = URL.Parse((string)baseobj); + } + else + { + @base = baseobj.Value(); + } + // establish base root + string root = string.Empty; + if (!string.Empty.Equals(@base.href)) + { + root += (@base.protocol) + "//" + @base.authority; + } + else + { + // support network-path reference with empty base + if (iri.IndexOf("//") != 0) + { + root += "//"; + } + } + // IRI not relative to base + if (iri.IndexOf(root) != 0) + { + return iri; + } + // remove root from IRI and parse remainder + URL rel = URL.Parse(JsonLD.JavaCompat.Substring(iri, root.Length)); + // remove path segments that match + IList baseSegments = _split(@base.normalizedPath, "/"); + IList iriSegments = _split(rel.normalizedPath, "/"); + while (baseSegments.Count > 0 && iriSegments.Count > 0) + { + if (!baseSegments[0].Equals(iriSegments[0])) + { + break; + } + if (baseSegments.Count > 0) + { + baseSegments.RemoveAt(0); + } + if (iriSegments.Count > 0) + { + iriSegments.RemoveAt(0); + } + } + // use '../' for each non-matching base segment + string rval = string.Empty; + if (baseSegments.Count > 0) + { + // don't count the last segment if it isn't a path (doesn't end in + // '/') + // don't count empty first segment, it means base began with '/' + if (!@base.normalizedPath.EndsWith("/") || string.Empty.Equals(baseSegments[0])) + { + baseSegments.RemoveAt(baseSegments.Count - 1); + } + for (int i = 0; i < baseSegments.Count; ++i) + { + rval += "../"; + } + } + // prepend remaining segments + rval += _join(iriSegments, "/"); + // add query and hash + if (!string.Empty.Equals(rel.query)) + { + rval += "?" + rel.query; + } + if (!string.Empty.Equals(rel.hash)) + { + rval += rel.hash; + } + if (string.Empty.Equals(rval)) + { + rval = "./"; + } + return rval; + } - /// Removes the @preserve keywords as the last step of the framing algorithm. - /// - /// Removes the @preserve keywords as the last step of the framing algorithm. - /// - /// the active context used to compact the input. - /// the framed, compacted output. - /// the compaction options used. - /// the resulting output. - /// JsonLdError - /// - internal static JToken RemovePreserve(Context ctx, JToken input, JsonLdOptions opts - ) - { - // recurse through arrays - if (IsArray(input)) - { + /// Removes the @preserve keywords as the last step of the framing algorithm. + /// + /// Removes the @preserve keywords as the last step of the framing algorithm. + /// + /// the active context used to compact the input. + /// the framed, compacted output. + /// the compaction options used. + /// the resulting output. + /// JsonLdError + /// + internal static JToken RemovePreserve(Context ctx, JToken input, JsonLdOptions opts + ) + { + // recurse through arrays + if (IsArray(input)) + { JArray output = new JArray(); - foreach (JToken i in (JArray)input) - { - JToken result = RemovePreserve(ctx, i, opts); - // drop nulls from arrays - if (!result.IsNull()) - { - output.Add(result); - } - } - input = output; - } - else - { - if (IsObject(input)) - { - // remove @preserve - if (((JObject)input).ContainsKey("@preserve")) - { + foreach (JToken i in (JArray)input) + { + JToken result = RemovePreserve(ctx, i, opts); + // drop nulls from arrays + if (!result.IsNull()) + { + output.Add(result); + } + } + input = output; + } + else + { + if (IsObject(input)) + { + // remove @preserve + if (((JObject)input).ContainsKey("@preserve")) + { if (((JObject)input)["@preserve"].SafeCompare("@null")) - { - return null; - } + { + return null; + } return ((JObject)input)["@preserve"]; - } - // skip @values - if (IsValue(input)) - { - return input; - } - // recurse through @lists - if (IsList(input)) - { + } + // skip @values + if (IsValue(input)) + { + return input; + } + // recurse through @lists + if (IsList(input)) + { ((JObject)input)["@list"] = RemovePreserve(ctx, ((JObject)input)["@list"], opts); - return input; - } - // recurse through properties + return input; + } + // recurse through properties foreach (string prop in input.GetKeys()) - { + { JToken result = RemovePreserve(ctx, ((JObject)input)[prop], opts - ); - string container = ctx.GetContainer(prop); + ); + string container = ctx.GetContainer(prop); if (opts.GetCompactArrays() && IsArray(result) && ((JArray)result).Count == - 1 && container == null) - { + 1 && container == null) + { result = ((JArray)result)[0]; - } - ((JObject)input)[prop] = result; - } - } - } - return input; - } + } + ((JObject)input)[prop] = result; + } + } + } + return input; + } - /// replicate javascript .join because i'm too lazy to keep doing it manually - /// - /// - /// - /// - private static string _join(IList list, string joiner) - { - string rval = string.Empty; - if (list.Count > 0) - { - rval += list[0]; - } - for (int i = 1; i < list.Count; i++) - { - rval += joiner + list[i]; - } - return rval; - } + /// replicate javascript .join because i'm too lazy to keep doing it manually + /// + /// + /// + /// + private static string _join(IList list, string joiner) + { + string rval = string.Empty; + if (list.Count > 0) + { + rval += list[0]; + } + for (int i = 1; i < list.Count; i++) + { + rval += joiner + list[i]; + } + return rval; + } - /// - /// replicates the functionality of javascript .split, which has different - /// results to java's String.split if there is a trailing / - /// - /// - /// - /// - private static IList _split(string @string, string delim) - { - IList rval = new List(System.Linq.Enumerable.ToList(@string.Split - (delim))); - if (@string.EndsWith("/")) - { - // javascript .split includes a blank entry if the string ends with - // the delimiter, java .split does not so we need to add it manually - rval.Add(string.Empty); - } - return rval; - } + /// + /// replicates the functionality of javascript .split, which has different + /// results to java's String.split if there is a trailing / + /// + /// + /// + /// + private static IList _split(string @string, string delim) + { + IList rval = new List(System.Linq.Enumerable.ToList(@string.Split + (delim))); + if (@string.EndsWith("/")) + { + // javascript .split includes a blank entry if the string ends with + // the delimiter, java .split does not so we need to add it manually + rval.Add(string.Empty); + } + return rval; + } - /// Compares two strings first based on length and then lexicographically. - /// Compares two strings first based on length and then lexicographically. - /// the first string. - /// the second string. - /// -1 if a < b, 1 if a > b, 0 if a == b. - internal static int CompareShortestLeast(string a, string b) - { - if (a.Length < b.Length) - { - return -1; - } - else - { - if (b.Length < a.Length) - { - return 1; - } - } - return System.Math.Sign(string.CompareOrdinal(a, b)); - } + /// Compares two strings first based on length and then lexicographically. + /// Compares two strings first based on length and then lexicographically. + /// the first string. + /// the second string. + /// -1 if a < b, 1 if a > b, 0 if a == b. + internal static int CompareShortestLeast(string a, string b) + { + if (a.Length < b.Length) + { + return -1; + } + else + { + if (b.Length < a.Length) + { + return 1; + } + } + return System.Math.Sign(string.CompareOrdinal(a, b)); + } - /// Determines if the given value is a property of the given subject. - /// Determines if the given value is a property of the given subject. - /// the subject to check. - /// the property to check. - /// the value to check. - /// true if the value exists, false if not. - internal static bool HasValue(JObject subject, string property - , JToken value) - { - bool rval = false; - if (HasProperty(subject, property)) - { - JToken val = subject[property]; - bool isList = IsList(val); - if (isList || val is JArray) - { - if (isList) - { - val = (JObject)val["@list"]; - } - foreach (JToken i in (JArray)val) - { - if (CompareValues(value, i)) - { - rval = true; - break; - } - } - } - else - { - if (!(value is JArray)) - { - rval = CompareValues(value, val); - } - } - } - return rval; - } + /// Determines if the given value is a property of the given subject. + /// Determines if the given value is a property of the given subject. + /// the subject to check. + /// the property to check. + /// the value to check. + /// true if the value exists, false if not. + internal static bool HasValue(JObject subject, string property + , JToken value) + { + bool rval = false; + if (HasProperty(subject, property)) + { + JToken val = subject[property]; + bool isList = IsList(val); + if (isList || val is JArray) + { + if (isList) + { + val = (JObject)val["@list"]; + } + foreach (JToken i in (JArray)val) + { + if (CompareValues(value, i)) + { + rval = true; + break; + } + } + } + else + { + if (!(value is JArray)) + { + rval = CompareValues(value, val); + } + } + } + return rval; + } - private static bool HasProperty(JObject subject, string property - ) - { - bool rval = false; - if (subject.ContainsKey(property)) - { - JToken value = subject[property]; - rval = (!(value is JArray) || ((JArray)value).Count > 0); - } - return rval; - } + private static bool HasProperty(JObject subject, string property + ) + { + bool rval = false; + if (subject.ContainsKey(property)) + { + JToken value = subject[property]; + rval = (!(value is JArray) || ((JArray)value).Count > 0); + } + return rval; + } - /// Compares two JSON-LD values for equality. - /// - /// Compares two JSON-LD values for equality. Two JSON-LD values will be - /// considered equal if: - /// 1. They are both primitives of the same type and value. 2. They are both @values - /// with the same @value, @type, and @language, OR 3. They both have @ids - /// they are the same. - /// - /// the first value. - /// the second value. - /// true if v1 and v2 are considered equal, false if not. - internal static bool CompareValues(JToken v1, JToken v2) - { - if (v1.Equals(v2)) - { - return true; - } - if (IsValue(v1) && IsValue(v2) && Obj.Equals(((JObject)v1)["@value" + /// Compares two JSON-LD values for equality. + /// + /// Compares two JSON-LD values for equality. Two JSON-LD values will be + /// considered equal if: + /// 1. They are both primitives of the same type and value. 2. They are both @values + /// with the same @value, @type, and @language, OR 3. They both have @ids + /// they are the same. + /// + /// the first value. + /// the second value. + /// true if v1 and v2 are considered equal, false if not. + internal static bool CompareValues(JToken v1, JToken v2) + { + if (v1.Equals(v2)) + { + return true; + } + if (IsValue(v1) && IsValue(v2) && Obj.Equals(((JObject)v1)["@value" ], ((JObject)v2)["@value"]) && Obj.Equals(((JObject)v1)["@type"], ((JObject)v2)["@type"]) && Obj.Equals (((JObject)v1)["@language"], ((JObject)v2 )["@language"]) && Obj.Equals(((JObject)v1)["@index"], ((JObject)v2)["@index"])) - { - return true; - } + { + return true; + } if ((v1 is JObject && ((JObject)v1).ContainsKey("@id")) && (v2 is JObject && ((JObject)v2).ContainsKey("@id")) && ((JObject)v1)["@id"].Equals(((JObject)v2 - )["@id"])) - { - return true; - } - return false; - } + )["@id"])) + { + return true; + } + return false; + } - /// Removes a value from a subject. - /// Removes a value from a subject. - /// the subject. - /// the property that relates the value to the subject. - /// the value to remove. - /// + /// Removes a value from a subject. + /// Removes a value from a subject. + /// the subject. + /// the property that relates the value to the subject. + /// the value to remove. + /// internal static void RemoveValue(JObject subject, string property , JObject value) - { - RemoveValue(subject, property, value, false); - } + { + RemoveValue(subject, property, value, false); + } internal static void RemoveValue(JObject subject, string property , JObject value, bool propertyIsArray) - { - // filter out value - JArray values = new JArray(); + { + // filter out value + JArray values = new JArray(); if (subject[property] is JArray) - { + { foreach (JToken e in ((JArray)subject[property])) - { + { if (!e.SafeCompare(value)) - { - values.Add(value); - } - } - } - else - { - if (!subject[property].SafeCompare(value)) - { - values.Add(subject[property]); - } - } - if (values.Count == 0) - { - JsonLD.Collections.Remove(subject, property); - } - else - { - if (values.Count == 1 && !propertyIsArray) - { - subject[property] = values[0]; - } - else - { - subject[property] = values; - } - } - } + { + values.Add(value); + } + } + } + else + { + if (!subject[property].SafeCompare(value)) + { + values.Add(subject[property]); + } + } + if (values.Count == 0) + { + JsonLD.Collections.Remove(subject, property); + } + else + { + if (values.Count == 1 && !propertyIsArray) + { + subject[property] = values[0]; + } + else + { + subject[property] = values; + } + } + } - /// Returns true if the given value is a blank node. - /// Returns true if the given value is a blank node. - /// the value to check. - /// true if the value is a blank node, false if not. - internal static bool IsBlankNode(JToken v) - { - // Note: A value is a blank node if all of these hold true: - // 1. It is an Object. - // 2. If it has an @id key its value begins with '_:'. - // 3. It has no keys OR is not a @value, @set, or @list. + /// Returns true if the given value is a blank node. + /// Returns true if the given value is a blank node. + /// the value to check. + /// true if the value is a blank node, false if not. + internal static bool IsBlankNode(JToken v) + { + // Note: A value is a blank node if all of these hold true: + // 1. It is an Object. + // 2. If it has an @id key its value begins with '_:'. + // 3. It has no keys OR is not a @value, @set, or @list. if (v is JObject) - { - if (((JObject)v).ContainsKey("@id")) - { + { + if (((JObject)v).ContainsKey("@id")) + { return ((string)((JObject)v)["@id"]).StartsWith("_:"); - } - else - { + } + else + { return ((JObject)v).Count == 0 || !(((JObject)v).ContainsKey("@value") || ((JObject)v).ContainsKey("@set") || ((JObject)v).ContainsKey("@list")); - } - } - return false; - } + } + } + return false; + } - /// Resolves external @context URLs using the given URL resolver. - /// - /// Resolves external @context URLs using the given URL resolver. Each - /// instance of @context in the input that refers to a URL will be replaced - /// with the JSON @context found at that URL. - /// - /// the JSON-LD input with possible contexts. - /// (url, callback(err, jsonCtx)) the URL resolver to use. - /// (err, input) called once the operation completes. - /// JsonLdError - /// - internal static void ResolveContextUrls(JToken input) - { + /// Resolves external @context URLs using the given URL resolver. + /// + /// Resolves external @context URLs using the given URL resolver. Each + /// instance of @context in the input that refers to a URL will be replaced + /// with the JSON @context found at that URL. + /// + /// the JSON-LD input with possible contexts. + /// (url, callback(err, jsonCtx)) the URL resolver to use. + /// (err, input) called once the operation completes. + /// JsonLdError + /// + internal static void ResolveContextUrls(JToken input) + { Resolve(input, new JObject()); - } + } - /// + /// private static void Resolve(JToken input, JObject cycles) - { - Pattern regex = Pattern.Compile("(http|https)://(\\w+:{0,1}\\w*@)?(\\S+)(:[0-9]+)?(/|/([\\w#!:.?+=&%@!\\-/]))?" - ); - if (cycles.Count > MaxContextUrls) - { - throw new JsonLdError(JsonLdError.Error.UnknownError); - } - // for tracking the URLs to resolve - JObject urls = new JObject(); - // find all URLs in the given input - if (!FindContextUrls(input, urls, false)) - { - // finished - FindContextUrls(input, urls, true); - } - // queue all unresolved URLs + { + Pattern regex = Pattern.Compile("(http|https)://(\\w+:{0,1}\\w*@)?(\\S+)(:[0-9]+)?(/|/([\\w#!:.?+=&%@!\\-/]))?" + ); + if (cycles.Count > MaxContextUrls) + { + throw new JsonLdError(JsonLdError.Error.UnknownError); + } + // for tracking the URLs to resolve + JObject urls = new JObject(); + // find all URLs in the given input + if (!FindContextUrls(input, urls, false)) + { + // finished + FindContextUrls(input, urls, true); + } + // queue all unresolved URLs JArray queue = new JArray(); - foreach (string url in urls.GetKeys()) - { - if (urls[url].SafeCompare(false)) - { - // validate URL - if (!regex.Matcher(url).Matches()) - { - throw new JsonLdError(JsonLdError.Error.UnknownError); - } - queue.Add(url); - } - } - // resolve URLs in queue - int count = queue.Count; - foreach (string url_1 in queue) - { - // check for context URL cycle - if (cycles.ContainsKey(url_1)) - { - throw new JsonLdError(JsonLdError.Error.UnknownError); - } + foreach (string url in urls.GetKeys()) + { + if (urls[url].SafeCompare(false)) + { + // validate URL + if (!regex.Matcher(url).Matches()) + { + throw new JsonLdError(JsonLdError.Error.UnknownError); + } + queue.Add(url); + } + } + // resolve URLs in queue + int count = queue.Count; + foreach (string url_1 in queue) + { + // check for context URL cycle + if (cycles.ContainsKey(url_1)) + { + throw new JsonLdError(JsonLdError.Error.UnknownError); + } JObject _cycles = (JObject)Clone(cycles); - _cycles[url_1] = true; - try - { + _cycles[url_1] = true; + try + { JObject ctx = (JObject)new DocumentLoader().LoadDocument(url_1).Document; - if (!ctx.ContainsKey("@context")) - { - ctx = new JObject(); + if (!ctx.ContainsKey("@context")) + { + ctx = new JObject(); ctx["@context"] = new JObject(); - } - Resolve(ctx, _cycles); - urls[url_1] = ctx["@context"]; - count -= 1; - if (count == 0) - { - FindContextUrls(input, urls, true); - } - } + } + Resolve(ctx, _cycles); + urls[url_1] = ctx["@context"]; + count -= 1; + if (count == 0) + { + FindContextUrls(input, urls, true); + } + } //catch (JsonParseException) //{ // throw new JsonLdError(JsonLdError.Error.UnknownError); @@ -946,155 +946,155 @@ private static void Resolve(JToken input, JObject cycles) //{ // throw new JsonLdError(JsonLdError.Error.UnknownError); //} - catch (IOException) - { - throw new JsonLdError(JsonLdError.Error.UnknownError); - } - } - } + catch (IOException) + { + throw new JsonLdError(JsonLdError.Error.UnknownError); + } + } + } - /// Finds all @context URLs in the given JSON-LD input. - /// Finds all @context URLs in the given JSON-LD input. - /// the JSON-LD input. - /// a map of URLs (url => false/@contexts). - /// true to replace the URLs in the given input with the - /// from the urls map, false not to. - /// true if new URLs to resolve were found, false if not. + /// Finds all @context URLs in the given JSON-LD input. + /// Finds all @context URLs in the given JSON-LD input. + /// the JSON-LD input. + /// a map of URLs (url => false/@contexts). + /// true to replace the URLs in the given input with the + /// from the urls map, false not to. + /// true if new URLs to resolve were found, false if not. private static bool FindContextUrls(JToken input, JObject urls - , bool replace) - { - int count = urls.Count; - if (input is JArray) - { + , bool replace) + { + int count = urls.Count; + if (input is JArray) + { foreach (JToken i in (JArray)input) - { - FindContextUrls(i, urls, replace); - } - return count < urls.Count; - } - else - { - if (input is JObject) - { - foreach (string key in input.GetKeys()) - { - if (!"@context".Equals(key)) - { + { + FindContextUrls(i, urls, replace); + } + return count < urls.Count; + } + else + { + if (input is JObject) + { + foreach (string key in input.GetKeys()) + { + if (!"@context".Equals(key)) + { FindContextUrls(((JObject)input)[key], urls, replace); - continue; - } - // get @context + continue; + } + // get @context JToken ctx = ((JObject)input)[key]; - // array @context - if (ctx is JArray) - { + // array @context + if (ctx is JArray) + { int length = ((JArray)ctx).Count; - for (int i = 0; i < length; i++) - { + for (int i = 0; i < length; i++) + { JToken _ctx = ((JArray)ctx)[i]; - if (_ctx.Type == JTokenType.String) - { - // replace w/@context if requested - if (replace) - { - _ctx = urls[(string)_ctx]; - if (_ctx is JArray) - { - // add flattened context + if (_ctx.Type == JTokenType.String) + { + // replace w/@context if requested + if (replace) + { + _ctx = urls[(string)_ctx]; + if (_ctx is JArray) + { + // add flattened context ((JArray)ctx).RemoveAt(i); JsonLD.Collections.AddAllObj(((JArray)ctx), (ICollection)_ctx); i += ((JArray)_ctx).Count; length += ((JArray)_ctx).Count; - } - else - { + } + else + { ((JArray)ctx)[i] = _ctx; - } - } - else - { - // @context URL found - if (!urls.ContainsKey((string)_ctx)) - { - urls[(string)_ctx] = false; - } - } - } - } - } - else - { - // string @context - if (ctx.Type == JTokenType.String) - { - // replace w/@context if requested - if (replace) - { - ((JObject)input)[key] = urls[(string)ctx]; - } - else - { - // @context URL found - if (!urls.ContainsKey((string)ctx)) - { - urls[(string)ctx] = false; - } - } - } - } - } - return (count < urls.Count); - } - } - return false; - } + } + } + else + { + // @context URL found + if (!urls.ContainsKey((string)_ctx)) + { + urls[(string)_ctx] = false; + } + } + } + } + } + else + { + // string @context + if (ctx.Type == JTokenType.String) + { + // replace w/@context if requested + if (replace) + { + ((JObject)input)[key] = urls[(string)ctx]; + } + else + { + // @context URL found + if (!urls.ContainsKey((string)ctx)) + { + urls[(string)ctx] = false; + } + } + } + } + } + return (count < urls.Count); + } + } + return false; + } internal static JToken Clone(JToken value) - { + { return value.DeepClone(); - } + } - /// Returns true if the given value is a JSON-LD Array - /// the value to check. - /// + /// Returns true if the given value is a JSON-LD Array + /// the value to check. + /// internal static bool IsArray(JToken v) - { - return (v is JArray); - } + { + return (v is JArray); + } - /// Returns true if the given value is a JSON-LD List - /// the value to check. - /// + /// Returns true if the given value is a JSON-LD List + /// the value to check. + /// internal static bool IsList(JToken v) - { - return (v is JObject && ((IDictionary)v).ContainsKey("@list") - ); - } + { + return (v is JObject && ((IDictionary)v).ContainsKey("@list") + ); + } - /// Returns true if the given value is a JSON-LD Object - /// the value to check. - /// + /// Returns true if the given value is a JSON-LD Object + /// the value to check. + /// internal static bool IsObject(JToken v) - { - return (v is JObject); - } + { + return (v is JObject); + } - /// Returns true if the given value is a JSON-LD value - /// the value to check. - /// + /// Returns true if the given value is a JSON-LD value + /// the value to check. + /// internal static bool IsValue(JToken v) - { - return (v is JObject && ((IDictionary)v).ContainsKey("@value" - )); - } + { + return (v is JObject && ((IDictionary)v).ContainsKey("@value" + )); + } - /// Returns true if the given value is a JSON-LD string - /// the value to check. - /// - internal static bool IsString(JToken v) - { - // TODO: should this return true for arrays of strings as well? - return (v.Type == JTokenType.String); - } - } + /// Returns true if the given value is a JSON-LD string + /// the value to check. + /// + internal static bool IsString(JToken v) + { + // TODO: should this return true for arrays of strings as well? + return (v.Type == JTokenType.String); + } + } } diff --git a/src/JsonLD/Core/NormalizeUtils.cs b/src/JsonLD/Core/NormalizeUtils.cs index 45bf20c..c6828ab 100644 --- a/src/JsonLD/Core/NormalizeUtils.cs +++ b/src/JsonLD/Core/NormalizeUtils.cs @@ -6,611 +6,621 @@ namespace JsonLD.Core { -#if !PORTABLE - internal class NormalizeUtils - { - private readonly UniqueNamer namer; + internal class NormalizeUtils + { + private readonly UniqueNamer namer; - private readonly IDictionary> bnodes; + private readonly IDictionary> bnodes; - private readonly IList quads; + private readonly IList quads; - private readonly JsonLdOptions options; + private readonly JsonLdOptions options; public NormalizeUtils(IList quads, IDictionary> bnodes, UniqueNamer - namer, JsonLdOptions options) - { - this.options = options; - this.quads = quads; - this.bnodes = bnodes; - this.namer = namer; - } + namer, JsonLdOptions options) + { + this.options = options; + this.quads = quads; + this.bnodes = bnodes; + this.namer = namer; + } - // generates unique and duplicate hashes for bnodes - /// - public virtual object HashBlankNodes(IEnumerable unnamed_) - { - IList unnamed = new List(unnamed_); - IList nextUnnamed = new List(); - IDictionary> duplicates = new Dictionary>(); - IDictionary unique = new Dictionary(); - // NOTE: not using the same structure as javascript here to avoid - // possible stack overflows - // hash quads for each unnamed bnode - for (int hui = 0; ; hui++) - { - if (hui == unnamed.Count) - { - // done, name blank nodes - bool named = false; - IList hashes = new List(unique.Keys); - hashes.SortInPlace(); - foreach (string hash in hashes) - { - string bnode = unique[hash]; - namer.GetName(bnode); - named = true; - } - // continue to hash bnodes if a bnode was assigned a name - if (named) - { - // this resets the initial variables, so it seems like it - // has to go on the stack - // but since this is the end of the function either way, it - // might not have to - // hashBlankNodes(unnamed); - hui = -1; - unnamed = nextUnnamed; - nextUnnamed = new List(); - duplicates = new Dictionary>(); - unique = new Dictionary(); - continue; - } - else - { - // name the duplicate hash bnods - // names duplicate hash bnodes - // enumerate duplicate hash groups in sorted order - hashes = new List(duplicates.Keys); - hashes.SortInPlace(); - // process each group - for (int pgi = 0; ; pgi++) - { - if (pgi == hashes.Count) - { - // done, create JSON-LD array - // return createArray(); - IList normalized = new List(); - // Note: At this point all bnodes in the set of RDF - // quads have been - // assigned canonical names, which have been stored - // in the 'namer' object. - // Here each quad is updated by assigning each of - // its bnodes its new name - // via the 'namer' object - // update bnode names in each quad and serialize - for (int cai = 0; cai < quads.Count; ++cai) - { - RDFDataset.Quad quad = quads[cai]; - foreach (string attr in new string[] { "subject", "object", "name" }) - { - if (quad.ContainsKey(attr)) - { - IDictionary qa = (IDictionary)quad[attr]; - if (qa != null && (string)qa["type"] == "blank node" && ((string)qa["value"]).IndexOf - ("_:c14n") != 0) - { - qa["value"] = namer.GetName((string)qa["value"]); - } - } - } - normalized.Add(RDFDatasetUtils.ToNQuad(quad, quad.ContainsKey("name" - ) && !(quad["name"] == null) ? (string)((IDictionary)((IDictionary)quad)["name"])["value"] : null)); - } - // sort normalized output - normalized.SortInPlace(); - // handle output format - if (options.format != null) - { - if ("application/nquads".Equals(options.format)) - { - string rval = string.Empty; - foreach (string n in normalized) - { - rval += n; - } - return rval; - } - else - { - throw new JsonLdError(JsonLdError.Error.UnknownFormat, options.format); - } - } - string rval_1 = string.Empty; - foreach (string n_1 in normalized) - { - rval_1 += n_1; - } - return RDFDatasetUtils.ParseNQuads(rval_1); - } - // name each group member - IList group = duplicates[hashes[pgi]]; - IList results = new List(); - for (int n_2 = 0; ; n_2++) - { - if (n_2 == group.Count) - { - // name bnodes in hash order - results.SortInPlace(new _IComparer_145()); - foreach (NormalizeUtils.HashResult r in results) - { - // name all bnodes in path namer in - // key-entry order - // Note: key-order is preserved in - // javascript - foreach (string key in r.pathNamer.Existing().GetKeys()) - { - namer.GetName(key); - } - } - // processGroup(i+1); - break; - } - else - { - // skip already-named bnodes - string bnode = group[n_2]; - if (namer.IsNamed(bnode)) - { - continue; - } - // hash bnode paths - UniqueNamer pathNamer = new UniqueNamer("_:b"); - pathNamer.GetName(bnode); - NormalizeUtils.HashResult result = HashPaths(bnode, bnodes, namer, pathNamer); - results.Add(result); - } - } - } - } - } - // hash unnamed bnode - string bnode_1 = unnamed[hui]; - string hash_1 = HashQuads(bnode_1, bnodes, namer); - // store hash as unique or a duplicate - if (duplicates.ContainsKey(hash_1)) - { - duplicates[hash_1].Add(bnode_1); - nextUnnamed.Add(bnode_1); - } - else - { - if (unique.ContainsKey(hash_1)) - { - IList tmp = new List(); - tmp.Add(unique[hash_1]); - tmp.Add(bnode_1); - duplicates[hash_1] = tmp; - nextUnnamed.Add(unique[hash_1]); - nextUnnamed.Add(bnode_1); - JsonLD.Collections.Remove(unique, hash_1); - } - else - { - unique[hash_1] = bnode_1; - } - } - } - } + // generates unique and duplicate hashes for bnodes + /// + public virtual object HashBlankNodes(IEnumerable unnamed_) + { +#if !PORTABLE + IList unnamed = new List(unnamed_); + IList nextUnnamed = new List(); + IDictionary> duplicates = new Dictionary>(); + IDictionary unique = new Dictionary(); + // NOTE: not using the same structure as javascript here to avoid + // possible stack overflows + // hash quads for each unnamed bnode + for (int hui = 0; ; hui++) + { + if (hui == unnamed.Count) + { + // done, name blank nodes + bool named = false; + IList hashes = new List(unique.Keys); + hashes.SortInPlace(); + foreach (string hash in hashes) + { + string bnode = unique[hash]; + namer.GetName(bnode); + named = true; + } + // continue to hash bnodes if a bnode was assigned a name + if (named) + { + // this resets the initial variables, so it seems like it + // has to go on the stack + // but since this is the end of the function either way, it + // might not have to + // hashBlankNodes(unnamed); + hui = -1; + unnamed = nextUnnamed; + nextUnnamed = new List(); + duplicates = new Dictionary>(); + unique = new Dictionary(); + continue; + } + else + { + // name the duplicate hash bnods + // names duplicate hash bnodes + // enumerate duplicate hash groups in sorted order + hashes = new List(duplicates.Keys); + hashes.SortInPlace(); + // process each group + for (int pgi = 0; ; pgi++) + { + if (pgi == hashes.Count) + { + // done, create JSON-LD array + // return createArray(); + IList normalized = new List(); + // Note: At this point all bnodes in the set of RDF + // quads have been + // assigned canonical names, which have been stored + // in the 'namer' object. + // Here each quad is updated by assigning each of + // its bnodes its new name + // via the 'namer' object + // update bnode names in each quad and serialize + for (int cai = 0; cai < quads.Count; ++cai) + { + RDFDataset.Quad quad = quads[cai]; + foreach (string attr in new string[] { "subject", "object", "name" }) + { + if (quad.ContainsKey(attr)) + { + IDictionary qa = (IDictionary)quad[attr]; + if (qa != null && (string)qa["type"] == "blank node" && ((string)qa["value"]).IndexOf + ("_:c14n") != 0) + { + qa["value"] = namer.GetName((string)qa["value"]); + } + } + } + normalized.Add(RDFDatasetUtils.ToNQuad(quad, quad.ContainsKey("name" + ) && !(quad["name"] == null) ? (string)((IDictionary)((IDictionary)quad)["name"])["value"] : null)); + } + // sort normalized output + normalized.SortInPlace(); + // handle output format + if (options.format != null) + { + if ("application/nquads".Equals(options.format)) + { + string rval = string.Empty; + foreach (string n in normalized) + { + rval += n; + } + return rval; + } + else + { + throw new JsonLdError(JsonLdError.Error.UnknownFormat, options.format); + } + } + string rval_1 = string.Empty; + foreach (string n_1 in normalized) + { + rval_1 += n_1; + } + return RDFDatasetUtils.ParseNQuads(rval_1); + } + // name each group member + IList group = duplicates[hashes[pgi]]; + IList results = new List(); + for (int n_2 = 0; ; n_2++) + { + if (n_2 == group.Count) + { + // name bnodes in hash order + results.SortInPlace(new _IComparer_145()); + foreach (NormalizeUtils.HashResult r in results) + { + // name all bnodes in path namer in + // key-entry order + // Note: key-order is preserved in + // javascript + foreach (string key in r.pathNamer.Existing().GetKeys()) + { + namer.GetName(key); + } + } + // processGroup(i+1); + break; + } + else + { + // skip already-named bnodes + string bnode = group[n_2]; + if (namer.IsNamed(bnode)) + { + continue; + } + // hash bnode paths + UniqueNamer pathNamer = new UniqueNamer("_:b"); + pathNamer.GetName(bnode); + NormalizeUtils.HashResult result = HashPaths(bnode, bnodes, namer, pathNamer); + results.Add(result); + } + } + } + } + } + // hash unnamed bnode + string bnode_1 = unnamed[hui]; + string hash_1 = HashQuads(bnode_1, bnodes, namer); + // store hash as unique or a duplicate + if (duplicates.ContainsKey(hash_1)) + { + duplicates[hash_1].Add(bnode_1); + nextUnnamed.Add(bnode_1); + } + else + { + if (unique.ContainsKey(hash_1)) + { + IList tmp = new List(); + tmp.Add(unique[hash_1]); + tmp.Add(bnode_1); + duplicates[hash_1] = tmp; + nextUnnamed.Add(unique[hash_1]); + nextUnnamed.Add(bnode_1); + JsonLD.Collections.Remove(unique, hash_1); + } + else + { + unique[hash_1] = bnode_1; + } + } + } +#else + throw new PlatformNotSupportedException(); +#endif + } - private sealed class _IComparer_145 : IComparer - { - public _IComparer_145() - { - } + private sealed class _IComparer_145 : IComparer + { + public _IComparer_145() + { + } - public int Compare(NormalizeUtils.HashResult a, NormalizeUtils.HashResult b) - { - int res = string.CompareOrdinal(a.hash, b.hash); - return res; - } - } + public int Compare(NormalizeUtils.HashResult a, NormalizeUtils.HashResult b) + { + int res = string.CompareOrdinal(a.hash, b.hash); + return res; + } + } - private class HashResult - { - internal string hash; + private class HashResult + { + internal string hash; - internal UniqueNamer pathNamer; - } + internal UniqueNamer pathNamer; + } - /// - /// Produces a hash for the paths of adjacent bnodes for a bnode, - /// incorporating all information about its subgraph of bnodes. - /// - /// - /// Produces a hash for the paths of adjacent bnodes for a bnode, - /// incorporating all information about its subgraph of bnodes. This method - /// will recursively pick adjacent bnode permutations that produce the - /// lexicographically-least 'path' serializations. - /// - /// the ID of the bnode to hash paths for. - /// the map of bnode quads. - /// the canonical bnode namer. - /// the namer used to assign names to adjacent bnodes. - /// (err, result) called once the operation completes. + /// + /// Produces a hash for the paths of adjacent bnodes for a bnode, + /// incorporating all information about its subgraph of bnodes. + /// + /// + /// Produces a hash for the paths of adjacent bnodes for a bnode, + /// incorporating all information about its subgraph of bnodes. This method + /// will recursively pick adjacent bnode permutations that produce the + /// lexicographically-least 'path' serializations. + /// + /// the ID of the bnode to hash paths for. + /// the map of bnode quads. + /// the canonical bnode namer. + /// the namer used to assign names to adjacent bnodes. + /// (err, result) called once the operation completes. private static NormalizeUtils.HashResult HashPaths(string id, IDictionary> bnodes, UniqueNamer namer, UniqueNamer pathNamer) - { - try - { - // create SHA-1 digest - MessageDigest md = MessageDigest.GetInstance("SHA-1"); - JObject groups = new JObject(); - IList groupHashes; - IList quads = (IList)bnodes[id]["quads"]; - for (int hpi = 0; ; hpi++) - { - if (hpi == quads.Count) - { - // done , hash groups - groupHashes = new List(groups.GetKeys()); + { +#if !PORTABLE + try + { + // create SHA-1 digest + MessageDigest md = MessageDigest.GetInstance("SHA-1"); + JObject groups = new JObject(); + IList groupHashes; + IList quads = (IList)bnodes[id]["quads"]; + for (int hpi = 0; ; hpi++) + { + if (hpi == quads.Count) + { + // done , hash groups + groupHashes = new List(groups.GetKeys()); ((List)groupHashes).Sort(StringComparer.CurrentCultureIgnoreCase); - for (int hgi = 0; ; hgi++) - { - if (hgi == groupHashes.Count) - { - NormalizeUtils.HashResult res = new NormalizeUtils.HashResult(); - res.hash = EncodeHex(md.Digest()); - res.pathNamer = pathNamer; - return res; - } - // digest group hash - string groupHash = groupHashes[hgi]; - md.Update(JsonLD.JavaCompat.GetBytesForString(groupHash, "UTF-8")); - // choose a path and namer from the permutations - string chosenPath = null; - UniqueNamer chosenNamer = null; - NormalizeUtils.Permutator permutator = new NormalizeUtils.Permutator((JArray)groups[groupHash]); - while (true) - { - bool contPermutation = false; - bool breakOut = false; - JArray permutation = permutator.Next(); - UniqueNamer pathNamerCopy = pathNamer.Clone(); - // build adjacent path - string path = string.Empty; - JArray recurse = new JArray(); - foreach (string bnode in permutation) - { - // use canonical name if available - if (namer.IsNamed(bnode)) - { - path += namer.GetName(bnode); - } - else - { - // recurse if bnode isn't named in the path - // yet - if (!pathNamerCopy.IsNamed(bnode)) - { - recurse.Add(bnode); - } - path += pathNamerCopy.GetName(bnode); - } - // skip permutation if path is already >= chosen - // path - if (chosenPath != null && path.Length >= chosenPath.Length && string.CompareOrdinal - (path, chosenPath) > 0) - { - // return nextPermutation(true); - if (permutator.HasNext()) - { - contPermutation = true; - } - else - { - // digest chosen path and update namer - md.Update(JsonLD.JavaCompat.GetBytesForString(chosenPath, "UTF-8")); - pathNamer = chosenNamer; - // hash the nextGroup - breakOut = true; - } - break; - } - } - // if we should do the next permutation - if (contPermutation) - { - continue; - } - // if we should stop processing this group - if (breakOut) - { - break; - } - // does the next recursion - for (int nrn = 0; ; nrn++) - { - if (nrn == recurse.Count) - { - // return nextPermutation(false); - if (chosenPath == null || string.CompareOrdinal(path, chosenPath) < 0) - { - chosenPath = path; - chosenNamer = pathNamerCopy; - } - if (!permutator.HasNext()) - { - // digest chosen path and update namer - md.Update(JsonLD.JavaCompat.GetBytesForString(chosenPath, "UTF-8")); - pathNamer = chosenNamer; - // hash the nextGroup - breakOut = true; - } - break; - } - // do recursion - string bnode_1 = (string)recurse[nrn]; - NormalizeUtils.HashResult result = HashPaths(bnode_1, bnodes, namer, pathNamerCopy); - path += pathNamerCopy.GetName(bnode_1) + "<" + result.hash + ">"; - pathNamerCopy = result.pathNamer; - // skip permutation if path is already >= chosen - // path - if (chosenPath != null && path.Length >= chosenPath.Length && string.CompareOrdinal - (path, chosenPath) > 0) - { - // return nextPermutation(true); - if (!permutator.HasNext()) - { - // digest chosen path and update namer - md.Update(JsonLD.JavaCompat.GetBytesForString(chosenPath, "UTF-8")); - pathNamer = chosenNamer; - // hash the nextGroup - breakOut = true; - } - break; - } - } - // do next recursion - // if we should stop processing this group - if (breakOut) - { - break; - } - } - } - } - // get adjacent bnode + for (int hgi = 0; ; hgi++) + { + if (hgi == groupHashes.Count) + { + NormalizeUtils.HashResult res = new NormalizeUtils.HashResult(); + res.hash = EncodeHex(md.Digest()); + res.pathNamer = pathNamer; + return res; + } + // digest group hash + string groupHash = groupHashes[hgi]; + md.Update(JsonLD.JavaCompat.GetBytesForString(groupHash, "UTF-8")); + // choose a path and namer from the permutations + string chosenPath = null; + UniqueNamer chosenNamer = null; + NormalizeUtils.Permutator permutator = new NormalizeUtils.Permutator((JArray)groups[groupHash]); + while (true) + { + bool contPermutation = false; + bool breakOut = false; + JArray permutation = permutator.Next(); + UniqueNamer pathNamerCopy = pathNamer.Clone(); + // build adjacent path + string path = string.Empty; + JArray recurse = new JArray(); + foreach (string bnode in permutation) + { + // use canonical name if available + if (namer.IsNamed(bnode)) + { + path += namer.GetName(bnode); + } + else + { + // recurse if bnode isn't named in the path + // yet + if (!pathNamerCopy.IsNamed(bnode)) + { + recurse.Add(bnode); + } + path += pathNamerCopy.GetName(bnode); + } + // skip permutation if path is already >= chosen + // path + if (chosenPath != null && path.Length >= chosenPath.Length && string.CompareOrdinal + (path, chosenPath) > 0) + { + // return nextPermutation(true); + if (permutator.HasNext()) + { + contPermutation = true; + } + else + { + // digest chosen path and update namer + md.Update(JsonLD.JavaCompat.GetBytesForString(chosenPath, "UTF-8")); + pathNamer = chosenNamer; + // hash the nextGroup + breakOut = true; + } + break; + } + } + // if we should do the next permutation + if (contPermutation) + { + continue; + } + // if we should stop processing this group + if (breakOut) + { + break; + } + // does the next recursion + for (int nrn = 0; ; nrn++) + { + if (nrn == recurse.Count) + { + // return nextPermutation(false); + if (chosenPath == null || string.CompareOrdinal(path, chosenPath) < 0) + { + chosenPath = path; + chosenNamer = pathNamerCopy; + } + if (!permutator.HasNext()) + { + // digest chosen path and update namer + md.Update(JsonLD.JavaCompat.GetBytesForString(chosenPath, "UTF-8")); + pathNamer = chosenNamer; + // hash the nextGroup + breakOut = true; + } + break; + } + // do recursion + string bnode_1 = (string)recurse[nrn]; + NormalizeUtils.HashResult result = HashPaths(bnode_1, bnodes, namer, pathNamerCopy); + path += pathNamerCopy.GetName(bnode_1) + "<" + result.hash + ">"; + pathNamerCopy = result.pathNamer; + // skip permutation if path is already >= chosen + // path + if (chosenPath != null && path.Length >= chosenPath.Length && string.CompareOrdinal + (path, chosenPath) > 0) + { + // return nextPermutation(true); + if (!permutator.HasNext()) + { + // digest chosen path and update namer + md.Update(JsonLD.JavaCompat.GetBytesForString(chosenPath, "UTF-8")); + pathNamer = chosenNamer; + // hash the nextGroup + breakOut = true; + } + break; + } + } + // do next recursion + // if we should stop processing this group + if (breakOut) + { + break; + } + } + } + } + // get adjacent bnode IDictionary quad = (IDictionary)quads[hpi]; string bnode_2 = GetAdjacentBlankNodeName((IDictionary)quad["subject" - ], id); - string direction = null; - if (bnode_2 != null) - { - // normal property - direction = "p"; - } - else - { + ], id); + string direction = null; + if (bnode_2 != null) + { + // normal property + direction = "p"; + } + else + { bnode_2 = GetAdjacentBlankNodeName((IDictionary)quad["object"], id - ); - if (bnode_2 != null) - { - // reverse property - direction = "r"; - } - } - if (bnode_2 != null) - { - // get bnode name (try canonical, path, then hash) - string name; - if (namer.IsNamed(bnode_2)) - { - name = namer.GetName(bnode_2); - } - else - { - if (pathNamer.IsNamed(bnode_2)) - { - name = pathNamer.GetName(bnode_2); - } - else - { - name = HashQuads(bnode_2, bnodes, namer); - } - } - // hash direction, property, end bnode name/hash - MessageDigest md1 = MessageDigest.GetInstance("SHA-1"); - // String toHash = direction + (String) ((Map) quad.get("predicate")).get("value") + name; - md1.Update(JsonLD.JavaCompat.GetBytesForString(direction, "UTF-8")); + ); + if (bnode_2 != null) + { + // reverse property + direction = "r"; + } + } + if (bnode_2 != null) + { + // get bnode name (try canonical, path, then hash) + string name; + if (namer.IsNamed(bnode_2)) + { + name = namer.GetName(bnode_2); + } + else + { + if (pathNamer.IsNamed(bnode_2)) + { + name = pathNamer.GetName(bnode_2); + } + else + { + name = HashQuads(bnode_2, bnodes, namer); + } + } + // hash direction, property, end bnode name/hash + MessageDigest md1 = MessageDigest.GetInstance("SHA-1"); + // String toHash = direction + (String) ((Map) quad.get("predicate")).get("value") + name; + md1.Update(JsonLD.JavaCompat.GetBytesForString(direction, "UTF-8")); md1.Update(JsonLD.JavaCompat.GetBytesForString(((string)((IDictionary)quad["predicate"])["value"]), "UTF-8")); - md1.Update(JsonLD.JavaCompat.GetBytesForString(name, "UTF-8")); - string groupHash = EncodeHex(md1.Digest()); - if (groups.ContainsKey(groupHash)) - { - ((JArray)groups[groupHash]).Add(bnode_2); - } - else - { + md1.Update(JsonLD.JavaCompat.GetBytesForString(name, "UTF-8")); + string groupHash = EncodeHex(md1.Digest()); + if (groups.ContainsKey(groupHash)) + { + ((JArray)groups[groupHash]).Add(bnode_2); + } + else + { JArray tmp = new JArray(); - tmp.Add(bnode_2); - groups[groupHash] = tmp; - } - } - } - } - catch - { - // TODO: i don't expect that SHA-1 is even NOT going to be - // available? - // look into this further - throw; - } - } + tmp.Add(bnode_2); + groups[groupHash] = tmp; + } + } + } + } + catch + { + // TODO: i don't expect that SHA-1 is even NOT going to be + // available? + // look into this further + throw; + } +#else + throw new PlatformNotSupportedException(); +#endif + } - /// Hashes all of the quads about a blank node. - /// Hashes all of the quads about a blank node. - /// the ID of the bnode to hash quads for. - /// the mapping of bnodes to quads. - /// the canonical bnode namer. - /// the new hash. + /// Hashes all of the quads about a blank node. + /// Hashes all of the quads about a blank node. + /// the ID of the bnode to hash quads for. + /// the mapping of bnodes to quads. + /// the canonical bnode namer. + /// the new hash. private static string HashQuads(string id, IDictionary> bnodes, UniqueNamer - namer) - { - // return cached hash - if (bnodes[id].ContainsKey("hash")) - { - return (string)bnodes[id]["hash"]; - } - // serialize all of bnode's quads + namer) + { + // return cached hash + if (bnodes[id].ContainsKey("hash")) + { + return (string)bnodes[id]["hash"]; + } + // serialize all of bnode's quads IList quads = (IList)bnodes[id]["quads"]; - IList nquads = new List(); - for (int i = 0; i < quads.Count; ++i) - { + IList nquads = new List(); + for (int i = 0; i < quads.Count; ++i) + { object name; nquads.Add(RDFDatasetUtils.ToNQuad((RDFDataset.Quad)quads[i], quads[i].TryGetValue("name", out name) ? (string)((IDictionary)name)["value"] : null, id)); - } - // sort serialized quads - nquads.SortInPlace(StringComparer.Ordinal); - // return hashed quads - string hash = Sha1hash(nquads); + } + // sort serialized quads + nquads.SortInPlace(StringComparer.Ordinal); + // return hashed quads + string hash = Sha1hash(nquads); ((IDictionary)bnodes[id])["hash"] = hash; - return hash; - } + return hash; + } - /// A helper class to sha1 hash all the strings in a collection - /// - /// - private static string Sha1hash(ICollection nquads) - { - try - { - // create SHA-1 digest - MessageDigest md = MessageDigest.GetInstance("SHA-1"); - foreach (string nquad in nquads) - { - md.Update(JsonLD.JavaCompat.GetBytesForString(nquad, "UTF-8")); - } - return EncodeHex(md.Digest()); - } + /// A helper class to sha1 hash all the strings in a collection + /// + /// + private static string Sha1hash(ICollection nquads) + { +#if !PORTABLE + try + { + // create SHA-1 digest + MessageDigest md = MessageDigest.GetInstance("SHA-1"); + foreach (string nquad in nquads) + { + md.Update(JsonLD.JavaCompat.GetBytesForString(nquad, "UTF-8")); + } + return EncodeHex(md.Digest()); + } //catch (NoSuchAlgorithmException e) //{ // throw new Exception(e); //} - catch - { - throw; - } - } + catch + { + throw; + } +#else + throw new PlatformNotSupportedException(); +#endif + } - // TODO: this is something to optimize - private static string EncodeHex(byte[] data) - { - string rval = string.Empty; - foreach (byte b in data) - { - rval += b.ToString("x2"); - } - return rval; - } + // TODO: this is something to optimize + private static string EncodeHex(byte[] data) + { + string rval = string.Empty; + foreach (byte b in data) + { + rval += b.ToString("x2"); + } + return rval; + } - /// - /// A helper function that gets the blank node name from an RDF quad node - /// (subject or object). - /// - /// - /// A helper function that gets the blank node name from an RDF quad node - /// (subject or object). If the node is a blank node and its value does not - /// match the given blank node ID, it will be returned. - /// - /// the RDF quad node. - /// the ID of the blank node to look next to. - /// the adjacent blank node name or null if none was found. + /// + /// A helper function that gets the blank node name from an RDF quad node + /// (subject or object). + /// + /// + /// A helper function that gets the blank node name from an RDF quad node + /// (subject or object). If the node is a blank node and its value does not + /// match the given blank node ID, it will be returned. + /// + /// the RDF quad node. + /// the ID of the blank node to look next to. + /// the adjacent blank node name or null if none was found. private static string GetAdjacentBlankNodeName(IDictionary node, string id) - { - return (string)node["type"] == "blank node" && (!node.ContainsKey("value") || (string)node["value"] != id) ? (string)node["value"] : null; - } + { + return (string)node["type"] == "blank node" && (!node.ContainsKey("value") || (string)node["value"] != id) ? (string)node["value"] : null; + } - private class Permutator - { - private readonly JArray list; + private class Permutator + { + private readonly JArray list; - private bool done; + private bool done; - private readonly IDictionary left; + private readonly IDictionary left; public Permutator(JArray list) - { + { this.list = (JArray)JsonLdUtils.Clone(list); - this.list.SortInPlace(); - this.done = false; - this.left = new Dictionary(); - foreach (string i in this.list) - { - this.left[i] = true; - } - } + this.list.SortInPlace(); + this.done = false; + this.left = new Dictionary(); + foreach (string i in this.list) + { + this.left[i] = true; + } + } - /// Returns true if there is another permutation. - /// Returns true if there is another permutation. - /// true if there is another permutation, false if not. - public virtual bool HasNext() - { - return !this.done; - } + /// Returns true if there is another permutation. + /// Returns true if there is another permutation. + /// true if there is another permutation, false if not. + public virtual bool HasNext() + { + return !this.done; + } - /// Gets the next permutation. - /// - /// Gets the next permutation. Call hasNext() to ensure there is another - /// one first. - /// - /// the next permutation. + /// Gets the next permutation. + /// + /// Gets the next permutation. Call hasNext() to ensure there is another + /// one first. + /// + /// the next permutation. public virtual JArray Next() - { + { JArray rval = (JArray)JsonLdUtils.Clone(this.list); - // Calculate the next permutation using Steinhaus-Johnson-Trotter - // permutation algoritm - // get largest mobile element k - // (mobile: element is grater than the one it is looking at) - string k = null; - int pos = 0; - int length = this.list.Count; - for (int i = 0; i < length; ++i) - { - string element = (string)this.list[i]; - bool left = this.left[element]; - if ((k == null || string.CompareOrdinal(element, k) > 0) && ((left && i > 0 && string.CompareOrdinal - (element, (string)this.list[i - 1]) > 0) || (!left && i < (length - 1) && string.CompareOrdinal - (element, (string)this.list[i + 1]) > 0))) - { - k = element; - pos = i; - } - } - // no more permutations - if (k == null) - { - this.done = true; - } - else - { - // swap k and the element it is looking at - int swap = this.left[k] ? pos - 1 : pos + 1; - this.list[pos] = this.list[swap]; - this.list[swap] = k; - // reverse the direction of all element larger than k - for (int i_1 = 0; i_1 < length; i_1++) - { - if (string.CompareOrdinal((string)this.list[i_1], k) > 0) - { - this.left[(string)this.list[i_1]] = !this.left[(string)this.list[i_1]]; - } - } - } - return rval; - } - } - } -#endif + // Calculate the next permutation using Steinhaus-Johnson-Trotter + // permutation algoritm + // get largest mobile element k + // (mobile: element is grater than the one it is looking at) + string k = null; + int pos = 0; + int length = this.list.Count; + for (int i = 0; i < length; ++i) + { + string element = (string)this.list[i]; + bool left = this.left[element]; + if ((k == null || string.CompareOrdinal(element, k) > 0) && ((left && i > 0 && string.CompareOrdinal + (element, (string)this.list[i - 1]) > 0) || (!left && i < (length - 1) && string.CompareOrdinal + (element, (string)this.list[i + 1]) > 0))) + { + k = element; + pos = i; + } + } + // no more permutations + if (k == null) + { + this.done = true; + } + else + { + // swap k and the element it is looking at + int swap = this.left[k] ? pos - 1 : pos + 1; + this.list[pos] = this.list[swap]; + this.list[swap] = k; + // reverse the direction of all element larger than k + for (int i_1 = 0; i_1 < length; i_1++) + { + if (string.CompareOrdinal((string)this.list[i_1], k) > 0) + { + this.left[(string)this.list[i_1]] = !this.left[(string)this.list[i_1]]; + } + } + } + return rval; + } + } + } } diff --git a/src/JsonLD/Core/RDFDataset.cs b/src/JsonLD/Core/RDFDataset.cs index a8c126f..6823ad3 100644 --- a/src/JsonLD/Core/RDFDataset.cs +++ b/src/JsonLD/Core/RDFDataset.cs @@ -5,807 +5,807 @@ namespace JsonLD.Core { - /// - /// Starting to migrate away from using plain java Maps as the internal RDF - /// dataset store. - /// - /// - /// Starting to migrate away from using plain java Maps as the internal RDF - /// dataset store. Currently each item just wraps a Map based on the old format - /// so everything doesn't break. Will phase this out once everything is using the - /// new format. - /// - /// Tristan - //[System.Serializable] - public class RDFDataset : Dictionary - { - //[System.Serializable] - public class Quad : Dictionary, IComparable - { - public Quad(string subject, string predicate, string @object, string graph) : this - (subject, predicate, @object.StartsWith("_:") ? (Node)new RDFDataset.BlankNode(@object - ) : (Node)new RDFDataset.IRI(@object), graph) - { - } - - public Quad(string subject, string predicate, string value, string datatype, string - language, string graph) : this(subject, predicate, new RDFDataset.Literal(value - , datatype, language), graph) - { - } - - private Quad(string subject, string predicate, RDFDataset.Node @object, string graph - ) : this(subject.StartsWith("_:") ? (Node)new RDFDataset.BlankNode(subject) : (Node)new RDFDataset.IRI - (subject), new RDFDataset.IRI(predicate), @object, graph) - { - } - - public Quad(RDFDataset.Node subject, RDFDataset.Node predicate, RDFDataset.Node @object - , string graph) : base() - { - this["subject"] = subject; - this["predicate"] = predicate; - this["object"] = @object; - if (graph != null && !"@default".Equals(graph)) - { - // TODO: i'm not yet sure if this should be added or if the - // graph should only be represented by the keys in the dataset - this["name"] = graph.StartsWith("_:") ? (Node)new RDFDataset.BlankNode(graph) : (Node)new RDFDataset.IRI - (graph); - } - } - - public virtual RDFDataset.Node GetSubject() - { - return (RDFDataset.Node)this["subject"]; - } - - public virtual RDFDataset.Node GetPredicate() - { - return (RDFDataset.Node)this["predicate"]; - } - - public virtual RDFDataset.Node GetObject() - { - return (RDFDataset.Node)this["object"]; - } - - public virtual RDFDataset.Node GetGraph() - { - return (RDFDataset.Node)this["name"]; - } - - public virtual int CompareTo(RDFDataset.Quad o) - { - if (o == null) - { - return 1; - } - int rval = GetGraph().CompareTo(o.GetGraph()); - if (rval != 0) - { - return rval; - } - rval = GetSubject().CompareTo(o.GetSubject()); - if (rval != 0) - { - return rval; - } - rval = GetPredicate().CompareTo(o.GetPredicate()); - if (rval != 0) - { - return rval; - } - return GetObject().CompareTo(o.GetObject()); - } - } - - //[System.Serializable] - public abstract class Node : Dictionary, IComparable - { - public abstract bool IsLiteral(); - - public abstract bool IsIRI(); - - public abstract bool IsBlankNode(); - - public virtual string GetValue() - { + /// + /// Starting to migrate away from using plain java Maps as the internal RDF + /// dataset store. + /// + /// + /// Starting to migrate away from using plain java Maps as the internal RDF + /// dataset store. Currently each item just wraps a Map based on the old format + /// so everything doesn't break. Will phase this out once everything is using the + /// new format. + /// + /// Tristan + //[System.Serializable] + public class RDFDataset : Dictionary + { + //[System.Serializable] + public class Quad : Dictionary, IComparable + { + public Quad(string subject, string predicate, string @object, string graph) : this + (subject, predicate, @object.StartsWith("_:") ? (Node)new RDFDataset.BlankNode(@object + ) : (Node)new RDFDataset.IRI(@object), graph) + { + } + + public Quad(string subject, string predicate, string value, string datatype, string + language, string graph) : this(subject, predicate, new RDFDataset.Literal(value + , datatype, language), graph) + { + } + + private Quad(string subject, string predicate, RDFDataset.Node @object, string graph + ) : this(subject.StartsWith("_:") ? (Node)new RDFDataset.BlankNode(subject) : (Node)new RDFDataset.IRI + (subject), new RDFDataset.IRI(predicate), @object, graph) + { + } + + public Quad(RDFDataset.Node subject, RDFDataset.Node predicate, RDFDataset.Node @object + , string graph) : base() + { + this["subject"] = subject; + this["predicate"] = predicate; + this["object"] = @object; + if (graph != null && !"@default".Equals(graph)) + { + // TODO: i'm not yet sure if this should be added or if the + // graph should only be represented by the keys in the dataset + this["name"] = graph.StartsWith("_:") ? (Node)new RDFDataset.BlankNode(graph) : (Node)new RDFDataset.IRI + (graph); + } + } + + public virtual RDFDataset.Node GetSubject() + { + return (RDFDataset.Node)this["subject"]; + } + + public virtual RDFDataset.Node GetPredicate() + { + return (RDFDataset.Node)this["predicate"]; + } + + public virtual RDFDataset.Node GetObject() + { + return (RDFDataset.Node)this["object"]; + } + + public virtual RDFDataset.Node GetGraph() + { + return (RDFDataset.Node)this["name"]; + } + + public virtual int CompareTo(RDFDataset.Quad o) + { + if (o == null) + { + return 1; + } + int rval = GetGraph().CompareTo(o.GetGraph()); + if (rval != 0) + { + return rval; + } + rval = GetSubject().CompareTo(o.GetSubject()); + if (rval != 0) + { + return rval; + } + rval = GetPredicate().CompareTo(o.GetPredicate()); + if (rval != 0) + { + return rval; + } + return GetObject().CompareTo(o.GetObject()); + } + } + + //[System.Serializable] + public abstract class Node : Dictionary, IComparable + { + public abstract bool IsLiteral(); + + public abstract bool IsIRI(); + + public abstract bool IsBlankNode(); + + public virtual string GetValue() + { object value; return this.TryGetValue("value", out value) ? (string)value : null; - } + } - public virtual string GetDatatype() - { + public virtual string GetDatatype() + { object value; return this.TryGetValue("datatype", out value) ? (string)value : null; - } + } - public virtual string GetLanguage() - { + public virtual string GetLanguage() + { object value; return this.TryGetValue("language", out value) ? (string)value : null; - } - - public virtual int CompareTo(RDFDataset.Node o) - { - if (this.IsIRI()) - { - if (!o.IsIRI()) - { - // IRIs > everything - return 1; - } - } - else - { - if (this.IsBlankNode()) - { - if (o.IsIRI()) - { - // IRI > blank node - return -1; - } - else - { - if (o.IsLiteral()) - { - // blank node > literal - return 1; - } - } - } - } - return string.CompareOrdinal(this.GetValue(), o.GetValue()); - } - - /// Converts an RDF triple object to a JSON-LD object. - /// Converts an RDF triple object to a JSON-LD object. - /// the RDF triple object to convert. - /// true to output native types, false not to. - /// the JSON-LD object. - /// JsonLdError - /// - internal virtual JObject ToObject(bool useNativeTypes) - { - // If value is an an IRI or a blank node identifier, return a new - // JSON object consisting - // of a single member @id whose value is set to value. - if (IsIRI() || IsBlankNode()) - { + } + + public virtual int CompareTo(RDFDataset.Node o) + { + if (this.IsIRI()) + { + if (!o.IsIRI()) + { + // IRIs > everything + return 1; + } + } + else + { + if (this.IsBlankNode()) + { + if (o.IsIRI()) + { + // IRI > blank node + return -1; + } + else + { + if (o.IsLiteral()) + { + // blank node > literal + return 1; + } + } + } + } + return string.CompareOrdinal(this.GetValue(), o.GetValue()); + } + + /// Converts an RDF triple object to a JSON-LD object. + /// Converts an RDF triple object to a JSON-LD object. + /// the RDF triple object to convert. + /// true to output native types, false not to. + /// the JSON-LD object. + /// JsonLdError + /// + internal virtual JObject ToObject(bool useNativeTypes) + { + // If value is an an IRI or a blank node identifier, return a new + // JSON object consisting + // of a single member @id whose value is set to value. + if (IsIRI() || IsBlankNode()) + { JObject obj = new JObject(); obj["@id"] = GetValue(); - return obj; - } - // convert literal object to JSON-LD - JObject rval = new JObject(); + return obj; + } + // convert literal object to JSON-LD + JObject rval = new JObject(); rval["@value"] = GetValue(); - // add language - if (GetLanguage() != null) - { - rval["@language"] = GetLanguage(); - } - else - { - // add datatype - string type = GetDatatype(); - string value = GetValue(); - if (useNativeTypes) - { - // use native datatypes for certain xsd types - if (JSONLDConsts.XsdString.Equals(type)) - { - } - else - { - // don't add xsd:string - if (JSONLDConsts.XsdBoolean.Equals(type)) - { - if ("true".Equals(value)) - { - rval["@value"] = true; - } - else - { - if ("false".Equals(value)) - { - rval["@value"] = false; - } - } - } - else - { - if (Pattern.Matches(value, "^[+-]?[0-9]+((?:\\.?[0-9]+((?:E?[+-]?[0-9]+)|)|))$")) - { - try - { - double d = double.Parse(value); - if (!double.IsNaN(d) && !double.IsInfinity(d)) - { - if (JSONLDConsts.XsdInteger.Equals(type)) - { - int i = (int)d; - if (i.ToString().Equals(value)) - { - rval["@value"] = i; - } - } - else - { - if (JSONLDConsts.XsdDouble.Equals(type)) - { - rval["@value"] = d; - } - else - { - // we don't know the type, so we should add - // it to the JSON-LD - rval["@type"] = type; - } - } - } - } - catch - { - // TODO: This should never happen since we match the - // value with regex! - throw; - } - } - else - { - // do not add xsd:string type - rval["@type"] = type; - } - } - } - } - else - { - if (!JSONLDConsts.XsdString.Equals(type)) - { - rval["@type"] = type; - } - } - } - return rval; - } - } - - //[System.Serializable] - public class Literal : RDFDataset.Node - { - public Literal(string value, string datatype, string language) : base() - { - this["type"] = "literal"; - this["value"] = value; - this["datatype"] = datatype != null ? datatype : JSONLDConsts.XsdString; - if (language != null) - { - this["language"] = language; - } - } - - public override bool IsLiteral() - { - return true; - } - - public override bool IsIRI() - { - return false; - } - - public override bool IsBlankNode() - { - return false; - } - - public override int CompareTo(RDFDataset.Node o) - { - if (o == null) - { - // valid nodes are > null nodes - return 1; - } - if (o.IsIRI()) - { - // literals < iri - return -1; - } - if (o.IsBlankNode()) - { - // blank node < iri - return -1; - } - if (this.GetLanguage() == null && ((RDFDataset.Literal)o).GetLanguage() != null) - { - return -1; - } - else - { - if (this.GetLanguage() != null && ((RDFDataset.Literal)o).GetLanguage() == null) - { - return 1; - } - } - if (this.GetDatatype() != null) - { - return string.CompareOrdinal(this.GetDatatype(), ((RDFDataset.Literal)o).GetDatatype - ()); - } - else - { - if (((RDFDataset.Literal)o).GetDatatype() != null) - { - return -1; - } - } - return 0; - } - } - - //[System.Serializable] - public class IRI : RDFDataset.Node - { - public IRI(string iri) : base() - { - this["type"] = "IRI"; - this["value"] = iri; - } - - public override bool IsLiteral() - { - return false; - } - - public override bool IsIRI() - { - return true; - } - - public override bool IsBlankNode() - { - return false; - } - } - - //[System.Serializable] - public class BlankNode : RDFDataset.Node - { - public BlankNode(string attribute) : base() - { - this["type"] = "blank node"; - this["value"] = attribute; - } - - public override bool IsLiteral() - { - return false; - } - - public override bool IsIRI() - { - return false; - } - - public override bool IsBlankNode() - { - return true; - } - } - - private static readonly RDFDataset.Node first = new RDFDataset.IRI(JSONLDConsts.RdfFirst - ); - - private static readonly RDFDataset.Node rest = new RDFDataset.IRI(JSONLDConsts.RdfRest - ); - - private static readonly RDFDataset.Node nil = new RDFDataset.IRI(JSONLDConsts.RdfNil - ); - - private readonly IDictionary context; - - private JsonLdApi api; - - public RDFDataset() : base() - { - // private UniqueNamer namer; - this["@default"] = new List(); - context = new Dictionary(); - } - - public RDFDataset(JsonLdApi jsonLdApi) : this() - { - // put("@context", context); - this.api = jsonLdApi; - } - - public virtual void SetNamespace(string ns, string prefix) - { - context[ns] = prefix; - } - - public virtual string GetNamespace(string ns) - { - return context[ns]; - } - - /// clears all the namespaces in this dataset - public virtual void ClearNamespaces() - { - context.Clear(); - } - - public virtual IDictionary GetNamespaces() - { - return context; - } - - /// Returns a valid @context containing any namespaces set - /// - public virtual JObject GetContext() - { + // add language + if (GetLanguage() != null) + { + rval["@language"] = GetLanguage(); + } + else + { + // add datatype + string type = GetDatatype(); + string value = GetValue(); + if (useNativeTypes) + { + // use native datatypes for certain xsd types + if (JSONLDConsts.XsdString.Equals(type)) + { + } + else + { + // don't add xsd:string + if (JSONLDConsts.XsdBoolean.Equals(type)) + { + if ("true".Equals(value)) + { + rval["@value"] = true; + } + else + { + if ("false".Equals(value)) + { + rval["@value"] = false; + } + } + } + else + { + if (Pattern.Matches(value, "^[+-]?[0-9]+((?:\\.?[0-9]+((?:E?[+-]?[0-9]+)|)|))$")) + { + try + { + double d = double.Parse(value); + if (!double.IsNaN(d) && !double.IsInfinity(d)) + { + if (JSONLDConsts.XsdInteger.Equals(type)) + { + int i = (int)d; + if (i.ToString().Equals(value)) + { + rval["@value"] = i; + } + } + else + { + if (JSONLDConsts.XsdDouble.Equals(type)) + { + rval["@value"] = d; + } + else + { + // we don't know the type, so we should add + // it to the JSON-LD + rval["@type"] = type; + } + } + } + } + catch + { + // TODO: This should never happen since we match the + // value with regex! + throw; + } + } + else + { + // do not add xsd:string type + rval["@type"] = type; + } + } + } + } + else + { + if (!JSONLDConsts.XsdString.Equals(type)) + { + rval["@type"] = type; + } + } + } + return rval; + } + } + + //[System.Serializable] + public class Literal : RDFDataset.Node + { + public Literal(string value, string datatype, string language) : base() + { + this["type"] = "literal"; + this["value"] = value; + this["datatype"] = datatype != null ? datatype : JSONLDConsts.XsdString; + if (language != null) + { + this["language"] = language; + } + } + + public override bool IsLiteral() + { + return true; + } + + public override bool IsIRI() + { + return false; + } + + public override bool IsBlankNode() + { + return false; + } + + public override int CompareTo(RDFDataset.Node o) + { + if (o == null) + { + // valid nodes are > null nodes + return 1; + } + if (o.IsIRI()) + { + // literals < iri + return -1; + } + if (o.IsBlankNode()) + { + // blank node < iri + return -1; + } + if (this.GetLanguage() == null && ((RDFDataset.Literal)o).GetLanguage() != null) + { + return -1; + } + else + { + if (this.GetLanguage() != null && ((RDFDataset.Literal)o).GetLanguage() == null) + { + return 1; + } + } + if (this.GetDatatype() != null) + { + return string.CompareOrdinal(this.GetDatatype(), ((RDFDataset.Literal)o).GetDatatype + ()); + } + else + { + if (((RDFDataset.Literal)o).GetDatatype() != null) + { + return -1; + } + } + return 0; + } + } + + //[System.Serializable] + public class IRI : RDFDataset.Node + { + public IRI(string iri) : base() + { + this["type"] = "IRI"; + this["value"] = iri; + } + + public override bool IsLiteral() + { + return false; + } + + public override bool IsIRI() + { + return true; + } + + public override bool IsBlankNode() + { + return false; + } + } + + //[System.Serializable] + public class BlankNode : RDFDataset.Node + { + public BlankNode(string attribute) : base() + { + this["type"] = "blank node"; + this["value"] = attribute; + } + + public override bool IsLiteral() + { + return false; + } + + public override bool IsIRI() + { + return false; + } + + public override bool IsBlankNode() + { + return true; + } + } + + private static readonly RDFDataset.Node first = new RDFDataset.IRI(JSONLDConsts.RdfFirst + ); + + private static readonly RDFDataset.Node rest = new RDFDataset.IRI(JSONLDConsts.RdfRest + ); + + private static readonly RDFDataset.Node nil = new RDFDataset.IRI(JSONLDConsts.RdfNil + ); + + private readonly IDictionary context; + + private JsonLdApi api; + + public RDFDataset() : base() + { + // private UniqueNamer namer; + this["@default"] = new List(); + context = new Dictionary(); + } + + public RDFDataset(JsonLdApi jsonLdApi) : this() + { + // put("@context", context); + this.api = jsonLdApi; + } + + public virtual void SetNamespace(string ns, string prefix) + { + context[ns] = prefix; + } + + public virtual string GetNamespace(string ns) + { + return context[ns]; + } + + /// clears all the namespaces in this dataset + public virtual void ClearNamespaces() + { + context.Clear(); + } + + public virtual IDictionary GetNamespaces() + { + return context; + } + + /// Returns a valid @context containing any namespaces set + /// + public virtual JObject GetContext() + { JObject rval = new JObject(); - rval.PutAll(context); - // replace "" with "@vocab" - if (rval.ContainsKey(string.Empty)) - { - rval["@vocab"] = JsonLD.Collections.Remove(rval, string.Empty); - } - return rval; - } - - /// parses a @context object and sets any namespaces found within it - /// - public virtual void ParseContext(JObject context) - { - foreach (string key in context.GetKeys()) - { - JToken val = context[key]; - if ("@vocab".Equals(key)) - { - if (val.IsNull() || JsonLdUtils.IsString(val)) - { - SetNamespace(string.Empty, (string)val); - } - } - else - { - // TODO: the context is actually invalid, should we throw an - // exception? - if ("@context".Equals(key)) - { - // go deeper! - ParseContext((JObject)context["@context"]); - } - else - { - if (!JsonLdUtils.IsKeyword(key)) - { - // TODO: should we make sure val is a valid URI prefix (i.e. it - // ends with /# or ?) - // or is it ok that full URIs for terms are used? - if (val.Type == JTokenType.String) - { - SetNamespace(key, (string)context[key]); - } - else - { - if (JsonLdUtils.IsObject(val) && ((JObject)val).ContainsKey("@id" - )) - { - SetNamespace(key, (string)((JObject)val)["@id"]); - } - } - } - } - } - } - } - - /// Adds a triple to the @default graph of this dataset - /// the subject for the triple - /// the predicate for the triple - /// the value of the literal object for the triple - /// - /// the datatype of the literal object for the triple (null values - /// will default to xsd:string) - /// - /// the language of the literal object for the triple (or null) - /// - public virtual void AddTriple(string s, string p, string value, string datatype, - string language) - { - AddQuad(s, p, value, datatype, language, "@default"); - } - - /// Adds a triple to the specified graph of this dataset - /// the subject for the triple - /// the predicate for the triple - /// the value of the literal object for the triple - /// - /// the datatype of the literal object for the triple (null values - /// will default to xsd:string) - /// - /// the graph to add this triple to - /// the language of the literal object for the triple (or null) - /// - public virtual void AddQuad(string s, string p, string value, string datatype, string - language, string graph) - { - if (graph == null) - { - graph = "@default"; - } - if (!this.ContainsKey(graph)) - { - this[graph] = new List(); - } - ((IList)this[graph]).Add(new RDFDataset.Quad(s, p, value, datatype - , language, graph)); - } - - /// Adds a triple to the @default graph of this dataset - /// the subject for the triple - /// the predicate for the triple - /// the object for the triple - /// - /// the datatype of the literal object for the triple (null values - /// will default to xsd:string) - /// - /// the language of the literal object for the triple (or null) - /// - public virtual void AddTriple(string s, string p, string o) - { - AddQuad(s, p, o, "@default"); - } - - /// Adds a triple to thespecified graph of this dataset - /// the subject for the triple - /// the predicate for the triple - /// the object for the triple - /// - /// the datatype of the literal object for the triple (null values - /// will default to xsd:string) - /// - /// the graph to add this triple to - /// the language of the literal object for the triple (or null) - /// - public virtual void AddQuad(string s, string p, string o, string graph) - { - if (graph == null) - { - graph = "@default"; - } - if (!this.ContainsKey(graph)) - { - this[graph] = new List(); - } - ((IList)this[graph]).Add(new RDFDataset.Quad(s, p, o, graph)); - } - - /// Creates an array of RDF triples for the given graph. - /// Creates an array of RDF triples for the given graph. - /// the graph to create RDF triples for. - internal virtual void GraphToRDF(string graphName, JObject graph - ) - { - // 4.2) - IList triples = new List(); - // 4.3) + rval.PutAll(context); + // replace "" with "@vocab" + if (rval.ContainsKey(string.Empty)) + { + rval["@vocab"] = JsonLD.Collections.Remove(rval, string.Empty); + } + return rval; + } + + /// parses a @context object and sets any namespaces found within it + /// + public virtual void ParseContext(JObject context) + { + foreach (string key in context.GetKeys()) + { + JToken val = context[key]; + if ("@vocab".Equals(key)) + { + if (val.IsNull() || JsonLdUtils.IsString(val)) + { + SetNamespace(string.Empty, (string)val); + } + } + else + { + // TODO: the context is actually invalid, should we throw an + // exception? + if ("@context".Equals(key)) + { + // go deeper! + ParseContext((JObject)context["@context"]); + } + else + { + if (!JsonLdUtils.IsKeyword(key)) + { + // TODO: should we make sure val is a valid URI prefix (i.e. it + // ends with /# or ?) + // or is it ok that full URIs for terms are used? + if (val.Type == JTokenType.String) + { + SetNamespace(key, (string)context[key]); + } + else + { + if (JsonLdUtils.IsObject(val) && ((JObject)val).ContainsKey("@id" + )) + { + SetNamespace(key, (string)((JObject)val)["@id"]); + } + } + } + } + } + } + } + + /// Adds a triple to the @default graph of this dataset + /// the subject for the triple + /// the predicate for the triple + /// the value of the literal object for the triple + /// + /// the datatype of the literal object for the triple (null values + /// will default to xsd:string) + /// + /// the language of the literal object for the triple (or null) + /// + public virtual void AddTriple(string s, string p, string value, string datatype, + string language) + { + AddQuad(s, p, value, datatype, language, "@default"); + } + + /// Adds a triple to the specified graph of this dataset + /// the subject for the triple + /// the predicate for the triple + /// the value of the literal object for the triple + /// + /// the datatype of the literal object for the triple (null values + /// will default to xsd:string) + /// + /// the graph to add this triple to + /// the language of the literal object for the triple (or null) + /// + public virtual void AddQuad(string s, string p, string value, string datatype, string + language, string graph) + { + if (graph == null) + { + graph = "@default"; + } + if (!this.ContainsKey(graph)) + { + this[graph] = new List(); + } + ((IList)this[graph]).Add(new RDFDataset.Quad(s, p, value, datatype + , language, graph)); + } + + /// Adds a triple to the @default graph of this dataset + /// the subject for the triple + /// the predicate for the triple + /// the object for the triple + /// + /// the datatype of the literal object for the triple (null values + /// will default to xsd:string) + /// + /// the language of the literal object for the triple (or null) + /// + public virtual void AddTriple(string s, string p, string o) + { + AddQuad(s, p, o, "@default"); + } + + /// Adds a triple to thespecified graph of this dataset + /// the subject for the triple + /// the predicate for the triple + /// the object for the triple + /// + /// the datatype of the literal object for the triple (null values + /// will default to xsd:string) + /// + /// the graph to add this triple to + /// the language of the literal object for the triple (or null) + /// + public virtual void AddQuad(string s, string p, string o, string graph) + { + if (graph == null) + { + graph = "@default"; + } + if (!this.ContainsKey(graph)) + { + this[graph] = new List(); + } + ((IList)this[graph]).Add(new RDFDataset.Quad(s, p, o, graph)); + } + + /// Creates an array of RDF triples for the given graph. + /// Creates an array of RDF triples for the given graph. + /// the graph to create RDF triples for. + internal virtual void GraphToRDF(string graphName, JObject graph + ) + { + // 4.2) + IList triples = new List(); + // 4.3) IEnumerable subjects = graph.GetKeys(); - // Collections.sort(subjects); - foreach (string id in subjects) - { - if (JsonLdUtils.IsRelativeIri(id)) - { - continue; - } + // Collections.sort(subjects); + foreach (string id in subjects) + { + if (JsonLdUtils.IsRelativeIri(id)) + { + continue; + } JObject node = (JObject)graph[id]; JArray properties = new JArray(node.GetKeys()); - properties.SortInPlace(); - foreach (string property in properties) - { + properties.SortInPlace(); + foreach (string property in properties) + { var localProperty = property; - JArray values; - // 4.3.2.1) - if ("@type".Equals(localProperty)) - { - values = (JArray)node["@type"]; - localProperty = JSONLDConsts.RdfType; - } - else - { - // 4.3.2.2) - if (JsonLdUtils.IsKeyword(localProperty)) - { - continue; - } - else - { - // 4.3.2.3) - if (localProperty.StartsWith("_:") && !api.opts.GetProduceGeneralizedRdf()) - { - continue; - } - else - { - // 4.3.2.4) - if (JsonLdUtils.IsRelativeIri(localProperty)) - { - continue; - } - else - { - values = (JArray)node[localProperty]; - } - } - } - } - RDFDataset.Node subject; - if (id.IndexOf("_:") == 0) - { - // NOTE: don't rename, just set it as a blank node - subject = new RDFDataset.BlankNode(id); - } - else - { - subject = new RDFDataset.IRI(id); - } - // RDF predicates - RDFDataset.Node predicate; - if (localProperty.StartsWith("_:")) - { - predicate = new RDFDataset.BlankNode(localProperty); - } - else - { - predicate = new RDFDataset.IRI(localProperty); - } - foreach (JToken item in values) - { - // convert @list to triples - if (JsonLdUtils.IsList(item)) - { - JArray list = (JArray)((JObject)item)["@list"]; - RDFDataset.Node last = null; - RDFDataset.Node firstBNode = nil; - if (!list.IsEmpty()) - { - last = ObjectToRDF(list[list.Count - 1]); - firstBNode = new RDFDataset.BlankNode(api.GenerateBlankNodeIdentifier()); - } - triples.Add(new RDFDataset.Quad(subject, predicate, firstBNode, graphName)); - for (int i = 0; i < list.Count - 1; i++) - { - RDFDataset.Node @object = ObjectToRDF(list[i]); - triples.Add(new RDFDataset.Quad(firstBNode, first, @object, graphName)); - RDFDataset.Node restBNode = new RDFDataset.BlankNode(api.GenerateBlankNodeIdentifier - ()); - triples.Add(new RDFDataset.Quad(firstBNode, rest, restBNode, graphName)); - firstBNode = restBNode; - } - if (last != null) - { - triples.Add(new RDFDataset.Quad(firstBNode, first, last, graphName)); - triples.Add(new RDFDataset.Quad(firstBNode, rest, nil, graphName)); - } - } - else - { - // convert value or node object to triple - RDFDataset.Node @object = ObjectToRDF(item); - if (@object != null) - { - triples.Add(new RDFDataset.Quad(subject, predicate, @object, graphName)); - } - } - } - } - } - this[graphName] = triples; - } - - /// - /// Converts a JSON-LD value object to an RDF literal or a JSON-LD string or - /// node object to an RDF resource. - /// - /// - /// Converts a JSON-LD value object to an RDF literal or a JSON-LD string or - /// node object to an RDF resource. - /// - /// the JSON-LD value or node object. - /// the UniqueNamer to use to assign blank node names. - /// the RDF literal or RDF resource. - private RDFDataset.Node ObjectToRDF(JToken item) - { - // convert value object to RDF - if (JsonLdUtils.IsValue(item)) - { - JToken value = ((JObject)item)["@value"]; - JToken datatype = ((JObject)item)["@type"]; - // convert to XSD datatypes as appropriate - if (value.Type == JTokenType.Boolean || value.Type == JTokenType.Float || value.Type == JTokenType.Integer) - { - // convert to XSD datatype - if (value.Type == JTokenType.Boolean) - { - return new RDFDataset.Literal(value.ToString(), datatype.IsNull() ? JSONLDConsts.XsdBoolean - : (string)datatype, null); - } - else - { - if (value.Type == JTokenType.Float || datatype.SafeCompare(JSONLDConsts.XsdDouble)) - { + JArray values; + // 4.3.2.1) + if ("@type".Equals(localProperty)) + { + values = (JArray)node["@type"]; + localProperty = JSONLDConsts.RdfType; + } + else + { + // 4.3.2.2) + if (JsonLdUtils.IsKeyword(localProperty)) + { + continue; + } + else + { + // 4.3.2.3) + if (localProperty.StartsWith("_:") && !api.opts.GetProduceGeneralizedRdf()) + { + continue; + } + else + { + // 4.3.2.4) + if (JsonLdUtils.IsRelativeIri(localProperty)) + { + continue; + } + else + { + values = (JArray)node[localProperty]; + } + } + } + } + RDFDataset.Node subject; + if (id.IndexOf("_:") == 0) + { + // NOTE: don't rename, just set it as a blank node + subject = new RDFDataset.BlankNode(id); + } + else + { + subject = new RDFDataset.IRI(id); + } + // RDF predicates + RDFDataset.Node predicate; + if (localProperty.StartsWith("_:")) + { + predicate = new RDFDataset.BlankNode(localProperty); + } + else + { + predicate = new RDFDataset.IRI(localProperty); + } + foreach (JToken item in values) + { + // convert @list to triples + if (JsonLdUtils.IsList(item)) + { + JArray list = (JArray)((JObject)item)["@list"]; + RDFDataset.Node last = null; + RDFDataset.Node firstBNode = nil; + if (!list.IsEmpty()) + { + last = ObjectToRDF(list[list.Count - 1]); + firstBNode = new RDFDataset.BlankNode(api.GenerateBlankNodeIdentifier()); + } + triples.Add(new RDFDataset.Quad(subject, predicate, firstBNode, graphName)); + for (int i = 0; i < list.Count - 1; i++) + { + RDFDataset.Node @object = ObjectToRDF(list[i]); + triples.Add(new RDFDataset.Quad(firstBNode, first, @object, graphName)); + RDFDataset.Node restBNode = new RDFDataset.BlankNode(api.GenerateBlankNodeIdentifier + ()); + triples.Add(new RDFDataset.Quad(firstBNode, rest, restBNode, graphName)); + firstBNode = restBNode; + } + if (last != null) + { + triples.Add(new RDFDataset.Quad(firstBNode, first, last, graphName)); + triples.Add(new RDFDataset.Quad(firstBNode, rest, nil, graphName)); + } + } + else + { + // convert value or node object to triple + RDFDataset.Node @object = ObjectToRDF(item); + if (@object != null) + { + triples.Add(new RDFDataset.Quad(subject, predicate, @object, graphName)); + } + } + } + } + } + this[graphName] = triples; + } + + /// + /// Converts a JSON-LD value object to an RDF literal or a JSON-LD string or + /// node object to an RDF resource. + /// + /// + /// Converts a JSON-LD value object to an RDF literal or a JSON-LD string or + /// node object to an RDF resource. + /// + /// the JSON-LD value or node object. + /// the UniqueNamer to use to assign blank node names. + /// the RDF literal or RDF resource. + private RDFDataset.Node ObjectToRDF(JToken item) + { + // convert value object to RDF + if (JsonLdUtils.IsValue(item)) + { + JToken value = ((JObject)item)["@value"]; + JToken datatype = ((JObject)item)["@type"]; + // convert to XSD datatypes as appropriate + if (value.Type == JTokenType.Boolean || value.Type == JTokenType.Float || value.Type == JTokenType.Integer) + { + // convert to XSD datatype + if (value.Type == JTokenType.Boolean) + { + return new RDFDataset.Literal(value.ToString(), datatype.IsNull() ? JSONLDConsts.XsdBoolean + : (string)datatype, null); + } + else + { + if (value.Type == JTokenType.Float || datatype.SafeCompare(JSONLDConsts.XsdDouble)) + { // Workaround for Newtonsoft.Json's refusal to cast a JTokenType.Integer to a double. if (value.Type == JTokenType.Integer) { int number = (int)value; value = new JValue((double)number); } - // canonical double representation - return new RDFDataset.Literal(string.Format("{0:0.0###############E0}", (double)value), datatype.IsNull() ? JSONLDConsts.XsdDouble - : (string)datatype, null); - } - else - { - return new RDFDataset.Literal(string.Format("{0:0}",value), datatype.IsNull() ? JSONLDConsts.XsdInteger - : (string)datatype, null); - } - } - } - else - { - if (((JObject)item).ContainsKey("@language")) - { - return new RDFDataset.Literal((string)value, datatype.IsNull() ? JSONLDConsts.RdfLangstring - : (string)datatype, (string)((JObject)item)["@language"]); - } - else - { - return new RDFDataset.Literal((string)value, datatype.IsNull() ? JSONLDConsts.XsdString - : (string)datatype, null); - } - } - } - else - { - // convert string/node object to RDF - string id; - if (JsonLdUtils.IsObject(item)) - { - id = (string)((JObject)item)["@id"]; - if (JsonLdUtils.IsRelativeIri(id)) - { - return null; - } - } - else - { - id = (string)item; - } - if (id.IndexOf("_:") == 0) - { - // NOTE: once again no need to rename existing blank nodes - return new RDFDataset.BlankNode(id); - } - else - { - return new RDFDataset.IRI(id); - } - } - } - - public virtual IList GraphNames() - { - return new List(Keys); - } - - public virtual IList GetQuads(string graphName) - { - return (IList)this[graphName]; - } - } + // canonical double representation + return new RDFDataset.Literal(string.Format("{0:0.0###############E0}", (double)value), datatype.IsNull() ? JSONLDConsts.XsdDouble + : (string)datatype, null); + } + else + { + return new RDFDataset.Literal(string.Format("{0:0}",value), datatype.IsNull() ? JSONLDConsts.XsdInteger + : (string)datatype, null); + } + } + } + else + { + if (((JObject)item).ContainsKey("@language")) + { + return new RDFDataset.Literal((string)value, datatype.IsNull() ? JSONLDConsts.RdfLangstring + : (string)datatype, (string)((JObject)item)["@language"]); + } + else + { + return new RDFDataset.Literal((string)value, datatype.IsNull() ? JSONLDConsts.XsdString + : (string)datatype, null); + } + } + } + else + { + // convert string/node object to RDF + string id; + if (JsonLdUtils.IsObject(item)) + { + id = (string)((JObject)item)["@id"]; + if (JsonLdUtils.IsRelativeIri(id)) + { + return null; + } + } + else + { + id = (string)item; + } + if (id.IndexOf("_:") == 0) + { + // NOTE: once again no need to rename existing blank nodes + return new RDFDataset.BlankNode(id); + } + else + { + return new RDFDataset.IRI(id); + } + } + } + + public virtual IList GraphNames() + { + return new List(Keys); + } + + public virtual IList GetQuads(string graphName) + { + return (IList)this[graphName]; + } + } } diff --git a/src/JsonLD/Core/RDFDatasetUtils.cs b/src/JsonLD/Core/RDFDatasetUtils.cs index d23aea8..7663cc4 100644 --- a/src/JsonLD/Core/RDFDatasetUtils.cs +++ b/src/JsonLD/Core/RDFDatasetUtils.cs @@ -6,682 +6,682 @@ namespace JsonLD.Core { - public class RDFDatasetUtils - { - /// Creates an array of RDF triples for the given graph. - /// Creates an array of RDF triples for the given graph. - /// the graph to create RDF triples for. - /// a UniqueNamer for assigning blank node names. - /// the array of RDF triples for the given graph. - [Obsolete] - internal static JArray GraphToRDF(JObject graph, UniqueNamer - namer) - { - // use RDFDataset.graphToRDF - JArray rval = new JArray(); - foreach (string id in graph.GetKeys()) - { + public class RDFDatasetUtils + { + /// Creates an array of RDF triples for the given graph. + /// Creates an array of RDF triples for the given graph. + /// the graph to create RDF triples for. + /// a UniqueNamer for assigning blank node names. + /// the array of RDF triples for the given graph. + [Obsolete] + internal static JArray GraphToRDF(JObject graph, UniqueNamer + namer) + { + // use RDFDataset.graphToRDF + JArray rval = new JArray(); + foreach (string id in graph.GetKeys()) + { JObject node = (JObject)graph[id]; - JArray properties = new JArray(node.GetKeys()); - properties.SortInPlace(); + JArray properties = new JArray(node.GetKeys()); + properties.SortInPlace(); foreach (string property in properties) - { + { var eachProperty = property; - JToken items = node[eachProperty]; - if ("@type".Equals(eachProperty)) - { - eachProperty = JSONLDConsts.RdfType; - } - else - { - if (JsonLdUtils.IsKeyword(eachProperty)) - { - continue; - } - } - foreach (JToken item in (JArray)items) - { - // RDF subjects - JObject subject = new JObject(); - if (id.IndexOf("_:") == 0) - { - subject["type"] = "blank node"; - subject["value"] = namer.GetName(id); - } - else - { - subject["type"] = "IRI"; - subject["value"] = id; - } - // RDF predicates - JObject predicate = new JObject(); - predicate["type"] = "IRI"; - predicate["value"] = eachProperty; - // convert @list to triples - if (JsonLdUtils.IsList(item)) - { - ListToRDF((JArray)((JObject)item)["@list"], namer, subject - , predicate, rval); - } - else - { - // convert value or node object to triple - object @object = ObjectToRDF(item, namer); - IDictionary tmp = new Dictionary(); - tmp["subject"] = subject; - tmp["predicate"] = predicate; - tmp["object"] = @object; - rval.Add(tmp); - } - } - } - } - return rval; - } - - /// - /// Converts a @list value into linked list of blank node RDF triples (an RDF - /// collection). - /// - /// - /// Converts a @list value into linked list of blank node RDF triples (an RDF - /// collection). - /// - /// the @list value. - /// a UniqueNamer for assigning blank node names. - /// the subject for the head of the list. - /// the predicate for the head of the list. - /// the array of triples to append to. + JToken items = node[eachProperty]; + if ("@type".Equals(eachProperty)) + { + eachProperty = JSONLDConsts.RdfType; + } + else + { + if (JsonLdUtils.IsKeyword(eachProperty)) + { + continue; + } + } + foreach (JToken item in (JArray)items) + { + // RDF subjects + JObject subject = new JObject(); + if (id.IndexOf("_:") == 0) + { + subject["type"] = "blank node"; + subject["value"] = namer.GetName(id); + } + else + { + subject["type"] = "IRI"; + subject["value"] = id; + } + // RDF predicates + JObject predicate = new JObject(); + predicate["type"] = "IRI"; + predicate["value"] = eachProperty; + // convert @list to triples + if (JsonLdUtils.IsList(item)) + { + ListToRDF((JArray)((JObject)item)["@list"], namer, subject + , predicate, rval); + } + else + { + // convert value or node object to triple + object @object = ObjectToRDF(item, namer); + IDictionary tmp = new Dictionary(); + tmp["subject"] = subject; + tmp["predicate"] = predicate; + tmp["object"] = @object; + rval.Add(tmp); + } + } + } + } + return rval; + } + + /// + /// Converts a @list value into linked list of blank node RDF triples (an RDF + /// collection). + /// + /// + /// Converts a @list value into linked list of blank node RDF triples (an RDF + /// collection). + /// + /// the @list value. + /// a UniqueNamer for assigning blank node names. + /// the subject for the head of the list. + /// the predicate for the head of the list. + /// the array of triples to append to. private static void ListToRDF(JArray list, UniqueNamer namer, JObject subject, JObject predicate, JArray triples - ) - { + ) + { JObject first = new JObject(); - first["type"] = "IRI"; - first["value"] = JSONLDConsts.RdfFirst; + first["type"] = "IRI"; + first["value"] = JSONLDConsts.RdfFirst; JObject rest = new JObject(); - rest["type"] = "IRI"; - rest["value"] = JSONLDConsts.RdfRest; + rest["type"] = "IRI"; + rest["value"] = JSONLDConsts.RdfRest; JObject nil = new JObject(); - nil["type"] = "IRI"; - nil["value"] = JSONLDConsts.RdfNil; - foreach (JToken item in list) - { + nil["type"] = "IRI"; + nil["value"] = JSONLDConsts.RdfNil; + foreach (JToken item in list) + { JObject blankNode = new JObject(); - blankNode["type"] = "blank node"; - blankNode["value"] = namer.GetName(); - { + blankNode["type"] = "blank node"; + blankNode["value"] = namer.GetName(); + { JObject tmp = new JObject(); - tmp["subject"] = subject; - tmp["predicate"] = predicate; - tmp["object"] = blankNode; - triples.Add(tmp); - } - subject = blankNode; - predicate = first; - JToken @object = ObjectToRDF(item, namer); - { + tmp["subject"] = subject; + tmp["predicate"] = predicate; + tmp["object"] = blankNode; + triples.Add(tmp); + } + subject = blankNode; + predicate = first; + JToken @object = ObjectToRDF(item, namer); + { JObject tmp = new JObject(); - tmp["subject"] = subject; - tmp["predicate"] = predicate; - tmp["object"] = @object; - triples.Add(tmp); - } - predicate = rest; - } + tmp["subject"] = subject; + tmp["predicate"] = predicate; + tmp["object"] = @object; + triples.Add(tmp); + } + predicate = rest; + } JObject tmp_1 = new JObject(); - tmp_1["subject"] = subject; - tmp_1["predicate"] = predicate; - tmp_1["object"] = nil; - triples.Add(tmp_1); - } - - /// - /// Converts a JSON-LD value object to an RDF literal or a JSON-LD string or - /// node object to an RDF resource. - /// - /// - /// Converts a JSON-LD value object to an RDF literal or a JSON-LD string or - /// node object to an RDF resource. - /// - /// the JSON-LD value or node object. - /// the UniqueNamer to use to assign blank node names. - /// the RDF literal or RDF resource. + tmp_1["subject"] = subject; + tmp_1["predicate"] = predicate; + tmp_1["object"] = nil; + triples.Add(tmp_1); + } + + /// + /// Converts a JSON-LD value object to an RDF literal or a JSON-LD string or + /// node object to an RDF resource. + /// + /// + /// Converts a JSON-LD value object to an RDF literal or a JSON-LD string or + /// node object to an RDF resource. + /// + /// the JSON-LD value or node object. + /// the UniqueNamer to use to assign blank node names. + /// the RDF literal or RDF resource. private static JObject ObjectToRDF(JToken item, UniqueNamer namer) - { + { JObject @object = new JObject(); - // convert value object to RDF - if (JsonLdUtils.IsValue(item)) - { - @object["type"] = "literal"; - JToken value = ((JObject)item)["@value"]; - JToken datatype = ((JObject)item)["@type"]; - // convert to XSD datatypes as appropriate + // convert value object to RDF + if (JsonLdUtils.IsValue(item)) + { + @object["type"] = "literal"; + JToken value = ((JObject)item)["@value"]; + JToken datatype = ((JObject)item)["@type"]; + // convert to XSD datatypes as appropriate if (value.Type == JTokenType.Boolean || value.Type == JTokenType.Float || value.Type == JTokenType.Integer ) - { - // convert to XSD datatype - if (value.Type == JTokenType.Boolean) - { - @object["value"] = value.ToString(); - @object["datatype"] = datatype.IsNull() ? JSONLDConsts.XsdBoolean : datatype; - } - else - { - if (value.Type == JTokenType.Float) - { - // canonical double representation - @object["value"] = string.Format("{0:0.0###############E0}", (double)value); - @object["datatype"] = datatype.IsNull() ? JSONLDConsts.XsdDouble : datatype; - } - else - { - DecimalFormat df = new DecimalFormat("0"); - @object["value"] = df.Format((int)value); - @object["datatype"] = datatype.IsNull() ? JSONLDConsts.XsdInteger : datatype; - } - } - } - else - { - if (((IDictionary)item).ContainsKey("@language")) - { - @object["value"] = value; - @object["datatype"] = datatype.IsNull() ? JSONLDConsts.RdfLangstring : datatype; - @object["language"] = ((IDictionary)item)["@language"]; - } - else - { - @object["value"] = value; - @object["datatype"] = datatype.IsNull() ? JSONLDConsts.XsdString : datatype; - } - } - } - else - { - // convert string/node object to RDF - string id = JsonLdUtils.IsObject(item) ? (string)((JObject)item - )["@id"] : (string)item; - if (id.IndexOf("_:") == 0) - { - @object["type"] = "blank node"; - @object["value"] = namer.GetName(id); - } - else - { - @object["type"] = "IRI"; - @object["value"] = id; - } - } - return @object; - } - - public static string ToNQuads(RDFDataset dataset) - { - IList quads = new List(); + { + // convert to XSD datatype + if (value.Type == JTokenType.Boolean) + { + @object["value"] = value.ToString(); + @object["datatype"] = datatype.IsNull() ? JSONLDConsts.XsdBoolean : datatype; + } + else + { + if (value.Type == JTokenType.Float) + { + // canonical double representation + @object["value"] = string.Format("{0:0.0###############E0}", (double)value); + @object["datatype"] = datatype.IsNull() ? JSONLDConsts.XsdDouble : datatype; + } + else + { + DecimalFormat df = new DecimalFormat("0"); + @object["value"] = df.Format((int)value); + @object["datatype"] = datatype.IsNull() ? JSONLDConsts.XsdInteger : datatype; + } + } + } + else + { + if (((IDictionary)item).ContainsKey("@language")) + { + @object["value"] = value; + @object["datatype"] = datatype.IsNull() ? JSONLDConsts.RdfLangstring : datatype; + @object["language"] = ((IDictionary)item)["@language"]; + } + else + { + @object["value"] = value; + @object["datatype"] = datatype.IsNull() ? JSONLDConsts.XsdString : datatype; + } + } + } + else + { + // convert string/node object to RDF + string id = JsonLdUtils.IsObject(item) ? (string)((JObject)item + )["@id"] : (string)item; + if (id.IndexOf("_:") == 0) + { + @object["type"] = "blank node"; + @object["value"] = namer.GetName(id); + } + else + { + @object["type"] = "IRI"; + @object["value"] = id; + } + } + return @object; + } + + public static string ToNQuads(RDFDataset dataset) + { + IList quads = new List(); foreach (string graphName in dataset.GraphNames()) - { + { var eachGraphName = graphName; IList triples = dataset.GetQuads(eachGraphName); - if ("@default".Equals(eachGraphName)) - { - eachGraphName = null; - } - foreach (RDFDataset.Quad triple in triples) - { - quads.Add(ToNQuad(triple, eachGraphName)); - } - } + if ("@default".Equals(eachGraphName)) + { + eachGraphName = null; + } + foreach (RDFDataset.Quad triple in triples) + { + quads.Add(ToNQuad(triple, eachGraphName)); + } + } ((List)quads).Sort(StringComparer.Ordinal); - string rval = string.Empty; - foreach (string quad in quads) - { - rval += quad; - } - return rval; - } - - internal static string ToNQuad(RDFDataset.Quad triple, string graphName, string bnode - ) - { - RDFDataset.Node s = triple.GetSubject(); - RDFDataset.Node p = triple.GetPredicate(); - RDFDataset.Node o = triple.GetObject(); - string quad = string.Empty; - // subject is an IRI or bnode - if (s.IsIRI()) - { - quad += "<" + Escape(s.GetValue()) + ">"; - } - else - { - // normalization mode - if (bnode != null) - { - quad += bnode.Equals(s.GetValue()) ? "_:a" : "_:z"; - } - else - { - // normal mode - quad += s.GetValue(); - } - } - if (p.IsIRI()) - { - quad += " <" + Escape(p.GetValue()) + "> "; - } - else - { - // otherwise it must be a bnode (TODO: can we only allow this if the - // flag is set in options?) - quad += " " + Escape(p.GetValue()) + " "; - } - // object is IRI, bnode or literal - if (o.IsIRI()) - { - quad += "<" + Escape(o.GetValue()) + ">"; - } - else - { - if (o.IsBlankNode()) - { - // normalization mode - if (bnode != null) - { - quad += bnode.Equals(o.GetValue()) ? "_:a" : "_:z"; - } - else - { - // normal mode - quad += o.GetValue(); - } - } - else - { - string escaped = Escape(o.GetValue()); - quad += "\"" + escaped + "\""; - if (JSONLDConsts.RdfLangstring.Equals(o.GetDatatype())) - { - quad += "@" + o.GetLanguage(); - } - else - { - if (!JSONLDConsts.XsdString.Equals(o.GetDatatype())) - { - quad += "^^<" + Escape(o.GetDatatype()) + ">"; - } - } - } - } - // graph - if (graphName != null) - { - if (graphName.IndexOf("_:") != 0) - { - quad += " <" + Escape(graphName) + ">"; - } - else - { - if (bnode != null) - { - quad += " _:g"; - } - else - { - quad += " " + graphName; - } - } - } - quad += " .\n"; - return quad; - } - - internal static string ToNQuad(RDFDataset.Quad triple, string graphName) - { - return ToNQuad(triple, graphName, null); - } - - private static readonly Pattern UcharMatched = Pattern.Compile("\\u005C(?:([tbnrf\\\"'])|(?:u(" - + JsonLD.Core.Regex.Hex + "{4}))|(?:U(" + JsonLD.Core.Regex.Hex + "{8})))" - ); - - public static string Unescape(string str) - { - string rval = str; - if (str != null) - { - Matcher m = UcharMatched.Matcher(str); - while (m.Find()) - { - string uni = m.Group(0); - if (m.Group(1) == null) - { - string hex = m.Group(2) != null ? m.Group(2) : m.Group(3); - int v = System.Convert.ToInt32(hex, 16); - // hex = - // hex.replaceAll("^(?:00)+", - // ""); - if (v > unchecked((int)(0xFFFF))) - { - // deal with UTF-32 - // Integer v = Integer.parseInt(hex, 16); - int vt = v - unchecked((int)(0x10000)); - int vh = vt >> 10; - int v1 = vt & unchecked((int)(0x3FF)); - int w1 = unchecked((int)(0xD800)) + vh; - int w2 = unchecked((int)(0xDC00)) + v1; - StringBuilder b = new StringBuilder(); - b.AppendCodePoint(w1); - b.AppendCodePoint(w2); - uni = b.ToString(); - } - else - { - uni = char.ToString((char)v); - } - } - else - { - char c = m.Group(1)[0]; - switch (c) - { - case 'b': - { - uni = "\b"; - break; - } - - case 'n': - { - uni = "\n"; - break; - } - - case 't': - { - uni = "\t"; - break; - } - - case 'f': - { - uni = "\f"; - break; - } - - case 'r': - { - uni = "\r"; - break; - } - - case '\'': - { - uni = "'"; - break; - } - - case '\"': - { - uni = "\""; - break; - } - - case '\\': - { - uni = "\\"; - break; - } - - default: - { - // do nothing - continue; - } - } - } - string pat = Pattern.Quote(m.Group(0)); - string x = JsonLD.JavaCompat.ToHexString(uni[0]); - rval = rval.Replace(pat, uni); - } - } - return rval; - } - - public static string Escape(string str) - { - string rval = string.Empty; - for (int i = 0; i < str.Length; i++) - { - char hi = str[i]; - if (hi <= unchecked((int)(0x8)) || hi == unchecked((int)(0xB)) || hi == unchecked( - (int)(0xC)) || (hi >= unchecked((int)(0xE)) && hi <= unchecked((int)(0x1F))) || - (hi >= unchecked((int)(0x7F)) && hi <= unchecked((int)(0xA0))) || ((hi >= unchecked( - (int)(0x24F)) && !char.IsHighSurrogate(hi)))) - { - // 0xA0 is end of - // non-printable latin-1 - // supplement - // characters - // 0x24F is the end of latin extensions - // TODO: there's probably a lot of other characters that - // shouldn't be escaped that - // fall outside these ranges, this is one example from the - // json-ld tests - rval += string.Format("\\u%04x", (int)hi); - } - else - { - if (char.IsHighSurrogate(hi)) - { - char lo = str[++i]; - int c = (hi << 10) + lo + (unchecked((int)(0x10000)) - (unchecked((int)(0xD800)) - << 10) - unchecked((int)(0xDC00))); - rval += string.Format("\\U%08x", c); - } - else - { - switch (hi) - { - case '\b': - { - rval += "\\b"; - break; - } - - case '\n': - { - rval += "\\n"; - break; - } - - case '\t': - { - rval += "\\t"; - break; - } - - case '\f': - { - rval += "\\f"; - break; - } - - case '\r': - { - rval += "\\r"; - break; - } - - case '\"': - { - // case '\'': - // rval += "\\'"; - // break; - rval += "\\\""; - // rval += "\\u0022"; - break; - } - - case '\\': - { - rval += "\\\\"; - break; - } - - default: - { - // just put the char as is - rval += hi; - break; - } - } - } - } - } - return rval; - } - - private class Regex - { - public static readonly Pattern Iri = Pattern.Compile("(?:<([^>]*)>)"); - - public static readonly Pattern Bnode = Pattern.Compile("(_:(?:[A-Za-z][A-Za-z0-9]*))" - ); - - public static readonly Pattern Plain = Pattern.Compile("\"([^\"\\\\]*(?:\\\\.[^\"\\\\]*)*)\"" - ); - - public static readonly Pattern Datatype = Pattern.Compile("(?:\\^\\^" + Iri + ")" - ); - - public static readonly Pattern Language = Pattern.Compile("(?:@([a-z]+(?:-[a-zA-Z0-9]+)*))" - ); - - public static readonly Pattern Literal = Pattern.Compile("(?:" + Plain + "(?:" + - Datatype + "|" + Language + ")?)"); - - public static readonly Pattern Ws = Pattern.Compile("[ \\t]+"); - - public static readonly Pattern Wso = Pattern.Compile("[ \\t]*"); - - public static readonly Pattern Eoln = Pattern.Compile("(?:\r\n)|(?:\n)|(?:\r)"); - - public static readonly Pattern Empty = Pattern.Compile("^" + Wso + "$"); - - public static readonly Pattern Subject = Pattern.Compile("(?:" + Iri + "|" + Bnode - + ")" + Ws); - - public static readonly Pattern Property = Pattern.Compile(Iri.GetPattern() + Ws.GetPattern - ()); - - public static readonly Pattern Object = Pattern.Compile("(?:" + Iri + "|" + Bnode - + "|" + Literal + ")" + Wso); - - public static readonly Pattern Graph = Pattern.Compile("(?:\\.|(?:(?:" + Iri + "|" - + Bnode + ")" + Wso + "\\.))"); - - public static readonly Pattern Quad = Pattern.Compile("^" + Wso + Subject + Property - + Object + Graph + Wso + "$"); - // define partial regexes - // final public static Pattern IRI = - // Pattern.compile("(?:<([^:]+:[^>]*)>)"); - // define quad part regexes - // full quad regex - } - - /// Parses RDF in the form of N-Quads. - /// Parses RDF in the form of N-Quads. - /// the N-Quads input to parse. - /// an RDF dataset. - /// - public static RDFDataset ParseNQuads(string input) - { - // build RDF dataset - RDFDataset dataset = new RDFDataset(); - // split N-Quad input into lines - string[] lines = RDFDatasetUtils.Regex.Eoln.Split(input); - int lineNumber = 0; - foreach (string line in lines) - { - lineNumber++; - // skip empty lines - if (RDFDatasetUtils.Regex.Empty.Matcher(line).Matches()) - { - continue; - } - // parse quad - Matcher match = RDFDatasetUtils.Regex.Quad.Matcher(line); - if (!match.Matches()) - { - throw new JsonLdError(JsonLdError.Error.SyntaxError, "Error while parsing N-Quads; invalid quad. line:" - + lineNumber); - } - // get subject - RDFDataset.Node subject; - if (match.Group(1) != null) - { - subject = new RDFDataset.IRI(Unescape(match.Group(1))); - } - else - { - subject = new RDFDataset.BlankNode(Unescape(match.Group(2))); - } - // get predicate - RDFDataset.Node predicate = new RDFDataset.IRI(Unescape(match.Group(3))); - // get object - RDFDataset.Node @object; - if (match.Group(4) != null) - { - @object = new RDFDataset.IRI(Unescape(match.Group(4))); - } - else - { - if (match.Group(5) != null) - { - @object = new RDFDataset.BlankNode(Unescape(match.Group(5))); - } - else - { - string language = Unescape(match.Group(8)); - string datatype = match.Group(7) != null ? Unescape(match.Group(7)) : match.Group - (8) != null ? JSONLDConsts.RdfLangstring : JSONLDConsts.XsdString; - string unescaped = Unescape(match.Group(6)); - @object = new RDFDataset.Literal(unescaped, datatype, language); - } - } - // get graph name ('@default' is used for the default graph) - string name = "@default"; - if (match.Group(9) != null) - { - name = Unescape(match.Group(9)); - } - else - { - if (match.Group(10) != null) - { - name = Unescape(match.Group(10)); - } - } - RDFDataset.Quad triple = new RDFDataset.Quad(subject, predicate, @object, name); - // initialise graph in dataset - if (!dataset.ContainsKey(name)) - { - IList tmp = new List(); - tmp.Add(triple); - dataset[name] = tmp; - } - else - { - // add triple if unique to its graph + string rval = string.Empty; + foreach (string quad in quads) + { + rval += quad; + } + return rval; + } + + internal static string ToNQuad(RDFDataset.Quad triple, string graphName, string bnode + ) + { + RDFDataset.Node s = triple.GetSubject(); + RDFDataset.Node p = triple.GetPredicate(); + RDFDataset.Node o = triple.GetObject(); + string quad = string.Empty; + // subject is an IRI or bnode + if (s.IsIRI()) + { + quad += "<" + Escape(s.GetValue()) + ">"; + } + else + { + // normalization mode + if (bnode != null) + { + quad += bnode.Equals(s.GetValue()) ? "_:a" : "_:z"; + } + else + { + // normal mode + quad += s.GetValue(); + } + } + if (p.IsIRI()) + { + quad += " <" + Escape(p.GetValue()) + "> "; + } + else + { + // otherwise it must be a bnode (TODO: can we only allow this if the + // flag is set in options?) + quad += " " + Escape(p.GetValue()) + " "; + } + // object is IRI, bnode or literal + if (o.IsIRI()) + { + quad += "<" + Escape(o.GetValue()) + ">"; + } + else + { + if (o.IsBlankNode()) + { + // normalization mode + if (bnode != null) + { + quad += bnode.Equals(o.GetValue()) ? "_:a" : "_:z"; + } + else + { + // normal mode + quad += o.GetValue(); + } + } + else + { + string escaped = Escape(o.GetValue()); + quad += "\"" + escaped + "\""; + if (JSONLDConsts.RdfLangstring.Equals(o.GetDatatype())) + { + quad += "@" + o.GetLanguage(); + } + else + { + if (!JSONLDConsts.XsdString.Equals(o.GetDatatype())) + { + quad += "^^<" + Escape(o.GetDatatype()) + ">"; + } + } + } + } + // graph + if (graphName != null) + { + if (graphName.IndexOf("_:") != 0) + { + quad += " <" + Escape(graphName) + ">"; + } + else + { + if (bnode != null) + { + quad += " _:g"; + } + else + { + quad += " " + graphName; + } + } + } + quad += " .\n"; + return quad; + } + + internal static string ToNQuad(RDFDataset.Quad triple, string graphName) + { + return ToNQuad(triple, graphName, null); + } + + private static readonly Pattern UcharMatched = Pattern.Compile("\\u005C(?:([tbnrf\\\"'])|(?:u(" + + JsonLD.Core.Regex.Hex + "{4}))|(?:U(" + JsonLD.Core.Regex.Hex + "{8})))" + ); + + public static string Unescape(string str) + { + string rval = str; + if (str != null) + { + Matcher m = UcharMatched.Matcher(str); + while (m.Find()) + { + string uni = m.Group(0); + if (m.Group(1) == null) + { + string hex = m.Group(2) != null ? m.Group(2) : m.Group(3); + int v = System.Convert.ToInt32(hex, 16); + // hex = + // hex.replaceAll("^(?:00)+", + // ""); + if (v > unchecked((int)(0xFFFF))) + { + // deal with UTF-32 + // Integer v = Integer.parseInt(hex, 16); + int vt = v - unchecked((int)(0x10000)); + int vh = vt >> 10; + int v1 = vt & unchecked((int)(0x3FF)); + int w1 = unchecked((int)(0xD800)) + vh; + int w2 = unchecked((int)(0xDC00)) + v1; + StringBuilder b = new StringBuilder(); + b.AppendCodePoint(w1); + b.AppendCodePoint(w2); + uni = b.ToString(); + } + else + { + uni = char.ToString((char)v); + } + } + else + { + char c = m.Group(1)[0]; + switch (c) + { + case 'b': + { + uni = "\b"; + break; + } + + case 'n': + { + uni = "\n"; + break; + } + + case 't': + { + uni = "\t"; + break; + } + + case 'f': + { + uni = "\f"; + break; + } + + case 'r': + { + uni = "\r"; + break; + } + + case '\'': + { + uni = "'"; + break; + } + + case '\"': + { + uni = "\""; + break; + } + + case '\\': + { + uni = "\\"; + break; + } + + default: + { + // do nothing + continue; + } + } + } + string pat = Pattern.Quote(m.Group(0)); + string x = JsonLD.JavaCompat.ToHexString(uni[0]); + rval = rval.Replace(pat, uni); + } + } + return rval; + } + + public static string Escape(string str) + { + string rval = string.Empty; + for (int i = 0; i < str.Length; i++) + { + char hi = str[i]; + if (hi <= unchecked((int)(0x8)) || hi == unchecked((int)(0xB)) || hi == unchecked( + (int)(0xC)) || (hi >= unchecked((int)(0xE)) && hi <= unchecked((int)(0x1F))) || + (hi >= unchecked((int)(0x7F)) && hi <= unchecked((int)(0xA0))) || ((hi >= unchecked( + (int)(0x24F)) && !char.IsHighSurrogate(hi)))) + { + // 0xA0 is end of + // non-printable latin-1 + // supplement + // characters + // 0x24F is the end of latin extensions + // TODO: there's probably a lot of other characters that + // shouldn't be escaped that + // fall outside these ranges, this is one example from the + // json-ld tests + rval += string.Format("\\u%04x", (int)hi); + } + else + { + if (char.IsHighSurrogate(hi)) + { + char lo = str[++i]; + int c = (hi << 10) + lo + (unchecked((int)(0x10000)) - (unchecked((int)(0xD800)) + << 10) - unchecked((int)(0xDC00))); + rval += string.Format("\\U%08x", c); + } + else + { + switch (hi) + { + case '\b': + { + rval += "\\b"; + break; + } + + case '\n': + { + rval += "\\n"; + break; + } + + case '\t': + { + rval += "\\t"; + break; + } + + case '\f': + { + rval += "\\f"; + break; + } + + case '\r': + { + rval += "\\r"; + break; + } + + case '\"': + { + // case '\'': + // rval += "\\'"; + // break; + rval += "\\\""; + // rval += "\\u0022"; + break; + } + + case '\\': + { + rval += "\\\\"; + break; + } + + default: + { + // just put the char as is + rval += hi; + break; + } + } + } + } + } + return rval; + } + + private class Regex + { + public static readonly Pattern Iri = Pattern.Compile("(?:<([^>]*)>)"); + + public static readonly Pattern Bnode = Pattern.Compile("(_:(?:[A-Za-z][A-Za-z0-9]*))" + ); + + public static readonly Pattern Plain = Pattern.Compile("\"([^\"\\\\]*(?:\\\\.[^\"\\\\]*)*)\"" + ); + + public static readonly Pattern Datatype = Pattern.Compile("(?:\\^\\^" + Iri + ")" + ); + + public static readonly Pattern Language = Pattern.Compile("(?:@([a-z]+(?:-[a-zA-Z0-9]+)*))" + ); + + public static readonly Pattern Literal = Pattern.Compile("(?:" + Plain + "(?:" + + Datatype + "|" + Language + ")?)"); + + public static readonly Pattern Ws = Pattern.Compile("[ \\t]+"); + + public static readonly Pattern Wso = Pattern.Compile("[ \\t]*"); + + public static readonly Pattern Eoln = Pattern.Compile("(?:\r\n)|(?:\n)|(?:\r)"); + + public static readonly Pattern Empty = Pattern.Compile("^" + Wso + "$"); + + public static readonly Pattern Subject = Pattern.Compile("(?:" + Iri + "|" + Bnode + + ")" + Ws); + + public static readonly Pattern Property = Pattern.Compile(Iri.GetPattern() + Ws.GetPattern + ()); + + public static readonly Pattern Object = Pattern.Compile("(?:" + Iri + "|" + Bnode + + "|" + Literal + ")" + Wso); + + public static readonly Pattern Graph = Pattern.Compile("(?:\\.|(?:(?:" + Iri + "|" + + Bnode + ")" + Wso + "\\.))"); + + public static readonly Pattern Quad = Pattern.Compile("^" + Wso + Subject + Property + + Object + Graph + Wso + "$"); + // define partial regexes + // final public static Pattern IRI = + // Pattern.compile("(?:<([^:]+:[^>]*)>)"); + // define quad part regexes + // full quad regex + } + + /// Parses RDF in the form of N-Quads. + /// Parses RDF in the form of N-Quads. + /// the N-Quads input to parse. + /// an RDF dataset. + /// + public static RDFDataset ParseNQuads(string input) + { + // build RDF dataset + RDFDataset dataset = new RDFDataset(); + // split N-Quad input into lines + string[] lines = RDFDatasetUtils.Regex.Eoln.Split(input); + int lineNumber = 0; + foreach (string line in lines) + { + lineNumber++; + // skip empty lines + if (RDFDatasetUtils.Regex.Empty.Matcher(line).Matches()) + { + continue; + } + // parse quad + Matcher match = RDFDatasetUtils.Regex.Quad.Matcher(line); + if (!match.Matches()) + { + throw new JsonLdError(JsonLdError.Error.SyntaxError, "Error while parsing N-Quads; invalid quad. line:" + + lineNumber); + } + // get subject + RDFDataset.Node subject; + if (match.Group(1) != null) + { + subject = new RDFDataset.IRI(Unescape(match.Group(1))); + } + else + { + subject = new RDFDataset.BlankNode(Unescape(match.Group(2))); + } + // get predicate + RDFDataset.Node predicate = new RDFDataset.IRI(Unescape(match.Group(3))); + // get object + RDFDataset.Node @object; + if (match.Group(4) != null) + { + @object = new RDFDataset.IRI(Unescape(match.Group(4))); + } + else + { + if (match.Group(5) != null) + { + @object = new RDFDataset.BlankNode(Unescape(match.Group(5))); + } + else + { + string language = Unescape(match.Group(8)); + string datatype = match.Group(7) != null ? Unescape(match.Group(7)) : match.Group + (8) != null ? JSONLDConsts.RdfLangstring : JSONLDConsts.XsdString; + string unescaped = Unescape(match.Group(6)); + @object = new RDFDataset.Literal(unescaped, datatype, language); + } + } + // get graph name ('@default' is used for the default graph) + string name = "@default"; + if (match.Group(9) != null) + { + name = Unescape(match.Group(9)); + } + else + { + if (match.Group(10) != null) + { + name = Unescape(match.Group(10)); + } + } + RDFDataset.Quad triple = new RDFDataset.Quad(subject, predicate, @object, name); + // initialise graph in dataset + if (!dataset.ContainsKey(name)) + { + IList tmp = new List(); + tmp.Add(triple); + dataset[name] = tmp; + } + else + { + // add triple if unique to its graph IList triples = (IList)dataset[name]; - if (!triples.Contains(triple)) - { - triples.Add(triple); - } - } - } - return dataset; - } - } + if (!triples.Contains(triple)) + { + triples.Add(triple); + } + } + } + return dataset; + } + } } diff --git a/src/JsonLD/Core/Regex.cs b/src/JsonLD/Core/Regex.cs index 09992a4..4d7bdd7 100644 --- a/src/JsonLD/Core/Regex.cs +++ b/src/JsonLD/Core/Regex.cs @@ -2,88 +2,88 @@ namespace JsonLD.Core { - internal class Regex - { - //public static readonly Pattern TrickyUtfChars = Pattern.Compile("[\uD800\uDC00-\uDB7F\uDFFF]" - // ); + internal class Regex + { + //public static readonly Pattern TrickyUtfChars = Pattern.Compile("[\uD800\uDC00-\uDB7F\uDFFF]" + // ); - public static readonly Pattern PnCharsBase = Pattern.Compile("[a-zA-Z]|[\\u00C0-\\u00D6]|[\\u00D8-\\u00F6]|[\\u00F8-\\u02FF]|[\\u0370-\\u037D]|[\\u037F-\\u1FFF]|" - + "[\\u200C-\\u200D]|[\\u2070-\\u218F]|[\\u2C00-\\u2FEF]|[\\u3001-\\uD7FF]|[\\uF900-\\uFDCF]|[\\uFDF0-\\uFFFD]|" - ); + public static readonly Pattern PnCharsBase = Pattern.Compile("[a-zA-Z]|[\\u00C0-\\u00D6]|[\\u00D8-\\u00F6]|[\\u00F8-\\u02FF]|[\\u0370-\\u037D]|[\\u037F-\\u1FFF]|" + + "[\\u200C-\\u200D]|[\\u2070-\\u218F]|[\\u2C00-\\u2FEF]|[\\u3001-\\uD7FF]|[\\uF900-\\uFDCF]|[\\uFDF0-\\uFFFD]|" + ); - public static readonly Pattern PnCharsU = Pattern.Compile(PnCharsBase + "|[_]"); + public static readonly Pattern PnCharsU = Pattern.Compile(PnCharsBase + "|[_]"); - public static readonly Pattern PnChars = Pattern.Compile(PnCharsU + "|[-0-9]|[\\u00B7]|[\\u0300-\\u036F]|[\\u203F-\\u2040]" - ); + public static readonly Pattern PnChars = Pattern.Compile(PnCharsU + "|[-0-9]|[\\u00B7]|[\\u0300-\\u036F]|[\\u203F-\\u2040]" + ); - public static readonly Pattern PnPrefix = Pattern.Compile("(?:(?:" + PnCharsBase - + ")(?:(?:" + PnChars + "|[\\.])*(?:" + PnChars + "))?)"); + public static readonly Pattern PnPrefix = Pattern.Compile("(?:(?:" + PnCharsBase + + ")(?:(?:" + PnChars + "|[\\.])*(?:" + PnChars + "))?)"); - public static readonly Pattern Hex = Pattern.Compile("[0-9A-Fa-f]"); + public static readonly Pattern Hex = Pattern.Compile("[0-9A-Fa-f]"); - public static readonly Pattern PnLocalEsc = Pattern.Compile("[\\\\][_~\\.\\-!$&'\\(\\)*+,;=/?#@%]" - ); + public static readonly Pattern PnLocalEsc = Pattern.Compile("[\\\\][_~\\.\\-!$&'\\(\\)*+,;=/?#@%]" + ); - public static readonly Pattern Percent = Pattern.Compile("%" + Hex + Hex); + public static readonly Pattern Percent = Pattern.Compile("%" + Hex + Hex); - public static readonly Pattern Plx = Pattern.Compile(Percent + "|" + PnLocalEsc); + public static readonly Pattern Plx = Pattern.Compile(Percent + "|" + PnLocalEsc); - public static readonly Pattern PnLocal = Pattern.Compile("((?:" + PnCharsU + "|[:]|[0-9]|" - + Plx + ")(?:(?:" + PnChars + "|[.]|[:]|" + Plx + ")*(?:" + PnChars + "|[:]|" + - Plx + "))?)"); + public static readonly Pattern PnLocal = Pattern.Compile("((?:" + PnCharsU + "|[:]|[0-9]|" + + Plx + ")(?:(?:" + PnChars + "|[.]|[:]|" + Plx + ")*(?:" + PnChars + "|[:]|" + + Plx + "))?)"); - public static readonly Pattern PnameNs = Pattern.Compile("((?:" + PnPrefix + ")?):" - ); + public static readonly Pattern PnameNs = Pattern.Compile("((?:" + PnPrefix + ")?):" + ); - public static readonly Pattern PnameLn = Pattern.Compile(string.Empty + PnameNs + - PnLocal); + public static readonly Pattern PnameLn = Pattern.Compile(string.Empty + PnameNs + + PnLocal); - public static readonly Pattern Uchar = Pattern.Compile("\\u005Cu" + Hex + Hex + Hex - + Hex + "|\\u005CU" + Hex + Hex + Hex + Hex + Hex + Hex + Hex + Hex); + public static readonly Pattern Uchar = Pattern.Compile("\\u005Cu" + Hex + Hex + Hex + + Hex + "|\\u005CU" + Hex + Hex + Hex + Hex + Hex + Hex + Hex + Hex); - public static readonly Pattern Echar = Pattern.Compile("\\u005C[tbnrf\\u005C\"']" - ); + public static readonly Pattern Echar = Pattern.Compile("\\u005C[tbnrf\\u005C\"']" + ); - public static readonly Pattern Iriref = Pattern.Compile("(?:<((?:[^\\x00-\\x20<>\"{}|\\^`\\\\]|" - + Uchar + ")*)>)"); + public static readonly Pattern Iriref = Pattern.Compile("(?:<((?:[^\\x00-\\x20<>\"{}|\\^`\\\\]|" + + Uchar + ")*)>)"); - public static readonly Pattern BlankNodeLabel = Pattern.Compile("(?:_:((?:" + PnCharsU - + "|[0-9])(?:(?:" + PnChars + "|[\\.])*(?:" + PnChars + "))?))"); + public static readonly Pattern BlankNodeLabel = Pattern.Compile("(?:_:((?:" + PnCharsU + + "|[0-9])(?:(?:" + PnChars + "|[\\.])*(?:" + PnChars + "))?))"); - public static readonly Pattern Ws = Pattern.Compile("[ \t\r\n]"); + public static readonly Pattern Ws = Pattern.Compile("[ \t\r\n]"); - public static readonly Pattern Ws0N = Pattern.Compile(Ws + "*"); + public static readonly Pattern Ws0N = Pattern.Compile(Ws + "*"); - public static readonly Pattern Ws01 = Pattern.Compile(Ws + "?"); + public static readonly Pattern Ws01 = Pattern.Compile(Ws + "?"); - public static readonly Pattern Ws1N = Pattern.Compile(Ws + "+"); + public static readonly Pattern Ws1N = Pattern.Compile(Ws + "+"); - public static readonly Pattern StringLiteralQuote = Pattern.Compile("\"(?:[^\\u0022\\u005C\\u000A\\u000D]|(?:" - + Echar + ")|(?:" + Uchar + "))*\""); + public static readonly Pattern StringLiteralQuote = Pattern.Compile("\"(?:[^\\u0022\\u005C\\u000A\\u000D]|(?:" + + Echar + ")|(?:" + Uchar + "))*\""); - public static readonly Pattern StringLiteralSingleQuote = Pattern.Compile("'(?:[^\\u0027\\u005C\\u000A\\u000D]|(?:" - + Echar + ")|(?:" + Uchar + "))*'"); + public static readonly Pattern StringLiteralSingleQuote = Pattern.Compile("'(?:[^\\u0027\\u005C\\u000A\\u000D]|(?:" + + Echar + ")|(?:" + Uchar + "))*'"); - public static readonly Pattern StringLiteralLongSingleQuote = Pattern.Compile("'''(?:(?:(?:'|'')?[^'\\\\])|" - + Echar + "|" + Uchar + ")*'''"); + public static readonly Pattern StringLiteralLongSingleQuote = Pattern.Compile("'''(?:(?:(?:'|'')?[^'\\\\])|" + + Echar + "|" + Uchar + ")*'''"); - public static readonly Pattern StringLiteralLongQuote = Pattern.Compile("\"\"\"(?:(?:(?:\"|\"\")?[^\\\"\\\\])|" - + Echar + "|" + Uchar + ")*\"\"\""); + public static readonly Pattern StringLiteralLongQuote = Pattern.Compile("\"\"\"(?:(?:(?:\"|\"\")?[^\\\"\\\\])|" + + Echar + "|" + Uchar + ")*\"\"\""); - public static readonly Pattern Langtag = Pattern.Compile("(?:@([a-zA-Z]+(?:-[a-zA-Z0-9]+)*))" - ); + public static readonly Pattern Langtag = Pattern.Compile("(?:@([a-zA-Z]+(?:-[a-zA-Z0-9]+)*))" + ); - public static readonly Pattern Integer = Pattern.Compile("[+-]?[0-9]+"); + public static readonly Pattern Integer = Pattern.Compile("[+-]?[0-9]+"); - public static readonly Pattern Decimal = Pattern.Compile("[+-]?[0-9]*\\.[0-9]+"); + public static readonly Pattern Decimal = Pattern.Compile("[+-]?[0-9]*\\.[0-9]+"); - public static readonly Pattern Exponent = Pattern.Compile("[eE][+-]?[0-9]+"); + public static readonly Pattern Exponent = Pattern.Compile("[eE][+-]?[0-9]+"); - public static readonly Pattern Double = Pattern.Compile("[+-]?(?:(?:[0-9]+\\.[0-9]*" - + Exponent + ")|(?:\\.[0-9]+" + Exponent + ")|(?:[0-9]+" + Exponent + "))"); - // ("1.7".equals(System.getProperty("java.specification.version")) ? - // "[\\x{10000}-\\x{EFFFF}]" : - // this seems to work with jdk1.6 - // for ttl - } + public static readonly Pattern Double = Pattern.Compile("[+-]?(?:(?:[0-9]+\\.[0-9]*" + + Exponent + ")|(?:\\.[0-9]+" + Exponent + ")|(?:[0-9]+" + Exponent + "))"); + // ("1.7".equals(System.getProperty("java.specification.version")) ? + // "[\\x{10000}-\\x{EFFFF}]" : + // this seems to work with jdk1.6 + // for ttl + } } diff --git a/src/JsonLD/Core/RemoteDocument.cs b/src/JsonLD/Core/RemoteDocument.cs index bf41338..872674d 100644 --- a/src/JsonLD/Core/RemoteDocument.cs +++ b/src/JsonLD/Core/RemoteDocument.cs @@ -2,43 +2,43 @@ namespace JsonLD.Core { - public class RemoteDocument - { - public virtual string DocumentUrl - { - get - { - return documentUrl; - } - set - { + public class RemoteDocument + { + public virtual string DocumentUrl + { + get + { + return documentUrl; + } + set + { this.documentUrl = value; - } - } + } + } - public virtual JToken Document - { - get - { - return document; - } - set - { + public virtual JToken Document + { + get + { + return document; + } + set + { this.document = value; - } - } + } + } - public virtual string ContextUrl - { - get - { - return contextUrl; - } - set - { + public virtual string ContextUrl + { + get + { + return contextUrl; + } + set + { this.contextUrl = value; - } - } + } + } public virtual JToken Context { @@ -52,24 +52,24 @@ public virtual JToken Context } } - internal string documentUrl; + internal string documentUrl; - internal JToken document; + internal JToken document; - internal string contextUrl; + internal string contextUrl; internal JToken context; public RemoteDocument(string url, JToken document) : this(url, document, null) - { - } + { + } - public RemoteDocument(string url, JToken document, string context) - { - this.documentUrl = url; - this.document = document; - this.contextUrl = context; - } - } + public RemoteDocument(string url, JToken document, string context) + { + this.documentUrl = url; + this.document = document; + this.contextUrl = context; + } + } } diff --git a/src/JsonLD/Core/UniqueNamer.cs b/src/JsonLD/Core/UniqueNamer.cs index 816e60d..4b74035 100644 --- a/src/JsonLD/Core/UniqueNamer.cs +++ b/src/JsonLD/Core/UniqueNamer.cs @@ -4,76 +4,76 @@ namespace JsonLD.Core { - public class UniqueNamer - { - private readonly string prefix; + public class UniqueNamer + { + private readonly string prefix; - private int counter; + private int counter; - private JObject existing; + private JObject existing; - /// Creates a new UniqueNamer. - /// - /// Creates a new UniqueNamer. A UniqueNamer issues unique names, keeping - /// track of any previously issued names. - /// - /// the prefix to use (''). - public UniqueNamer(string prefix) - { - this.prefix = prefix; - this.counter = 0; - this.existing = new JObject(); - } + /// Creates a new UniqueNamer. + /// + /// Creates a new UniqueNamer. A UniqueNamer issues unique names, keeping + /// track of any previously issued names. + /// + /// the prefix to use (''). + public UniqueNamer(string prefix) + { + this.prefix = prefix; + this.counter = 0; + this.existing = new JObject(); + } - /// Copies this UniqueNamer. - /// Copies this UniqueNamer. - /// a copy of this UniqueNamer. - public virtual JsonLD.Core.UniqueNamer Clone() - { - JsonLD.Core.UniqueNamer copy = new JsonLD.Core.UniqueNamer(this.prefix); - copy.counter = this.counter; - copy.existing = (JObject)JsonLdUtils.Clone(this.existing); - return copy; - } + /// Copies this UniqueNamer. + /// Copies this UniqueNamer. + /// a copy of this UniqueNamer. + public virtual JsonLD.Core.UniqueNamer Clone() + { + JsonLD.Core.UniqueNamer copy = new JsonLD.Core.UniqueNamer(this.prefix); + copy.counter = this.counter; + copy.existing = (JObject)JsonLdUtils.Clone(this.existing); + return copy; + } - /// - /// Gets the new name for the given old name, where if no old name is given a - /// new name will be generated. - /// - /// - /// Gets the new name for the given old name, where if no old name is given a - /// new name will be generated. - /// - /// - /// the new name. - public virtual string GetName(string oldName) - { - if (oldName != null && ((IDictionary)this.existing).ContainsKey(oldName)) - { - return (string)(this.existing[oldName]); - } - string name = this.prefix + this.counter; - this.counter++; - if (oldName != null) - { - this.existing[oldName] = name; - } - return name; - } + /// + /// Gets the new name for the given old name, where if no old name is given a + /// new name will be generated. + /// + /// + /// Gets the new name for the given old name, where if no old name is given a + /// new name will be generated. + /// + /// + /// the new name. + public virtual string GetName(string oldName) + { + if (oldName != null && ((IDictionary)this.existing).ContainsKey(oldName)) + { + return (string)(this.existing[oldName]); + } + string name = this.prefix + this.counter; + this.counter++; + if (oldName != null) + { + this.existing[oldName] = name; + } + return name; + } - public virtual string GetName() - { - return GetName(null); - } + public virtual string GetName() + { + return GetName(null); + } - public virtual bool IsNamed(string oldName) - { - return ((IDictionary)this.existing).ContainsKey(oldName); - } + public virtual bool IsNamed(string oldName) + { + return ((IDictionary)this.existing).ContainsKey(oldName); + } - public virtual JObject Existing() - { - return existing; - } - } + public virtual JObject Existing() + { + return existing; + } + } } diff --git a/src/JsonLD/Impl/NQuadRDFParser.cs b/src/JsonLD/Impl/NQuadRDFParser.cs index 56569f9..5a0bd32 100644 --- a/src/JsonLD/Impl/NQuadRDFParser.cs +++ b/src/JsonLD/Impl/NQuadRDFParser.cs @@ -4,20 +4,20 @@ namespace JsonLD.Impl { - public class NQuadRDFParser : IRDFParser - { - /// - public virtual RDFDataset Parse(JToken input) - { - if (input.Type == JTokenType.String) - { - return RDFDatasetUtils.ParseNQuads((string)input); - } - else - { - throw new JsonLdError(JsonLdError.Error.InvalidInput, "NQuad Parser expected string input." - ); - } - } - } + public class NQuadRDFParser : IRDFParser + { + /// + public virtual RDFDataset Parse(JToken input) + { + if (input.Type == JTokenType.String) + { + return RDFDatasetUtils.ParseNQuads((string)input); + } + else + { + throw new JsonLdError(JsonLdError.Error.InvalidInput, "NQuad Parser expected string input." + ); + } + } + } } diff --git a/src/JsonLD/Impl/NQuadTripleCallback.cs b/src/JsonLD/Impl/NQuadTripleCallback.cs index 33e66aa..83f6059 100644 --- a/src/JsonLD/Impl/NQuadTripleCallback.cs +++ b/src/JsonLD/Impl/NQuadTripleCallback.cs @@ -4,11 +4,11 @@ namespace JsonLD.Impl { - public class NQuadTripleCallback : IJSONLDTripleCallback - { - public virtual object Call(RDFDataset dataset) - { - return RDFDatasetUtils.ToNQuads(dataset); - } - } + public class NQuadTripleCallback : IJSONLDTripleCallback + { + public virtual object Call(RDFDataset dataset) + { + return RDFDatasetUtils.ToNQuads(dataset); + } + } } diff --git a/src/JsonLD/Impl/TurtleRDFParser.cs b/src/JsonLD/Impl/TurtleRDFParser.cs index 8fb295f..c282a25 100644 --- a/src/JsonLD/Impl/TurtleRDFParser.cs +++ b/src/JsonLD/Impl/TurtleRDFParser.cs @@ -5,729 +5,729 @@ namespace JsonLD.Impl { - /// - /// A (probably terribly slow) Parser for turtle -> the internal RDFDataset used - /// by JSOND-Java - /// TODO: this probably needs to be changed to use a proper parser/lexer - /// - /// Tristan - public class TurtleRDFParser : IRDFParser - { - internal class Regex - { - public static readonly Pattern PrefixId = Pattern.Compile("@prefix" + JsonLD.Core.Regex - .Ws1N + JsonLD.Core.Regex.PnameNs + JsonLD.Core.Regex.Ws1N + JsonLD.Core.Regex - .Iriref + JsonLD.Core.Regex.Ws0N + "\\." + JsonLD.Core.Regex.Ws0N); + /// + /// A (probably terribly slow) Parser for turtle -> the internal RDFDataset used + /// by JSOND-Java + /// TODO: this probably needs to be changed to use a proper parser/lexer + /// + /// Tristan + public class TurtleRDFParser : IRDFParser + { + internal class Regex + { + public static readonly Pattern PrefixId = Pattern.Compile("@prefix" + JsonLD.Core.Regex + .Ws1N + JsonLD.Core.Regex.PnameNs + JsonLD.Core.Regex.Ws1N + JsonLD.Core.Regex + .Iriref + JsonLD.Core.Regex.Ws0N + "\\." + JsonLD.Core.Regex.Ws0N); - public static readonly Pattern Base = Pattern.Compile("@base" + JsonLD.Core.Regex - .Ws1N + JsonLD.Core.Regex.Iriref + JsonLD.Core.Regex.Ws0N + "\\." + JsonLD.Core.Regex - .Ws0N); + public static readonly Pattern Base = Pattern.Compile("@base" + JsonLD.Core.Regex + .Ws1N + JsonLD.Core.Regex.Iriref + JsonLD.Core.Regex.Ws0N + "\\." + JsonLD.Core.Regex + .Ws0N); - public static readonly Pattern SparqlPrefix = Pattern.Compile("[Pp][Rr][Ee][Ff][Ii][Xx]" - + JsonLD.Core.Regex.Ws + JsonLD.Core.Regex.PnameNs + JsonLD.Core.Regex - .Ws + JsonLD.Core.Regex.Iriref + JsonLD.Core.Regex.Ws0N); + public static readonly Pattern SparqlPrefix = Pattern.Compile("[Pp][Rr][Ee][Ff][Ii][Xx]" + + JsonLD.Core.Regex.Ws + JsonLD.Core.Regex.PnameNs + JsonLD.Core.Regex + .Ws + JsonLD.Core.Regex.Iriref + JsonLD.Core.Regex.Ws0N); - public static readonly Pattern SparqlBase = Pattern.Compile("[Bb][Aa][Ss][Ee]" + - JsonLD.Core.Regex.Ws + JsonLD.Core.Regex.Iriref + JsonLD.Core.Regex.Ws0N - ); + public static readonly Pattern SparqlBase = Pattern.Compile("[Bb][Aa][Ss][Ee]" + + JsonLD.Core.Regex.Ws + JsonLD.Core.Regex.Iriref + JsonLD.Core.Regex.Ws0N + ); - public static readonly Pattern PrefixedName = Pattern.Compile("(?:" + JsonLD.Core.Regex - .PnameLn + "|" + JsonLD.Core.Regex.PnameNs + ")"); + public static readonly Pattern PrefixedName = Pattern.Compile("(?:" + JsonLD.Core.Regex + .PnameLn + "|" + JsonLD.Core.Regex.PnameNs + ")"); - public static readonly Pattern Iri = Pattern.Compile("(?:" + JsonLD.Core.Regex - .Iriref + "|" + PrefixedName + ")"); + public static readonly Pattern Iri = Pattern.Compile("(?:" + JsonLD.Core.Regex + .Iriref + "|" + PrefixedName + ")"); - public static readonly Pattern Anon = Pattern.Compile("(?:\\[" + JsonLD.Core.Regex - .Ws + "*\\])"); + public static readonly Pattern Anon = Pattern.Compile("(?:\\[" + JsonLD.Core.Regex + .Ws + "*\\])"); - public static readonly Pattern BlankNode = Pattern.Compile(JsonLD.Core.Regex.BlankNodeLabel - + "|" + Anon); + public static readonly Pattern BlankNode = Pattern.Compile(JsonLD.Core.Regex.BlankNodeLabel + + "|" + Anon); - public static readonly Pattern String = Pattern.Compile("(" + JsonLD.Core.Regex - .StringLiteralLongSingleQuote + "|" + JsonLD.Core.Regex.StringLiteralLongQuote - + "|" + JsonLD.Core.Regex.StringLiteralQuote + "|" + JsonLD.Core.Regex.StringLiteralSingleQuote - + ")"); + public static readonly Pattern String = Pattern.Compile("(" + JsonLD.Core.Regex + .StringLiteralLongSingleQuote + "|" + JsonLD.Core.Regex.StringLiteralLongQuote + + "|" + JsonLD.Core.Regex.StringLiteralQuote + "|" + JsonLD.Core.Regex.StringLiteralSingleQuote + + ")"); - public static readonly Pattern BooleanLiteral = Pattern.Compile("(true|false)"); + public static readonly Pattern BooleanLiteral = Pattern.Compile("(true|false)"); - public static readonly Pattern RdfLiteral = Pattern.Compile(String + "(?:" + JsonLD.Core.Regex - .Langtag + "|\\^\\^" + Iri + ")?"); + public static readonly Pattern RdfLiteral = Pattern.Compile(String + "(?:" + JsonLD.Core.Regex + .Langtag + "|\\^\\^" + Iri + ")?"); - public static readonly Pattern NumericLiteral = Pattern.Compile("(" + JsonLD.Core.Regex - .Double + ")|(" + JsonLD.Core.Regex.Decimal + ")|(" + JsonLD.Core.Regex.Integer - + ")"); + public static readonly Pattern NumericLiteral = Pattern.Compile("(" + JsonLD.Core.Regex + .Double + ")|(" + JsonLD.Core.Regex.Decimal + ")|(" + JsonLD.Core.Regex.Integer + + ")"); - public static readonly Pattern Literal = Pattern.Compile(RdfLiteral + "|" + NumericLiteral - + "|" + BooleanLiteral); + public static readonly Pattern Literal = Pattern.Compile(RdfLiteral + "|" + NumericLiteral + + "|" + BooleanLiteral); - public static readonly Pattern Directive = Pattern.Compile("^(?:" + PrefixId + "|" - + Base + "|" + SparqlPrefix + "|" + SparqlBase + ")"); + public static readonly Pattern Directive = Pattern.Compile("^(?:" + PrefixId + "|" + + Base + "|" + SparqlPrefix + "|" + SparqlBase + ")"); - public static readonly Pattern Subject = Pattern.Compile("^" + Iri + "|" + BlankNode - ); + public static readonly Pattern Subject = Pattern.Compile("^" + Iri + "|" + BlankNode + ); - public static readonly Pattern Predicate = Pattern.Compile("^" + Iri + "|a" + JsonLD.Core.Regex - .Ws1N); + public static readonly Pattern Predicate = Pattern.Compile("^" + Iri + "|a" + JsonLD.Core.Regex + .Ws1N); - public static readonly Pattern Object = Pattern.Compile("^" + Iri + "|" + BlankNode - + "|" + Literal); + public static readonly Pattern Object = Pattern.Compile("^" + Iri + "|" + BlankNode + + "|" + Literal); - public static readonly Pattern Eoln = Pattern.Compile("(?:\r\n)|(?:\n)|(?:\r)"); + public static readonly Pattern Eoln = Pattern.Compile("(?:\r\n)|(?:\n)|(?:\r)"); - public static readonly Pattern NextEoln = Pattern.Compile("^.*(?:" + Eoln + ")" + - JsonLD.Core.Regex.Ws0N); + public static readonly Pattern NextEoln = Pattern.Compile("^.*(?:" + Eoln + ")" + + JsonLD.Core.Regex.Ws0N); - public static readonly Pattern CommentOrWs = Pattern.Compile("^(?:(?:[#].*(?:" + - Eoln + ")" + JsonLD.Core.Regex.Ws0N + ")|(?:" + JsonLD.Core.Regex.Ws1N + "))" - ); - // others - // final public static Pattern WS_AT_LINE_START = Pattern.compile("^" + - // WS_1_N); - // final public static Pattern EMPTY_LINE = Pattern.compile("^" + WS + - // "*$"); - } + public static readonly Pattern CommentOrWs = Pattern.Compile("^(?:(?:[#].*(?:" + + Eoln + ")" + JsonLD.Core.Regex.Ws0N + ")|(?:" + JsonLD.Core.Regex.Ws1N + "))" + ); + // others + // final public static Pattern WS_AT_LINE_START = Pattern.compile("^" + + // WS_1_N); + // final public static Pattern EMPTY_LINE = Pattern.compile("^" + WS + + // "*$"); + } - private class State - { - internal string baseIri = string.Empty; + private class State + { + internal string baseIri = string.Empty; - internal IDictionary namespaces = new Dictionary( - ); + internal IDictionary namespaces = new Dictionary( + ); - internal string curSubject = null; + internal string curSubject = null; - internal string curPredicate = null; + internal string curPredicate = null; - internal string line = null; + internal string line = null; - internal int lineNumber = 0; + internal int lineNumber = 0; - internal int linePosition = 0; + internal int linePosition = 0; - internal UniqueNamer namer = new UniqueNamer("_:b"); + internal UniqueNamer namer = new UniqueNamer("_:b"); - private readonly Stack> stack = new Stack>(); + private readonly Stack> stack = new Stack>(); - public bool expectingBnodeClose = false; + public bool expectingBnodeClose = false; - /// - public State(TurtleRDFParser _enclosing, string input) - { - this._enclosing = _enclosing; - // int bnodes = 0; - // {{ getName(); }}; // call - // getName() after - // construction to make - // first active bnode _:b1 - this.line = input; - this.lineNumber = 1; - this.AdvanceLinePosition(0); - } + /// + public State(TurtleRDFParser _enclosing, string input) + { + this._enclosing = _enclosing; + // int bnodes = 0; + // {{ getName(); }}; // call + // getName() after + // construction to make + // first active bnode _:b1 + this.line = input; + this.lineNumber = 1; + this.AdvanceLinePosition(0); + } - public virtual void Push() - { - this.stack.Push(new _Dictionary_126(this)); - this.expectingBnodeClose = true; - this.curSubject = null; - this.curPredicate = null; - } + public virtual void Push() + { + this.stack.Push(new _Dictionary_126(this)); + this.expectingBnodeClose = true; + this.curSubject = null; + this.curPredicate = null; + } - private sealed class _Dictionary_126 : Dictionary - { + private sealed class _Dictionary_126 : Dictionary + { State _enclosing; public _Dictionary_126(State trp) - { + { _enclosing = trp; - { - this[this._enclosing.curSubject] = this._enclosing.curPredicate; - } - } - } - - public virtual void Pop() - { - if (this.stack.Count > 0) - { - foreach (KeyValuePair x in this.stack.Pop().GetEnumerableSelf()) - { - this.curSubject = x.Key; - this.curPredicate = x.Value; - } - } - if (this.stack.Count == 0) - { - this.expectingBnodeClose = false; - } - } - - /// - private void AdvanceLineNumber() - { - Matcher match = TurtleRDFParser.Regex.NextEoln.Matcher(this.line); - if (match.Find()) - { - string[] split = match.Group(0).Split(string.Empty + TurtleRDFParser.Regex.Eoln); - this.lineNumber += (split.Length - 1); - this.linePosition += split[split.Length - 1].Length; - this.line = JsonLD.JavaCompat.Substring(this.line, match.Group(0).Length); - } - } - - /// - public virtual void AdvanceLinePosition(int len) - { - if (len > 0) - { - this.linePosition += len; - this.line = JsonLD.JavaCompat.Substring(this.line, len); - } - while (!string.Empty.Equals(this.line)) - { - // clear any whitespace - Matcher match = TurtleRDFParser.Regex.CommentOrWs.Matcher(this.line); - if (match.Find() && match.Group(0).Length > 0) - { - Matcher eoln = TurtleRDFParser.Regex.Eoln.Matcher(match.Group(0)); - int end = 0; - while (eoln.Find()) - { - this.lineNumber += 1; - end = eoln.End(); - } - this.linePosition = match.Group(0).Length - end; - this.line = JsonLD.JavaCompat.Substring(this.line, match.Group(0).Length); - } - else - { - break; - } - } - if (string.Empty.Equals(this.line) && !this.EndIsOK()) - { - throw new JsonLdError(JsonLdError.Error.ParseError, "Error while parsing Turtle; unexpected end of input. {line: " - + this.lineNumber + ", position:" + this.linePosition + "}"); - } - } - - private bool EndIsOK() - { - return this.curSubject == null && this.stack.Count == 0; - } - - /// - public virtual string ExpandIRI(string ns, string name) - { - if (this.namespaces.ContainsKey(ns)) - { - return this.namespaces[ns] + name; - } - else - { - throw new JsonLdError(JsonLdError.Error.ParseError, "No prefix found for: " + ns - + " {line: " + this.lineNumber + ", position:" + this.linePosition + "}"); - } - } - - private readonly TurtleRDFParser _enclosing; - } - - /// - public virtual RDFDataset Parse(JToken input) - { - if (!(input.Type == JTokenType.String)) - { - throw new JsonLdError(JsonLdError.Error.InvalidInput, "Invalid input; Triple RDF Parser requires a string input" - ); - } - RDFDataset result = new RDFDataset(); - TurtleRDFParser.State state = new TurtleRDFParser.State(this, (string)input); - while (!string.Empty.Equals(state.line)) - { - // check if line is a directive - Matcher match = TurtleRDFParser.Regex.Directive.Matcher(state.line); - if (match.Find()) - { - if (match.Group(1) != null || match.Group(4) != null) - { - string ns = match.Group(1) != null ? match.Group(1) : match.Group(4); - string iri = match.Group(1) != null ? match.Group(2) : match.Group(5); - if (!iri.Contains(":")) - { - iri = state.baseIri + iri; - } - iri = RDFDatasetUtils.Unescape(iri); - ValidateIRI(state, iri); - state.namespaces[ns] = iri; - result.SetNamespace(ns, iri); - } - else - { - string @base = match.Group(3) != null ? match.Group(3) : match.Group(6); - @base = RDFDatasetUtils.Unescape(@base); - ValidateIRI(state, @base); - if (!@base.Contains(":")) - { - state.baseIri = state.baseIri + @base; - } - else - { - state.baseIri = @base; - } - } - state.AdvanceLinePosition(match.Group(0).Length); - continue; - } - if (state.curSubject == null) - { - // we need to match a subject - match = TurtleRDFParser.Regex.Subject.Matcher(state.line); - if (match.Find()) - { - string iri; - if (match.Group(1) != null) - { - // matched IRI - iri = RDFDatasetUtils.Unescape(match.Group(1)); - if (!iri.Contains(":")) - { - iri = state.baseIri + iri; - } - } - else - { - if (match.Group(2) != null) - { - // matched NS:NAME - string ns = match.Group(2); - string name = UnescapeReserved(match.Group(3)); - iri = state.ExpandIRI(ns, name); - } - else - { - if (match.Group(4) != null) - { - // match ns: only - iri = state.ExpandIRI(match.Group(4), string.Empty); - } - else - { - if (match.Group(5) != null) - { - // matched BNODE - iri = state.namer.GetName(match.Group(0).Trim()); - } - else - { - // matched anon node - iri = state.namer.GetName(); - } - } - } - } - // make sure IRI still matches an IRI after escaping - ValidateIRI(state, iri); - state.curSubject = iri; - state.AdvanceLinePosition(match.Group(0).Length); - } - else - { - // handle blank nodes - if (state.line.StartsWith("[")) - { - string bnode = state.namer.GetName(); - state.AdvanceLinePosition(1); - state.Push(); - state.curSubject = bnode; - } - else - { - // handle collections - if (state.line.StartsWith("(")) - { - string bnode = state.namer.GetName(); - // so we know we want a predicate if the collection close - // isn't followed by a subject end - state.curSubject = bnode; - state.AdvanceLinePosition(1); - state.Push(); - state.curSubject = bnode; - state.curPredicate = JSONLDConsts.RdfFirst; - } - else - { - // make sure we have a subject already - throw new JsonLdError(JsonLdError.Error.ParseError, "Error while parsing Turtle; missing expected subject. {line: " - + state.lineNumber + "position: " + state.linePosition + "}"); - } - } - } - } - if (state.curPredicate == null) - { - // match predicate - match = TurtleRDFParser.Regex.Predicate.Matcher(state.line); - if (match.Find()) - { - string iri = string.Empty; - if (match.Group(1) != null) - { - // matched IRI - iri = RDFDatasetUtils.Unescape(match.Group(1)); - if (!iri.Contains(":")) - { - iri = state.baseIri + iri; - } - } - else - { - if (match.Group(2) != null) - { - // matched NS:NAME - string ns = match.Group(2); - string name = UnescapeReserved(match.Group(3)); - iri = state.ExpandIRI(ns, name); - } - else - { - if (match.Group(4) != null) - { - // matched ns: - iri = state.ExpandIRI(match.Group(4), string.Empty); - } - else - { - // matched "a" - iri = JSONLDConsts.RdfType; - } - } - } - ValidateIRI(state, iri); - state.curPredicate = iri; - state.AdvanceLinePosition(match.Group(0).Length); - } - else - { - throw new JsonLdError(JsonLdError.Error.ParseError, "Error while parsing Turtle; missing expected predicate. {line: " - + state.lineNumber + "position: " + state.linePosition + "}"); - } - } - // expecting bnode or object - // match BNODE values - if (state.line.StartsWith("[")) - { - string bnode = state.namer.GetName(); - result.AddTriple(state.curSubject, state.curPredicate, bnode); - state.AdvanceLinePosition(1); - // check for anonymous objects - if (state.line.StartsWith("]")) - { - state.AdvanceLinePosition(1); - } - else - { - // next we expect a statement or object separator - // otherwise we're inside the blank node - state.Push(); - state.curSubject = bnode; - // next we expect a predicate - continue; - } - } - else - { - // match collections - if (state.line.StartsWith("(")) - { - state.AdvanceLinePosition(1); - // check for empty collection - if (state.line.StartsWith(")")) - { - state.AdvanceLinePosition(1); - result.AddTriple(state.curSubject, state.curPredicate, JSONLDConsts.RdfNil); - } - else - { - // next we expect a statement or object separator - // otherwise we're inside the collection - string bnode = state.namer.GetName(); - result.AddTriple(state.curSubject, state.curPredicate, bnode); - state.Push(); - state.curSubject = bnode; - state.curPredicate = JSONLDConsts.RdfFirst; - continue; - } - } - else - { - // match object - match = TurtleRDFParser.Regex.Object.Matcher(state.line); - if (match.Find()) - { - string iri = null; - if (match.Group(1) != null) - { - // matched IRI - iri = RDFDatasetUtils.Unescape(match.Group(1)); - if (!iri.Contains(":")) - { - iri = state.baseIri + iri; - } - } - else - { - if (match.Group(2) != null) - { - // matched NS:NAME - string ns = match.Group(2); - string name = UnescapeReserved(match.Group(3)); - iri = state.ExpandIRI(ns, name); - } - else - { - if (match.Group(4) != null) - { - // matched ns: - iri = state.ExpandIRI(match.Group(4), string.Empty); - } - else - { - if (match.Group(5) != null) - { - // matched BNODE - iri = state.namer.GetName(match.Group(0).Trim()); - } - } - } - } - if (iri != null) - { - ValidateIRI(state, iri); - // we have a object - result.AddTriple(state.curSubject, state.curPredicate, iri); - } - else - { - // we have a literal - string value = match.Group(6); - string lang = null; - string datatype = null; - if (value != null) - { - // we have a string literal - value = UnquoteString(value); - value = RDFDatasetUtils.Unescape(value); - lang = match.Group(7); - if (lang == null) - { - if (match.Group(8) != null) - { - datatype = RDFDatasetUtils.Unescape(match.Group(8)); - if (!datatype.Contains(":")) - { - datatype = state.baseIri + datatype; - } - ValidateIRI(state, datatype); - } - else - { - if (match.Group(9) != null) - { - datatype = state.ExpandIRI(match.Group(9), UnescapeReserved(match.Group(10))); - } - else - { - if (match.Group(11) != null) - { - datatype = state.ExpandIRI(match.Group(11), string.Empty); - } - } - } - } - else - { - datatype = JSONLDConsts.RdfLangstring; - } - } - else - { - if (match.Group(12) != null) - { - // integer literal - value = match.Group(12); - datatype = JSONLDConsts.XsdDouble; - } - else - { - if (match.Group(13) != null) - { - // decimal literal - value = match.Group(13); - datatype = JSONLDConsts.XsdDecimal; - } - else - { - if (match.Group(14) != null) - { - // double literal - value = match.Group(14); - datatype = JSONLDConsts.XsdInteger; - } - else - { - if (match.Group(15) != null) - { - // boolean literal - value = match.Group(15); - datatype = JSONLDConsts.XsdBoolean; - } - } - } - } - } - result.AddTriple(state.curSubject, state.curPredicate, value, datatype, lang); - } - state.AdvanceLinePosition(match.Group(0).Length); - } - else - { - throw new JsonLdError(JsonLdError.Error.ParseError, "Error while parsing Turtle; missing expected object or blank node. {line: " - + state.lineNumber + "position: " + state.linePosition + "}"); - } - } - } - // close collection - bool collectionClosed = false; - while (state.line.StartsWith(")")) - { - if (!JSONLDConsts.RdfFirst.Equals(state.curPredicate)) - { - throw new JsonLdError(JsonLdError.Error.ParseError, "Error while parsing Turtle; unexpected ). {line: " - + state.lineNumber + "position: " + state.linePosition + "}"); - } - result.AddTriple(state.curSubject, JSONLDConsts.RdfRest, JSONLDConsts.RdfNil); - state.Pop(); - state.AdvanceLinePosition(1); - collectionClosed = true; - } - bool expectDotOrPred = false; - // match end of bnode - if (state.line.StartsWith("]")) - { - string bnode = state.curSubject; - state.Pop(); - state.AdvanceLinePosition(1); - if (state.curSubject == null) - { - // this is a bnode as a subject and we - // expect either a . or a predicate - state.curSubject = bnode; - expectDotOrPred = true; - } - } - // match list separator - if (!expectDotOrPred && state.line.StartsWith(",")) - { - state.AdvanceLinePosition(1); - // now we expect another object/bnode - continue; - } - // match predicate end - if (!expectDotOrPred) - { - while (state.line.StartsWith(";")) - { - state.curPredicate = null; - state.AdvanceLinePosition(1); - // now we expect another predicate, or a dot - expectDotOrPred = true; - } - } - if (state.line.StartsWith(".")) - { - if (state.expectingBnodeClose) - { - throw new JsonLdError(JsonLdError.Error.ParseError, "Error while parsing Turtle; missing expected )\"]\". {line: " - + state.lineNumber + "position: " + state.linePosition + "}"); - } - state.curSubject = null; - state.curPredicate = null; - state.AdvanceLinePosition(1); - // this can now be the end of the document. - continue; - } - else - { - if (expectDotOrPred) - { - // we're expecting another predicate since we didn't find a dot - continue; - } - } - // if we're in a collection - if (JSONLDConsts.RdfFirst.Equals(state.curPredicate)) - { - string bnode = state.namer.GetName(); - result.AddTriple(state.curSubject, JSONLDConsts.RdfRest, bnode); - state.curSubject = bnode; - continue; - } - if (collectionClosed) - { - // we expect another object - // TODO: it's not clear yet if this is valid - continue; - } - // if we get here, we're missing a close statement - throw new JsonLdError(JsonLdError.Error.ParseError, "Error while parsing Turtle; missing expected \"]\" \",\" \";\" or \".\". {line: " - + state.lineNumber + "position: " + state.linePosition + "}"); - } - return result; - } - - internal static readonly Pattern IrirefMinusContainer = Pattern.Compile("(?:(?:[^\\x00-\\x20<>\"{}|\\^`\\\\]|" - + JsonLD.Core.Regex.Uchar + ")*)|" + TurtleRDFParser.Regex.PrefixedName); - - /// - private void ValidateIRI(TurtleRDFParser.State state, string iri) - { - if (!IrirefMinusContainer.Matcher(iri).Matches()) - { - throw new JsonLdError(JsonLdError.Error.ParseError, "Error while parsing Turtle; invalid IRI after escaping. {line: " - + state.lineNumber + "position: " + state.linePosition + "}"); - } - } - - private static readonly Pattern PnLocalEscMatched = Pattern.Compile("[\\\\]([_~\\.\\-!$&'\\(\\)*+,;=/?#@%])" - ); - - internal static string UnescapeReserved(string str) - { - if (str != null) - { - Matcher m = PnLocalEscMatched.Matcher(str); - if (m.Find()) - { - return m.ReplaceAll("$1"); - } - } - return str; - } - - private string UnquoteString(string value) - { - if (value.StartsWith("\"\"\"") || value.StartsWith("'''")) - { - return JsonLD.JavaCompat.Substring(value, 3, value.Length - 3); - } - else - { - if (value.StartsWith("\"") || value.StartsWith("'")) - { - return JsonLD.JavaCompat.Substring(value, 1, value.Length - 1); - } - } - return value; - } - } + { + this[this._enclosing.curSubject] = this._enclosing.curPredicate; + } + } + } + + public virtual void Pop() + { + if (this.stack.Count > 0) + { + foreach (KeyValuePair x in this.stack.Pop().GetEnumerableSelf()) + { + this.curSubject = x.Key; + this.curPredicate = x.Value; + } + } + if (this.stack.Count == 0) + { + this.expectingBnodeClose = false; + } + } + + /// + private void AdvanceLineNumber() + { + Matcher match = TurtleRDFParser.Regex.NextEoln.Matcher(this.line); + if (match.Find()) + { + string[] split = match.Group(0).Split(string.Empty + TurtleRDFParser.Regex.Eoln); + this.lineNumber += (split.Length - 1); + this.linePosition += split[split.Length - 1].Length; + this.line = JsonLD.JavaCompat.Substring(this.line, match.Group(0).Length); + } + } + + /// + public virtual void AdvanceLinePosition(int len) + { + if (len > 0) + { + this.linePosition += len; + this.line = JsonLD.JavaCompat.Substring(this.line, len); + } + while (!string.Empty.Equals(this.line)) + { + // clear any whitespace + Matcher match = TurtleRDFParser.Regex.CommentOrWs.Matcher(this.line); + if (match.Find() && match.Group(0).Length > 0) + { + Matcher eoln = TurtleRDFParser.Regex.Eoln.Matcher(match.Group(0)); + int end = 0; + while (eoln.Find()) + { + this.lineNumber += 1; + end = eoln.End(); + } + this.linePosition = match.Group(0).Length - end; + this.line = JsonLD.JavaCompat.Substring(this.line, match.Group(0).Length); + } + else + { + break; + } + } + if (string.Empty.Equals(this.line) && !this.EndIsOK()) + { + throw new JsonLdError(JsonLdError.Error.ParseError, "Error while parsing Turtle; unexpected end of input. {line: " + + this.lineNumber + ", position:" + this.linePosition + "}"); + } + } + + private bool EndIsOK() + { + return this.curSubject == null && this.stack.Count == 0; + } + + /// + public virtual string ExpandIRI(string ns, string name) + { + if (this.namespaces.ContainsKey(ns)) + { + return this.namespaces[ns] + name; + } + else + { + throw new JsonLdError(JsonLdError.Error.ParseError, "No prefix found for: " + ns + + " {line: " + this.lineNumber + ", position:" + this.linePosition + "}"); + } + } + + private readonly TurtleRDFParser _enclosing; + } + + /// + public virtual RDFDataset Parse(JToken input) + { + if (!(input.Type == JTokenType.String)) + { + throw new JsonLdError(JsonLdError.Error.InvalidInput, "Invalid input; Triple RDF Parser requires a string input" + ); + } + RDFDataset result = new RDFDataset(); + TurtleRDFParser.State state = new TurtleRDFParser.State(this, (string)input); + while (!string.Empty.Equals(state.line)) + { + // check if line is a directive + Matcher match = TurtleRDFParser.Regex.Directive.Matcher(state.line); + if (match.Find()) + { + if (match.Group(1) != null || match.Group(4) != null) + { + string ns = match.Group(1) != null ? match.Group(1) : match.Group(4); + string iri = match.Group(1) != null ? match.Group(2) : match.Group(5); + if (!iri.Contains(":")) + { + iri = state.baseIri + iri; + } + iri = RDFDatasetUtils.Unescape(iri); + ValidateIRI(state, iri); + state.namespaces[ns] = iri; + result.SetNamespace(ns, iri); + } + else + { + string @base = match.Group(3) != null ? match.Group(3) : match.Group(6); + @base = RDFDatasetUtils.Unescape(@base); + ValidateIRI(state, @base); + if (!@base.Contains(":")) + { + state.baseIri = state.baseIri + @base; + } + else + { + state.baseIri = @base; + } + } + state.AdvanceLinePosition(match.Group(0).Length); + continue; + } + if (state.curSubject == null) + { + // we need to match a subject + match = TurtleRDFParser.Regex.Subject.Matcher(state.line); + if (match.Find()) + { + string iri; + if (match.Group(1) != null) + { + // matched IRI + iri = RDFDatasetUtils.Unescape(match.Group(1)); + if (!iri.Contains(":")) + { + iri = state.baseIri + iri; + } + } + else + { + if (match.Group(2) != null) + { + // matched NS:NAME + string ns = match.Group(2); + string name = UnescapeReserved(match.Group(3)); + iri = state.ExpandIRI(ns, name); + } + else + { + if (match.Group(4) != null) + { + // match ns: only + iri = state.ExpandIRI(match.Group(4), string.Empty); + } + else + { + if (match.Group(5) != null) + { + // matched BNODE + iri = state.namer.GetName(match.Group(0).Trim()); + } + else + { + // matched anon node + iri = state.namer.GetName(); + } + } + } + } + // make sure IRI still matches an IRI after escaping + ValidateIRI(state, iri); + state.curSubject = iri; + state.AdvanceLinePosition(match.Group(0).Length); + } + else + { + // handle blank nodes + if (state.line.StartsWith("[")) + { + string bnode = state.namer.GetName(); + state.AdvanceLinePosition(1); + state.Push(); + state.curSubject = bnode; + } + else + { + // handle collections + if (state.line.StartsWith("(")) + { + string bnode = state.namer.GetName(); + // so we know we want a predicate if the collection close + // isn't followed by a subject end + state.curSubject = bnode; + state.AdvanceLinePosition(1); + state.Push(); + state.curSubject = bnode; + state.curPredicate = JSONLDConsts.RdfFirst; + } + else + { + // make sure we have a subject already + throw new JsonLdError(JsonLdError.Error.ParseError, "Error while parsing Turtle; missing expected subject. {line: " + + state.lineNumber + "position: " + state.linePosition + "}"); + } + } + } + } + if (state.curPredicate == null) + { + // match predicate + match = TurtleRDFParser.Regex.Predicate.Matcher(state.line); + if (match.Find()) + { + string iri = string.Empty; + if (match.Group(1) != null) + { + // matched IRI + iri = RDFDatasetUtils.Unescape(match.Group(1)); + if (!iri.Contains(":")) + { + iri = state.baseIri + iri; + } + } + else + { + if (match.Group(2) != null) + { + // matched NS:NAME + string ns = match.Group(2); + string name = UnescapeReserved(match.Group(3)); + iri = state.ExpandIRI(ns, name); + } + else + { + if (match.Group(4) != null) + { + // matched ns: + iri = state.ExpandIRI(match.Group(4), string.Empty); + } + else + { + // matched "a" + iri = JSONLDConsts.RdfType; + } + } + } + ValidateIRI(state, iri); + state.curPredicate = iri; + state.AdvanceLinePosition(match.Group(0).Length); + } + else + { + throw new JsonLdError(JsonLdError.Error.ParseError, "Error while parsing Turtle; missing expected predicate. {line: " + + state.lineNumber + "position: " + state.linePosition + "}"); + } + } + // expecting bnode or object + // match BNODE values + if (state.line.StartsWith("[")) + { + string bnode = state.namer.GetName(); + result.AddTriple(state.curSubject, state.curPredicate, bnode); + state.AdvanceLinePosition(1); + // check for anonymous objects + if (state.line.StartsWith("]")) + { + state.AdvanceLinePosition(1); + } + else + { + // next we expect a statement or object separator + // otherwise we're inside the blank node + state.Push(); + state.curSubject = bnode; + // next we expect a predicate + continue; + } + } + else + { + // match collections + if (state.line.StartsWith("(")) + { + state.AdvanceLinePosition(1); + // check for empty collection + if (state.line.StartsWith(")")) + { + state.AdvanceLinePosition(1); + result.AddTriple(state.curSubject, state.curPredicate, JSONLDConsts.RdfNil); + } + else + { + // next we expect a statement or object separator + // otherwise we're inside the collection + string bnode = state.namer.GetName(); + result.AddTriple(state.curSubject, state.curPredicate, bnode); + state.Push(); + state.curSubject = bnode; + state.curPredicate = JSONLDConsts.RdfFirst; + continue; + } + } + else + { + // match object + match = TurtleRDFParser.Regex.Object.Matcher(state.line); + if (match.Find()) + { + string iri = null; + if (match.Group(1) != null) + { + // matched IRI + iri = RDFDatasetUtils.Unescape(match.Group(1)); + if (!iri.Contains(":")) + { + iri = state.baseIri + iri; + } + } + else + { + if (match.Group(2) != null) + { + // matched NS:NAME + string ns = match.Group(2); + string name = UnescapeReserved(match.Group(3)); + iri = state.ExpandIRI(ns, name); + } + else + { + if (match.Group(4) != null) + { + // matched ns: + iri = state.ExpandIRI(match.Group(4), string.Empty); + } + else + { + if (match.Group(5) != null) + { + // matched BNODE + iri = state.namer.GetName(match.Group(0).Trim()); + } + } + } + } + if (iri != null) + { + ValidateIRI(state, iri); + // we have a object + result.AddTriple(state.curSubject, state.curPredicate, iri); + } + else + { + // we have a literal + string value = match.Group(6); + string lang = null; + string datatype = null; + if (value != null) + { + // we have a string literal + value = UnquoteString(value); + value = RDFDatasetUtils.Unescape(value); + lang = match.Group(7); + if (lang == null) + { + if (match.Group(8) != null) + { + datatype = RDFDatasetUtils.Unescape(match.Group(8)); + if (!datatype.Contains(":")) + { + datatype = state.baseIri + datatype; + } + ValidateIRI(state, datatype); + } + else + { + if (match.Group(9) != null) + { + datatype = state.ExpandIRI(match.Group(9), UnescapeReserved(match.Group(10))); + } + else + { + if (match.Group(11) != null) + { + datatype = state.ExpandIRI(match.Group(11), string.Empty); + } + } + } + } + else + { + datatype = JSONLDConsts.RdfLangstring; + } + } + else + { + if (match.Group(12) != null) + { + // integer literal + value = match.Group(12); + datatype = JSONLDConsts.XsdDouble; + } + else + { + if (match.Group(13) != null) + { + // decimal literal + value = match.Group(13); + datatype = JSONLDConsts.XsdDecimal; + } + else + { + if (match.Group(14) != null) + { + // double literal + value = match.Group(14); + datatype = JSONLDConsts.XsdInteger; + } + else + { + if (match.Group(15) != null) + { + // boolean literal + value = match.Group(15); + datatype = JSONLDConsts.XsdBoolean; + } + } + } + } + } + result.AddTriple(state.curSubject, state.curPredicate, value, datatype, lang); + } + state.AdvanceLinePosition(match.Group(0).Length); + } + else + { + throw new JsonLdError(JsonLdError.Error.ParseError, "Error while parsing Turtle; missing expected object or blank node. {line: " + + state.lineNumber + "position: " + state.linePosition + "}"); + } + } + } + // close collection + bool collectionClosed = false; + while (state.line.StartsWith(")")) + { + if (!JSONLDConsts.RdfFirst.Equals(state.curPredicate)) + { + throw new JsonLdError(JsonLdError.Error.ParseError, "Error while parsing Turtle; unexpected ). {line: " + + state.lineNumber + "position: " + state.linePosition + "}"); + } + result.AddTriple(state.curSubject, JSONLDConsts.RdfRest, JSONLDConsts.RdfNil); + state.Pop(); + state.AdvanceLinePosition(1); + collectionClosed = true; + } + bool expectDotOrPred = false; + // match end of bnode + if (state.line.StartsWith("]")) + { + string bnode = state.curSubject; + state.Pop(); + state.AdvanceLinePosition(1); + if (state.curSubject == null) + { + // this is a bnode as a subject and we + // expect either a . or a predicate + state.curSubject = bnode; + expectDotOrPred = true; + } + } + // match list separator + if (!expectDotOrPred && state.line.StartsWith(",")) + { + state.AdvanceLinePosition(1); + // now we expect another object/bnode + continue; + } + // match predicate end + if (!expectDotOrPred) + { + while (state.line.StartsWith(";")) + { + state.curPredicate = null; + state.AdvanceLinePosition(1); + // now we expect another predicate, or a dot + expectDotOrPred = true; + } + } + if (state.line.StartsWith(".")) + { + if (state.expectingBnodeClose) + { + throw new JsonLdError(JsonLdError.Error.ParseError, "Error while parsing Turtle; missing expected )\"]\". {line: " + + state.lineNumber + "position: " + state.linePosition + "}"); + } + state.curSubject = null; + state.curPredicate = null; + state.AdvanceLinePosition(1); + // this can now be the end of the document. + continue; + } + else + { + if (expectDotOrPred) + { + // we're expecting another predicate since we didn't find a dot + continue; + } + } + // if we're in a collection + if (JSONLDConsts.RdfFirst.Equals(state.curPredicate)) + { + string bnode = state.namer.GetName(); + result.AddTriple(state.curSubject, JSONLDConsts.RdfRest, bnode); + state.curSubject = bnode; + continue; + } + if (collectionClosed) + { + // we expect another object + // TODO: it's not clear yet if this is valid + continue; + } + // if we get here, we're missing a close statement + throw new JsonLdError(JsonLdError.Error.ParseError, "Error while parsing Turtle; missing expected \"]\" \",\" \";\" or \".\". {line: " + + state.lineNumber + "position: " + state.linePosition + "}"); + } + return result; + } + + internal static readonly Pattern IrirefMinusContainer = Pattern.Compile("(?:(?:[^\\x00-\\x20<>\"{}|\\^`\\\\]|" + + JsonLD.Core.Regex.Uchar + ")*)|" + TurtleRDFParser.Regex.PrefixedName); + + /// + private void ValidateIRI(TurtleRDFParser.State state, string iri) + { + if (!IrirefMinusContainer.Matcher(iri).Matches()) + { + throw new JsonLdError(JsonLdError.Error.ParseError, "Error while parsing Turtle; invalid IRI after escaping. {line: " + + state.lineNumber + "position: " + state.linePosition + "}"); + } + } + + private static readonly Pattern PnLocalEscMatched = Pattern.Compile("[\\\\]([_~\\.\\-!$&'\\(\\)*+,;=/?#@%])" + ); + + internal static string UnescapeReserved(string str) + { + if (str != null) + { + Matcher m = PnLocalEscMatched.Matcher(str); + if (m.Find()) + { + return m.ReplaceAll("$1"); + } + } + return str; + } + + private string UnquoteString(string value) + { + if (value.StartsWith("\"\"\"") || value.StartsWith("'''")) + { + return JsonLD.JavaCompat.Substring(value, 3, value.Length - 3); + } + else + { + if (value.StartsWith("\"") || value.StartsWith("'")) + { + return JsonLD.JavaCompat.Substring(value, 1, value.Length - 1); + } + } + return value; + } + } } diff --git a/src/JsonLD/Impl/TurtleTripleCallback.cs b/src/JsonLD/Impl/TurtleTripleCallback.cs index 0cc3f5a..f2562cc 100644 --- a/src/JsonLD/Impl/TurtleTripleCallback.cs +++ b/src/JsonLD/Impl/TurtleTripleCallback.cs @@ -4,433 +4,433 @@ namespace JsonLD.Impl { - public class TurtleTripleCallback : IJSONLDTripleCallback - { - private const int MaxLineLength = 160; + public class TurtleTripleCallback : IJSONLDTripleCallback + { + private const int MaxLineLength = 160; - private const int TabSpaces = 4; + private const int TabSpaces = 4; - private const string ColsKey = "..cols.."; + private const string ColsKey = "..cols.."; - private sealed class _Dictionary_32 : Dictionary - { - public _Dictionary_32() - { - { - } - } - } + private sealed class _Dictionary_32 : Dictionary + { + public _Dictionary_32() + { + { + } + } + } - internal readonly IDictionary availableNamespaces = new _Dictionary_32 - (); + internal readonly IDictionary availableNamespaces = new _Dictionary_32 + (); - internal ICollection usedNamespaces; + internal ICollection usedNamespaces; - public TurtleTripleCallback() - { - } + public TurtleTripleCallback() + { + } - // this shouldn't be a - // valid iri/bnode i - // hope! - // TODO: fill with default namespaces - public virtual object Call(RDFDataset dataset) - { - foreach (KeyValuePair e in dataset.GetNamespaces().GetEnumerableSelf - ()) - { - availableNamespaces[e.Value] = e.Key; - } - usedNamespaces = new HashSet(); - int tabs = 0; - JObject refs = new JObject(); - JObject ttl = new JObject(); - foreach (string graphName in dataset.Keys) - { + // this shouldn't be a + // valid iri/bnode i + // hope! + // TODO: fill with default namespaces + public virtual object Call(RDFDataset dataset) + { + foreach (KeyValuePair e in dataset.GetNamespaces().GetEnumerableSelf + ()) + { + availableNamespaces[e.Value] = e.Key; + } + usedNamespaces = new HashSet(); + int tabs = 0; + JObject refs = new JObject(); + JObject ttl = new JObject(); + foreach (string graphName in dataset.Keys) + { string localGraphName = graphName; - IList triples = (IList)dataset.GetQuads(localGraphName); - if ("@default".Equals(localGraphName)) - { - localGraphName = null; - } - // http://www.w3.org/TR/turtle/#unlabeled-bnodes - // TODO: implement nesting for unlabled nodes - // map of what the output should look like - // subj (or [ if bnode) > pred > obj - // > obj (set ref if IRI) - // > pred > obj (set ref if bnode) - // subj > etc etc etc - // subjid -> [ ref, ref, ref ] - string prevSubject = string.Empty; - string prevPredicate = string.Empty; - JObject thisSubject = null; - JArray thisPredicate = null; - foreach (RDFDataset.Quad triple in triples) - { - string subject = triple.GetSubject().GetValue(); - string predicate = triple.GetPredicate().GetValue(); - if (prevSubject.Equals(subject)) - { - if (prevPredicate.Equals(predicate)) - { - } - else - { - // nothing to do - // new predicate - if (thisSubject.ContainsKey(predicate)) - { - thisPredicate = (JArray)thisSubject[predicate]; - } - else - { - thisPredicate = new JArray(); - thisSubject[predicate] = thisPredicate; - } - prevPredicate = predicate; - } - } - else - { - // new subject - if (ttl.ContainsKey(subject)) - { - thisSubject = (JObject)ttl[subject]; - } - else - { - thisSubject = new JObject(); - ttl[subject] = thisSubject; - } - if (thisSubject.ContainsKey(predicate)) - { - thisPredicate = (JArray)thisSubject[predicate]; - } - else - { - thisPredicate = new JArray(); - thisSubject[predicate] = thisPredicate; - } - prevSubject = subject; - prevPredicate = predicate; - } - if (triple.GetObject().IsLiteral()) - { - thisPredicate.Add(triple.GetObject()); - } - else - { - string o = triple.GetObject().GetValue(); - if (o.StartsWith("_:")) - { - // add ref to o - if (!refs.ContainsKey(o)) - { - refs[o] = new JArray(); - } - ((JArray)refs[o]).Add(thisPredicate); - } - thisPredicate.Add(o); - } - } - } - JObject collections = new JObject(); - JArray subjects = new JArray(ttl.GetKeys()); - // find collections - foreach (string subj in subjects) - { - JObject preds = (JObject)ttl[subj]; - if (preds != null && preds.ContainsKey(JSONLDConsts.RdfFirst)) - { - JArray col = new JArray(); - collections[subj] = col; - while (true) - { - JArray first = (JArray)JsonLD.Collections.Remove(preds, JSONLDConsts.RdfFirst); - JToken o = first[0]; - col.Add(o); - // refs - if (refs.ContainsKey((string)o)) - { - ((JArray)refs[(string)o]).Remove(first); - ((JArray)refs[(string)o]).Add(col); - } - string next = (string)JsonLD.Collections.Remove(preds, JSONLDConsts.RdfRest)[0 - ]; - if (JSONLDConsts.RdfNil.Equals(next)) - { - // end of this list - break; - } - // if collections already contains a value for "next", add - // it to this col and break out - if (collections.ContainsKey(next)) - { - JsonLD.Collections.AddAll(col, (JArray)JsonLD.Collections.Remove(collections, next)); - break; - } - preds = (JObject)JsonLD.Collections.Remove(ttl, next); - JsonLD.Collections.Remove(refs, next); - } - } - } - // process refs (nesting referenced bnodes if only one reference to them - // in the whole graph) - foreach (string id in refs.GetKeys()) - { - // skip items if there is more than one reference to them in the - // graph - if (((JArray)refs[id]).Count > 1) - { - continue; - } - // otherwise embed them into the referenced location - JToken @object = JsonLD.Collections.Remove(ttl, id); - if (collections.ContainsKey(id)) - { - @object = new JObject(); - JArray tmp = new JArray(); - tmp.Add(JsonLD.Collections.Remove(collections, id)); - ((JObject)@object)[ColsKey] = tmp; - } - JArray predicate = (JArray)refs[id][0]; - // replace the one bnode ref with the object - predicate[predicate.LastIndexOf(id)] = (JToken)@object; - } - // replace the rest of the collections - foreach (string id_1 in collections.GetKeys()) - { - JObject subj_1 = (JObject)ttl[id_1]; - if (!subj_1.ContainsKey(ColsKey)) - { - subj_1[ColsKey] = new JArray(); - } - ((JArray)subj_1[ColsKey]).Add(collections[id_1]); - } - // build turtle output - string output = GenerateTurtle(ttl, 0, 0, false); - string prefixes = string.Empty; - foreach (string prefix in usedNamespaces) - { - string name = availableNamespaces[prefix]; - prefixes += "@prefix " + name + ": <" + prefix + "> .\n"; - } - return (string.Empty.Equals(prefixes) ? string.Empty : prefixes + "\n") + output; - } + IList triples = (IList)dataset.GetQuads(localGraphName); + if ("@default".Equals(localGraphName)) + { + localGraphName = null; + } + // http://www.w3.org/TR/turtle/#unlabeled-bnodes + // TODO: implement nesting for unlabled nodes + // map of what the output should look like + // subj (or [ if bnode) > pred > obj + // > obj (set ref if IRI) + // > pred > obj (set ref if bnode) + // subj > etc etc etc + // subjid -> [ ref, ref, ref ] + string prevSubject = string.Empty; + string prevPredicate = string.Empty; + JObject thisSubject = null; + JArray thisPredicate = null; + foreach (RDFDataset.Quad triple in triples) + { + string subject = triple.GetSubject().GetValue(); + string predicate = triple.GetPredicate().GetValue(); + if (prevSubject.Equals(subject)) + { + if (prevPredicate.Equals(predicate)) + { + } + else + { + // nothing to do + // new predicate + if (thisSubject.ContainsKey(predicate)) + { + thisPredicate = (JArray)thisSubject[predicate]; + } + else + { + thisPredicate = new JArray(); + thisSubject[predicate] = thisPredicate; + } + prevPredicate = predicate; + } + } + else + { + // new subject + if (ttl.ContainsKey(subject)) + { + thisSubject = (JObject)ttl[subject]; + } + else + { + thisSubject = new JObject(); + ttl[subject] = thisSubject; + } + if (thisSubject.ContainsKey(predicate)) + { + thisPredicate = (JArray)thisSubject[predicate]; + } + else + { + thisPredicate = new JArray(); + thisSubject[predicate] = thisPredicate; + } + prevSubject = subject; + prevPredicate = predicate; + } + if (triple.GetObject().IsLiteral()) + { + thisPredicate.Add(triple.GetObject()); + } + else + { + string o = triple.GetObject().GetValue(); + if (o.StartsWith("_:")) + { + // add ref to o + if (!refs.ContainsKey(o)) + { + refs[o] = new JArray(); + } + ((JArray)refs[o]).Add(thisPredicate); + } + thisPredicate.Add(o); + } + } + } + JObject collections = new JObject(); + JArray subjects = new JArray(ttl.GetKeys()); + // find collections + foreach (string subj in subjects) + { + JObject preds = (JObject)ttl[subj]; + if (preds != null && preds.ContainsKey(JSONLDConsts.RdfFirst)) + { + JArray col = new JArray(); + collections[subj] = col; + while (true) + { + JArray first = (JArray)JsonLD.Collections.Remove(preds, JSONLDConsts.RdfFirst); + JToken o = first[0]; + col.Add(o); + // refs + if (refs.ContainsKey((string)o)) + { + ((JArray)refs[(string)o]).Remove(first); + ((JArray)refs[(string)o]).Add(col); + } + string next = (string)JsonLD.Collections.Remove(preds, JSONLDConsts.RdfRest)[0 + ]; + if (JSONLDConsts.RdfNil.Equals(next)) + { + // end of this list + break; + } + // if collections already contains a value for "next", add + // it to this col and break out + if (collections.ContainsKey(next)) + { + JsonLD.Collections.AddAll(col, (JArray)JsonLD.Collections.Remove(collections, next)); + break; + } + preds = (JObject)JsonLD.Collections.Remove(ttl, next); + JsonLD.Collections.Remove(refs, next); + } + } + } + // process refs (nesting referenced bnodes if only one reference to them + // in the whole graph) + foreach (string id in refs.GetKeys()) + { + // skip items if there is more than one reference to them in the + // graph + if (((JArray)refs[id]).Count > 1) + { + continue; + } + // otherwise embed them into the referenced location + JToken @object = JsonLD.Collections.Remove(ttl, id); + if (collections.ContainsKey(id)) + { + @object = new JObject(); + JArray tmp = new JArray(); + tmp.Add(JsonLD.Collections.Remove(collections, id)); + ((JObject)@object)[ColsKey] = tmp; + } + JArray predicate = (JArray)refs[id][0]; + // replace the one bnode ref with the object + predicate[predicate.LastIndexOf(id)] = (JToken)@object; + } + // replace the rest of the collections + foreach (string id_1 in collections.GetKeys()) + { + JObject subj_1 = (JObject)ttl[id_1]; + if (!subj_1.ContainsKey(ColsKey)) + { + subj_1[ColsKey] = new JArray(); + } + ((JArray)subj_1[ColsKey]).Add(collections[id_1]); + } + // build turtle output + string output = GenerateTurtle(ttl, 0, 0, false); + string prefixes = string.Empty; + foreach (string prefix in usedNamespaces) + { + string name = availableNamespaces[prefix]; + prefixes += "@prefix " + name + ": <" + prefix + "> .\n"; + } + return (string.Empty.Equals(prefixes) ? string.Empty : prefixes + "\n") + output; + } - private string GenerateObject(object @object, string sep, bool hasNext, int indentation - , int lineLength) - { - string rval = string.Empty; - string obj; - if (@object is string) - { - obj = GetURI((string)@object); - } - else - { - if (@object is RDFDataset.Literal) - { - obj = ((RDFDataset.Literal)@object).GetValue(); - string lang = ((RDFDataset.Literal)@object).GetLanguage(); - string dt = ((RDFDataset.Literal)@object).GetDatatype(); - if (lang != null) - { - obj = "\"" + obj + "\""; - obj += "@" + lang; - } - else - { - if (dt != null) - { - // TODO: this probably isn't an exclusive list of all the - // datatype literals that can be represented as native types - if (!(JSONLDConsts.XsdDouble.Equals(dt) || JSONLDConsts.XsdInteger.Equals(dt) || - JSONLDConsts.XsdFloat.Equals(dt) || JSONLDConsts.XsdBoolean.Equals(dt))) - { - obj = "\"" + obj + "\""; - if (!JSONLDConsts.XsdString.Equals(dt)) - { - obj += "^^" + GetURI(dt); - } - } - } - else - { - obj = "\"" + obj + "\""; - } - } - } - else - { - // must be an object - JObject tmp = new JObject(); - tmp["_:x"] = (JObject)@object; - obj = GenerateTurtle(tmp, indentation + 1, lineLength, true); - } - } - int idxofcr = obj.IndexOf("\n"); - // check if output will fix in the max line length (factor in comma if - // not the last item, current line length and length to the next CR) - if ((hasNext ? 1 : 0) + lineLength + (idxofcr != -1 ? idxofcr : obj.Length) > MaxLineLength) - { - rval += "\n" + Tabs(indentation + 1); - lineLength = (indentation + 1) * TabSpaces; - } - rval += obj; - if (idxofcr != -1) - { - lineLength += (obj.Length - obj.LastIndexOf("\n")); - } - else - { - lineLength += obj.Length; - } - if (hasNext) - { - rval += sep; - lineLength += sep.Length; - if (lineLength < MaxLineLength) - { - rval += " "; - lineLength++; - } - else - { - rval += "\n"; - } - } - return rval; - } + private string GenerateObject(object @object, string sep, bool hasNext, int indentation + , int lineLength) + { + string rval = string.Empty; + string obj; + if (@object is string) + { + obj = GetURI((string)@object); + } + else + { + if (@object is RDFDataset.Literal) + { + obj = ((RDFDataset.Literal)@object).GetValue(); + string lang = ((RDFDataset.Literal)@object).GetLanguage(); + string dt = ((RDFDataset.Literal)@object).GetDatatype(); + if (lang != null) + { + obj = "\"" + obj + "\""; + obj += "@" + lang; + } + else + { + if (dt != null) + { + // TODO: this probably isn't an exclusive list of all the + // datatype literals that can be represented as native types + if (!(JSONLDConsts.XsdDouble.Equals(dt) || JSONLDConsts.XsdInteger.Equals(dt) || + JSONLDConsts.XsdFloat.Equals(dt) || JSONLDConsts.XsdBoolean.Equals(dt))) + { + obj = "\"" + obj + "\""; + if (!JSONLDConsts.XsdString.Equals(dt)) + { + obj += "^^" + GetURI(dt); + } + } + } + else + { + obj = "\"" + obj + "\""; + } + } + } + else + { + // must be an object + JObject tmp = new JObject(); + tmp["_:x"] = (JObject)@object; + obj = GenerateTurtle(tmp, indentation + 1, lineLength, true); + } + } + int idxofcr = obj.IndexOf("\n"); + // check if output will fix in the max line length (factor in comma if + // not the last item, current line length and length to the next CR) + if ((hasNext ? 1 : 0) + lineLength + (idxofcr != -1 ? idxofcr : obj.Length) > MaxLineLength) + { + rval += "\n" + Tabs(indentation + 1); + lineLength = (indentation + 1) * TabSpaces; + } + rval += obj; + if (idxofcr != -1) + { + lineLength += (obj.Length - obj.LastIndexOf("\n")); + } + else + { + lineLength += obj.Length; + } + if (hasNext) + { + rval += sep; + lineLength += sep.Length; + if (lineLength < MaxLineLength) + { + rval += " "; + lineLength++; + } + else + { + rval += "\n"; + } + } + return rval; + } - private string GenerateTurtle(JObject ttl, int indentation, int lineLength, bool isObject) - { - string rval = string.Empty; - IEnumerator subjIter = ttl.GetKeys().GetEnumerator(); - while (subjIter.MoveNext()) - { - string subject = subjIter.Current; - JObject subjval = (JObject)ttl[subject]; - // boolean isBlankNode = subject.startsWith("_:"); - bool hasOpenBnodeBracket = false; - if (subject.StartsWith("_:")) - { - // only open blank node bracket the node doesn't contain any - // collections - if (!subjval.ContainsKey(ColsKey)) - { - rval += "[ "; - lineLength += 2; - hasOpenBnodeBracket = true; - } - // TODO: according to http://www.rdfabout.com/demo/validator/ - // 1) collections as objects cannot contain any predicates other - // than rdf:first and rdf:rest - // 2) collections cannot be surrounded with [ ] - // check for collection - if (subjval.ContainsKey(ColsKey)) - { - JArray collections = (JArray)JsonLD.Collections.Remove(subjval, ColsKey); - foreach (JToken collection in collections) - { - rval += "( "; - lineLength += 2; + private string GenerateTurtle(JObject ttl, int indentation, int lineLength, bool isObject) + { + string rval = string.Empty; + IEnumerator subjIter = ttl.GetKeys().GetEnumerator(); + while (subjIter.MoveNext()) + { + string subject = subjIter.Current; + JObject subjval = (JObject)ttl[subject]; + // boolean isBlankNode = subject.startsWith("_:"); + bool hasOpenBnodeBracket = false; + if (subject.StartsWith("_:")) + { + // only open blank node bracket the node doesn't contain any + // collections + if (!subjval.ContainsKey(ColsKey)) + { + rval += "[ "; + lineLength += 2; + hasOpenBnodeBracket = true; + } + // TODO: according to http://www.rdfabout.com/demo/validator/ + // 1) collections as objects cannot contain any predicates other + // than rdf:first and rdf:rest + // 2) collections cannot be surrounded with [ ] + // check for collection + if (subjval.ContainsKey(ColsKey)) + { + JArray collections = (JArray)JsonLD.Collections.Remove(subjval, ColsKey); + foreach (JToken collection in collections) + { + rval += "( "; + lineLength += 2; IEnumerator objIter = ((JArray)collection).Children().GetEnumerator(); - while (objIter.MoveNext()) - { - JToken @object = objIter.Current; - rval += GenerateObject(@object, string.Empty, objIter.MoveNext(), indentation, lineLength - ); - lineLength = rval.Length - rval.LastIndexOf("\n"); - } - rval += " ) "; - lineLength += 3; - } - } - } - else - { - // check for blank node - rval += GetURI(subject) + " "; - lineLength += subject.Length + 1; - } - IEnumerator predIter = ttl[subject].GetKeys().GetEnumerator(); - while (predIter.MoveNext()) - { - string predicate = predIter.Current; - rval += GetURI(predicate) + " "; - lineLength += predicate.Length + 1; - IEnumerator objIter = ((JArray)ttl[subject][predicate]).Children().GetEnumerator(); - while (objIter.MoveNext()) - { - JToken @object = objIter.Current; - rval += GenerateObject(@object, ",", objIter.MoveNext(), indentation, lineLength); - lineLength = rval.Length - rval.LastIndexOf("\n"); - } - if (predIter.MoveNext()) - { - rval += " ;\n" + Tabs(indentation + 1); - lineLength = (indentation + 1) * TabSpaces; - } - } - if (hasOpenBnodeBracket) - { - rval += " ]"; - } - if (!isObject) - { - rval += " .\n"; - if (subjIter.MoveNext()) - { - // add blank space if we have another - // object below this - rval += "\n"; - } - } - } - return rval; - } + while (objIter.MoveNext()) + { + JToken @object = objIter.Current; + rval += GenerateObject(@object, string.Empty, objIter.MoveNext(), indentation, lineLength + ); + lineLength = rval.Length - rval.LastIndexOf("\n"); + } + rval += " ) "; + lineLength += 3; + } + } + } + else + { + // check for blank node + rval += GetURI(subject) + " "; + lineLength += subject.Length + 1; + } + IEnumerator predIter = ttl[subject].GetKeys().GetEnumerator(); + while (predIter.MoveNext()) + { + string predicate = predIter.Current; + rval += GetURI(predicate) + " "; + lineLength += predicate.Length + 1; + IEnumerator objIter = ((JArray)ttl[subject][predicate]).Children().GetEnumerator(); + while (objIter.MoveNext()) + { + JToken @object = objIter.Current; + rval += GenerateObject(@object, ",", objIter.MoveNext(), indentation, lineLength); + lineLength = rval.Length - rval.LastIndexOf("\n"); + } + if (predIter.MoveNext()) + { + rval += " ;\n" + Tabs(indentation + 1); + lineLength = (indentation + 1) * TabSpaces; + } + } + if (hasOpenBnodeBracket) + { + rval += " ]"; + } + if (!isObject) + { + rval += " .\n"; + if (subjIter.MoveNext()) + { + // add blank space if we have another + // object below this + rval += "\n"; + } + } + } + return rval; + } - // TODO: Assert (TAB_SPACES == 4) otherwise this needs to be edited, and - // should fail to compile - private string Tabs(int tabs) - { - string rval = string.Empty; - for (int i = 0; i < tabs; i++) - { - rval += " "; - } - // using spaces for tabs - return rval; - } + // TODO: Assert (TAB_SPACES == 4) otherwise this needs to be edited, and + // should fail to compile + private string Tabs(int tabs) + { + string rval = string.Empty; + for (int i = 0; i < tabs; i++) + { + rval += " "; + } + // using spaces for tabs + return rval; + } - /// - /// checks the URI for a prefix, and if one is found, set used prefixes to - /// true - /// - /// - /// - private string GetURI(string uri) - { - // check for bnode - if (uri.StartsWith("_:")) - { - // return the bnode id - return uri; - } - foreach (string prefix in availableNamespaces.Keys) - { - if (uri.StartsWith(prefix)) - { - usedNamespaces.Add(prefix); - // return the prefixed URI - return availableNamespaces[prefix] + ":" + JsonLD.JavaCompat.Substring(uri, prefix. - Length); - } - } - // return the full URI - return "<" + uri + ">"; - } - } + /// + /// checks the URI for a prefix, and if one is found, set used prefixes to + /// true + /// + /// + /// + private string GetURI(string uri) + { + // check for bnode + if (uri.StartsWith("_:")) + { + // return the bnode id + return uri; + } + foreach (string prefix in availableNamespaces.Keys) + { + if (uri.StartsWith(prefix)) + { + usedNamespaces.Add(prefix); + // return the prefixed URI + return availableNamespaces[prefix] + ":" + JsonLD.JavaCompat.Substring(uri, prefix. + Length); + } + } + // return the full URI + return "<" + uri + ">"; + } + } } diff --git a/src/JsonLD/Util/JSONUtils.cs b/src/JsonLD/Util/JSONUtils.cs index df8947c..4989451 100644 --- a/src/JsonLD/Util/JSONUtils.cs +++ b/src/JsonLD/Util/JSONUtils.cs @@ -8,42 +8,42 @@ namespace JsonLD.Util { - /// A bunch of functions to make loading JSON easy - /// tristan - public class JSONUtils - { - /// An HTTP Accept header that prefers JSONLD. - /// An HTTP Accept header that prefers JSONLD. - protected internal const string AcceptHeader = "application/ld+json, application/json;q=0.9, application/javascript;q=0.5, text/javascript;q=0.5, text/plain;q=0.2, */*;q=0.1"; + /// A bunch of functions to make loading JSON easy + /// tristan + public class JSONUtils + { + /// An HTTP Accept header that prefers JSONLD. + /// An HTTP Accept header that prefers JSONLD. + protected internal const string AcceptHeader = "application/ld+json, application/json;q=0.9, application/javascript;q=0.5, text/javascript;q=0.5, text/plain;q=0.2, */*;q=0.1"; - //private static readonly ObjectMapper JsonMapper = new ObjectMapper(); + //private static readonly ObjectMapper JsonMapper = new ObjectMapper(); - //private static readonly JsonFactory JsonFactory = new JsonFactory(JsonMapper); + //private static readonly JsonFactory JsonFactory = new JsonFactory(JsonMapper); - static JSONUtils() - { - // Disable default Jackson behaviour to close - // InputStreams/Readers/OutputStreams/Writers - //JsonFactory.Disable(JsonGenerator.Feature.AutoCloseTarget); - // Disable string retention features that may work for most JSON where - // the field names are in limited supply, but does not work for JSON-LD - // where a wide range of URIs are used for subjects and predicates - //JsonFactory.Disable(JsonFactory.Feature.InternFieldNames); - //JsonFactory.Disable(JsonFactory.Feature.CanonicalizeFieldNames); - } + static JSONUtils() + { + // Disable default Jackson behaviour to close + // InputStreams/Readers/OutputStreams/Writers + //JsonFactory.Disable(JsonGenerator.Feature.AutoCloseTarget); + // Disable string retention features that may work for most JSON where + // the field names are in limited supply, but does not work for JSON-LD + // where a wide range of URIs are used for subjects and predicates + //JsonFactory.Disable(JsonFactory.Feature.InternFieldNames); + //JsonFactory.Disable(JsonFactory.Feature.CanonicalizeFieldNames); + } - // private static volatile IHttpClient httpClient; + // private static volatile IHttpClient httpClient; - /// - /// - public static JToken FromString(string jsonString) - { - return FromReader(new StringReader(jsonString)); - } + /// + /// + public static JToken FromString(string jsonString) + { + return FromReader(new StringReader(jsonString)); + } - /// + /// public static JToken FromReader(TextReader r) - { + { var serializer = new JsonSerializer(); using (var reader = new JsonTextReader(r)) @@ -51,12 +51,12 @@ public static JToken FromReader(TextReader r) var result = (JToken)serializer.Deserialize(reader); return result; } - } + } - /// - /// - public static void Write(TextWriter w, JToken jsonObject) - { + /// + /// + public static void Write(TextWriter w, JToken jsonObject) + { var serializer = new JsonSerializer(); using (var writer = new JsonTextWriter(w)) { @@ -64,10 +64,10 @@ public static void Write(TextWriter w, JToken jsonObject) } } - /// - /// + /// + /// public static void WritePrettyPrint(TextWriter w, JToken jsonObject) - { + { var serializer = new JsonSerializer(); using (var writer = new JsonTextWriter(w)) { @@ -76,79 +76,79 @@ public static void WritePrettyPrint(TextWriter w, JToken jsonObject) } } - /// + /// public static JToken FromInputStream(Stream content) - { - return FromInputStream(content, "UTF-8"); - } + { + return FromInputStream(content, "UTF-8"); + } - // no readers from - // inputstreams w.o. - // encoding!! - /// + // no readers from + // inputstreams w.o. + // encoding!! + /// public static JToken FromInputStream(Stream content, string enc) - { + { return FromReader(new StreamReader(content, System.Text.Encoding.GetEncoding(enc))); - } + } public static string ToPrettyString(JToken obj) - { - StringWriter sw = new StringWriter(); - try - { - WritePrettyPrint(sw, obj); - } - catch - { - // TODO Is this really possible with stringwriter? - // I think it's only there because of the interface - // however, if so... well, we have to do something! - // it seems weird for toString to throw an IOException + { + StringWriter sw = new StringWriter(); + try + { + WritePrettyPrint(sw, obj); + } + catch + { + // TODO Is this really possible with stringwriter? + // I think it's only there because of the interface + // however, if so... well, we have to do something! + // it seems weird for toString to throw an IOException throw; - } - return sw.ToString(); - } + } + return sw.ToString(); + } public static string ToString(JToken obj) - { - // throws - // JsonGenerationException, - // JsonMappingException { - StringWriter sw = new StringWriter(); - try - { - Write(sw, obj); - } - catch - { - // TODO Is this really possible with stringwriter? - // I think it's only there because of the interface - // however, if so... well, we have to do something! - // it seems weird for toString to throw an IOException + { + // throws + // JsonGenerationException, + // JsonMappingException { + StringWriter sw = new StringWriter(); + try + { + Write(sw, obj); + } + catch + { + // TODO Is this really possible with stringwriter? + // I think it's only there because of the interface + // however, if so... well, we have to do something! + // it seems weird for toString to throw an IOException throw; - } - return sw.ToString(); - } + } + return sw.ToString(); + } - /// - /// Returns a Map, List, or String containing the contents of the JSON - /// resource resolved from the URL. - /// - /// - /// Returns a Map, List, or String containing the contents of the JSON - /// resource resolved from the URL. - /// - /// The URL to resolve - /// - /// The Map, List, or String that represent the JSON resource - /// resolved from the URL - /// - /// If the JSON was not valid. - /// - /// If there was an error resolving the resource. - /// + /// + /// Returns a Map, List, or String containing the contents of the JSON + /// resource resolved from the URL. + /// + /// + /// Returns a Map, List, or String containing the contents of the JSON + /// resource resolved from the URL. + /// + /// The URL to resolve + /// + /// The Map, List, or String that represent the JSON resource + /// resolved from the URL + /// + /// If the JSON was not valid. + /// + /// If there was an error resolving the resource. + /// public static JToken FromURL(Uri url) - { + { #if !PORTABLE HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url); req.Accept = AcceptHeader; @@ -156,8 +156,8 @@ public static JToken FromURL(Uri url) Stream stream = resp.GetResponseStream(); return FromInputStream(stream); #else - throw new NotImplementedException(); + throw new PlatformNotSupportedException(); #endif - } - } + } + } } diff --git a/src/JsonLD/Util/JavaCompat.cs b/src/JsonLD/Util/JavaCompat.cs index b74b23d..3489301 100644 --- a/src/JsonLD/Util/JavaCompat.cs +++ b/src/JsonLD/Util/JavaCompat.cs @@ -282,7 +282,7 @@ public string GetPattern() #if !PORTABLE return this.pattern; #else - throw new NotImplementedException(); + throw new PlatformNotSupportedException(); #endif } diff --git a/src/JsonLD/Util/Obj.cs b/src/JsonLD/Util/Obj.cs index 9bb079e..9425b79 100644 --- a/src/JsonLD/Util/Obj.cs +++ b/src/JsonLD/Util/Obj.cs @@ -4,90 +4,90 @@ namespace JsonLD.Util { - public class Obj - { - /// - /// Used to make getting values from maps embedded in maps embedded in maps - /// easier TODO: roll out the loops for efficiency - /// - /// - /// - /// - public static object Get(JToken map, params string[] keys) - { - foreach (string key in keys) - { - map = ((IDictionary)map)[key]; - // make sure we don't crash if we get a null somewhere down the line - if (map == null) - { - return map; - } - } - return map; - } + public class Obj + { + /// + /// Used to make getting values from maps embedded in maps embedded in maps + /// easier TODO: roll out the loops for efficiency + /// + /// + /// + /// + public static object Get(JToken map, params string[] keys) + { + foreach (string key in keys) + { + map = ((IDictionary)map)[key]; + // make sure we don't crash if we get a null somewhere down the line + if (map == null) + { + return map; + } + } + return map; + } - public static object Put(object map, string key1, object value) - { - ((IDictionary)map)[key1] = value; - return map; - } + public static object Put(object map, string key1, object value) + { + ((IDictionary)map)[key1] = value; + return map; + } - public static object Put(object map, string key1, string key2, object value) - { - ((IDictionary)((IDictionary)map)[key1])[key2] = value; - return map; - } + public static object Put(object map, string key1, string key2, object value) + { + ((IDictionary)((IDictionary)map)[key1])[key2] = value; + return map; + } - public static object Put(object map, string key1, string key2, string key3, object - value) - { - ((IDictionary)((IDictionary)((IDictionary)map)[key1])[key2])[key3] = value; - return map; - } + public static object Put(object map, string key1, string key2, string key3, object + value) + { + ((IDictionary)((IDictionary)((IDictionary)map)[key1])[key2])[key3] = value; + return map; + } - public static object Put(object map, string key1, string key2, string key3, string - key4, object value) - { - ((IDictionary)((IDictionary)((IDictionary)((IDictionary)map)[key1])[key2])[key3])[key4] = value; - return map; - } + public static object Put(object map, string key1, string key2, string key3, string + key4, object value) + { + ((IDictionary)((IDictionary)((IDictionary)((IDictionary)map)[key1])[key2])[key3])[key4] = value; + return map; + } - public static bool Contains(object map, params string[] keys) - { - foreach (string key in keys) - { - map = ((IDictionary)map)[key]; - if (map == null) - { - return false; - } - } - return true; - } + public static bool Contains(object map, params string[] keys) + { + foreach (string key in keys) + { + map = ((IDictionary)map)[key]; + if (map == null) + { + return false; + } + } + return true; + } - public static object Remove(object map, string k1, string k2) - { - return JsonLD.Collections.Remove(((IDictionary)((IDictionary)map)[k1]), k2); - } + public static object Remove(object map, string k1, string k2) + { + return JsonLD.Collections.Remove(((IDictionary)((IDictionary)map)[k1]), k2); + } - /// A null-safe equals check using v1.equals(v2) if they are both not null. - /// A null-safe equals check using v1.equals(v2) if they are both not null. - /// The source object for the equals check. - /// - /// The object to be checked for equality using the first objects - /// equals method. - /// - /// - /// True if the objects were both null. True if both objects were not - /// null and v1.equals(v2). False otherwise. - /// - public static bool Equals(object v1, object v2) - { - return v1 == null ? v2 == null : v1.Equals(v2); - } - } + /// A null-safe equals check using v1.equals(v2) if they are both not null. + /// A null-safe equals check using v1.equals(v2) if they are both not null. + /// The source object for the equals check. + /// + /// The object to be checked for equality using the first objects + /// equals method. + /// + /// + /// True if the objects were both null. True if both objects were not + /// null and v1.equals(v2). False otherwise. + /// + public static bool Equals(object v1, object v2) + { + return v1 == null ? v2 == null : v1.Equals(v2); + } + } }