diff --git a/NuGet.config b/NuGet.config
deleted file mode 100644
index 9ce5681d..00000000
--- a/NuGet.config
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Schema.NET.sln b/Schema.NET.sln
index 48d4fcb2..cbda0f49 100644
--- a/Schema.NET.sln
+++ b/Schema.NET.sln
@@ -15,7 +15,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
build.cake = build.cake
Key.snk = Key.snk
MinimumRecommendedRulesWithStyleCop.ruleset = MinimumRecommendedRulesWithStyleCop.ruleset
- NuGet.config = NuGet.config
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Schema.NET.Tool", "Source\Schema.NET.Tool\Schema.NET.Tool.csproj", "{3CED3D1A-AB36-4B39-86DC-910BF8237DE9}"
diff --git a/Source/Schema.NET/ContextJsonConverter.cs b/Source/Schema.NET/ContextJsonConverter.cs
new file mode 100644
index 00000000..24c03075
--- /dev/null
+++ b/Source/Schema.NET/ContextJsonConverter.cs
@@ -0,0 +1,59 @@
+namespace Schema.NET
+{
+ using System;
+ using Newtonsoft.Json;
+ using Newtonsoft.Json.Linq;
+
+ ///
+ /// Converts a object to and from JSON.
+ ///
+ ///
+ public class ContextJsonConverter : JsonConverter
+ {
+ ///
+ public override JsonLdContext ReadJson(JsonReader reader, Type objectType, JsonLdContext existingValue, bool hasExistingValue, JsonSerializer serializer)
+ {
+ var context = hasExistingValue ? existingValue : new JsonLdContext();
+
+ string name;
+ string language;
+ if (reader.TokenType == JsonToken.String)
+ {
+ name = (string)reader.Value;
+ language = null;
+ }
+ else
+ {
+ var o = JObject.Load(reader);
+
+ var nameProperty = o.Property("name", StringComparison.OrdinalIgnoreCase);
+ name = nameProperty?.Value?.ToString() ?? "http://schema.org";
+
+ var languageProperty = o.Property("@language", StringComparison.OrdinalIgnoreCase);
+ language = languageProperty?.Value?.ToString();
+ }
+
+ context.Name = name;
+ context.Language = language;
+ return context;
+ }
+
+ ///
+ public override void WriteJson(JsonWriter writer, JsonLdContext value, JsonSerializer serializer)
+ {
+ if (string.IsNullOrWhiteSpace(value.Language))
+ {
+ writer.WriteValue(value.Name);
+ }
+ else
+ {
+ writer.WriteStartObject();
+ writer.WritePropertyName("name");
+ writer.WriteValue(value.Name);
+ writer.WritePropertyName("@language");
+ writer.WriteValue(value.Language);
+ writer.WriteEndObject();
+ }
+ }
+ }
+}
diff --git a/Source/Schema.NET/JsonLdContext.cs b/Source/Schema.NET/JsonLdContext.cs
new file mode 100644
index 00000000..2405d0d4
--- /dev/null
+++ b/Source/Schema.NET/JsonLdContext.cs
@@ -0,0 +1,77 @@
+namespace Schema.NET
+{
+ using System;
+ using System.Runtime.Serialization;
+
+ ///
+ /// The @context for a JSON-LD document.
+ /// See https://w3c.github.io/json-ld-syntax
+ ///
+ public class JsonLdContext : IEquatable
+ {
+ ///
+ /// Gets or sets the name.
+ ///
+ [DataMember(Name = "name", Order = 0)]
+ public string Name { get; set; } = "http://schema.org";
+
+ ///
+ /// Gets or sets the language.
+ ///
+ [DataMember(Name = "@language", Order = 1)]
+ public string Language { get; set; }
+
+ ///
+ /// Performs an implicit conversion from to .
+ ///
+ /// The context.
+ /// The result of the conversion.
+ public static implicit operator string(JsonLdContext context) => context.Name;
+
+ ///
+ /// Implements the operator ==.
+ ///
+ /// The left.
+ /// The right.
+ ///
+ /// The result of the operator.
+ ///
+ public static bool operator ==(JsonLdContext left, JsonLdContext right) => left.Equals(right);
+
+ ///
+ /// Implements the operator !=.
+ ///
+ /// The left.
+ /// The right.
+ ///
+ /// The result of the operator.
+ ///
+ public static bool operator !=(JsonLdContext left, JsonLdContext right) => !(left == right);
+
+ ///
+ public bool Equals(JsonLdContext other)
+ {
+ if (other is null)
+ {
+ return false;
+ }
+
+ if (object.ReferenceEquals(this, other))
+ {
+ return true;
+ }
+
+ return this.Name == other.Name &&
+ this.Language == other.Language;
+ }
+
+ ///
+ public override bool Equals(object obj) => this.Equals(obj as JsonLdContext);
+
+ ///
+ public override int GetHashCode() => HashCode.Of(this.Name).And(this.Language);
+
+ ///
+ public override string ToString() => this.Name;
+ }
+}
diff --git a/Source/Schema.NET/JsonLdObject.cs b/Source/Schema.NET/JsonLdObject.cs
index f467ae0b..a3731c71 100644
--- a/Source/Schema.NET/JsonLdObject.cs
+++ b/Source/Schema.NET/JsonLdObject.cs
@@ -1,17 +1,18 @@
-namespace Schema.NET
+namespace Schema.NET
{
using System;
- using System.Runtime.Serialization;
-
+ using System.Runtime.Serialization;
+ using Newtonsoft.Json;
+
///
- /// The base object
+ /// The base JSON-LD object.
/// See https://json-ld.org/spec/latest/json-ld
///
[DataContract]
public class JsonLdObject
{
///
- /// Gets or sets the context used to define the short-hand names that are used throughout a JSON-LD document.
+ /// Gets the context used to define the short-hand names that are used throughout a JSON-LD document.
/// These short-hand names are called terms and help developers to express specific identifiers in a compact
/// manner.
/// When two people communicate with one another, the conversation takes place in a shared environment,
@@ -22,8 +23,16 @@ public class JsonLdObject
/// Simply speaking, a context is used to map terms to IRIs. Terms are case sensitive and any valid string that
/// is not a reserved JSON-LD keyword can be used as a term.
///
- [DataMember(Name = "@context", Order = 0)]
- public virtual string Context { get; }
+ [DataMember(Name = "@context", Order = 0)]
+ [JsonConverter(typeof(ContextJsonConverter))]
+ public virtual JsonLdContext Context { get; internal set; } = new JsonLdContext();
+
+ ///
+ /// Gets or sets the type, used to uniquely identify things that are being described in the document with IRIs
+ /// or blank node identifiers.
+ ///
+ [DataMember(Name = "@type", Order = 1)]
+ public virtual string Type { get; }
///
/// Gets or sets the identifier used to uniquely identify things that are being described in the document with
@@ -35,12 +44,5 @@ public class JsonLdObject
///
[DataMember(Name = "@id", Order = 2)]
public virtual Uri Id { get; set; }
-
- ///
- /// Gets or sets the type, used to uniquely identify things that are being described in the document with IRIs
- /// or blank node identifiers.
- ///
- [DataMember(Name = "@type", Order = 1)]
- public virtual string Type { get; }
}
}
diff --git a/Source/Schema.NET/Schema.NET.csproj b/Source/Schema.NET/Schema.NET.csproj
index 629552fe..c01f555f 100644
--- a/Source/Schema.NET/Schema.NET.csproj
+++ b/Source/Schema.NET/Schema.NET.csproj
@@ -43,7 +43,7 @@
-
+
diff --git a/Source/Schema.NET/ValuesJsonConverter.cs b/Source/Schema.NET/ValuesJsonConverter.cs
index 16f98d81..03925732 100644
--- a/Source/Schema.NET/ValuesJsonConverter.cs
+++ b/Source/Schema.NET/ValuesJsonConverter.cs
@@ -10,7 +10,7 @@ namespace Schema.NET
using Newtonsoft.Json.Linq;
///
- /// Converts a object to JSON.
+ /// Converts a object to and from JSON.
///
///
public class ValuesJsonConverter : JsonConverter
diff --git a/Source/Schema.NET/core/Thing.cs b/Source/Schema.NET/core/Thing.cs
index c1cd0ac4..f0ecfd6f 100644
--- a/Source/Schema.NET/core/Thing.cs
+++ b/Source/Schema.NET/core/Thing.cs
@@ -1,4 +1,4 @@
-namespace Schema.NET
+namespace Schema.NET
{
using System;
using System.Runtime.Serialization;
@@ -76,12 +76,6 @@ public partial interface IThing
[DataContract]
public partial class Thing : IThing
{
- ///
- /// Gets the context for the object, specifying that it comes from schema.org.
- ///
- [DataMember(Name = "@context", Order = 0)]
- public override string Context => "http://schema.org";
-
///
/// Gets the name of the type as specified by schema.org.
///
diff --git a/Tests/Schema.NET.Test/ContextJsonConverterTest.cs b/Tests/Schema.NET.Test/ContextJsonConverterTest.cs
new file mode 100644
index 00000000..80aea47c
--- /dev/null
+++ b/Tests/Schema.NET.Test/ContextJsonConverterTest.cs
@@ -0,0 +1,63 @@
+namespace Schema.NET.Test
+{
+ using Newtonsoft.Json;
+ using Xunit;
+
+ public class ContextJsonConverterTest
+ {
+ [Fact]
+ public void ReadJson_StringContext_ContextHasName()
+ {
+ var json = "{\"@context\":\"foo\",\"@type\":\"Thing\"}";
+
+ var thing = JsonConvert.DeserializeObject(json);
+
+ Assert.NotNull(thing.Context);
+ Assert.Equal("foo", thing.Context.Name);
+ Assert.Null(thing.Context.Language);
+ }
+
+ [Fact]
+ public void ReadJson_ObjectContextWithName_ContextHasName()
+ {
+ var json = "{\"@context\":{\"name\":\"foo\"},\"@type\":\"Thing\"}";
+
+ var thing = JsonConvert.DeserializeObject(json);
+
+ Assert.NotNull(thing.Context);
+ Assert.Equal("foo", thing.Context.Name);
+ Assert.Null(thing.Context.Language);
+ }
+
+ [Fact]
+ public void ReadJson_ObjectContextWithNameAndLanguage_ContextHasNameAndLanguage()
+ {
+ var json = "{\"@context\":{\"name\":\"foo\",\"@language\":\"en\"},\"@type\":\"Thing\"}";
+
+ var thing = JsonConvert.DeserializeObject(json);
+
+ Assert.NotNull(thing.Context);
+ Assert.Equal("foo", thing.Context.Name);
+ Assert.Equal("en", thing.Context.Language);
+ }
+
+ [Fact]
+ public void WriteJson_StringContext_ContextHasName()
+ {
+ var json = new Thing().ToString();
+
+ Assert.Equal("{\"@context\":\"http://schema.org\",\"@type\":\"Thing\"}", json);
+ }
+
+ [Fact]
+ public void WriteJson_ObjectContextWithLanguage_ContextHasName()
+ {
+ var thing = new Thing();
+ thing.Context.Language = "en";
+
+ var json = thing.ToString();
+
+ Assert.Equal("{\"@context\":{\"name\":\"http://schema.org\",\"@language\":\"en\"},\"@type\":\"Thing\"}", json);
+ }
+ }
+}
diff --git a/Tests/Schema.NET.Test/JsonLdContextTest.cs b/Tests/Schema.NET.Test/JsonLdContextTest.cs
new file mode 100644
index 00000000..8d072de1
--- /dev/null
+++ b/Tests/Schema.NET.Test/JsonLdContextTest.cs
@@ -0,0 +1,67 @@
+namespace Schema.NET.Test
+{
+ using System.Collections.Generic;
+ using Xunit;
+
+ public class JsonLdContextTest
+ {
+ public static IEnumerable