Skip to content

Commit f2ad80b

Browse files
authored
Merge pull request #70 from RehanSaeed/add-context-object
Add JsonLdContext and it's JsonConverter
2 parents b35806f + 6a4128f commit f2ad80b

File tree

10 files changed

+285
-30
lines changed

10 files changed

+285
-30
lines changed

NuGet.config

Lines changed: 0 additions & 6 deletions
This file was deleted.

Schema.NET.sln

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
1515
build.cake = build.cake
1616
Key.snk = Key.snk
1717
MinimumRecommendedRulesWithStyleCop.ruleset = MinimumRecommendedRulesWithStyleCop.ruleset
18-
NuGet.config = NuGet.config
1918
EndProjectSection
2019
EndProject
2120
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Schema.NET.Tool", "Source\Schema.NET.Tool\Schema.NET.Tool.csproj", "{3CED3D1A-AB36-4B39-86DC-910BF8237DE9}"
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
namespace Schema.NET
2+
{
3+
using System;
4+
using Newtonsoft.Json;
5+
using Newtonsoft.Json.Linq;
6+
7+
/// <summary>
8+
/// Converts a <see cref="JsonLdContext"/> object to and from JSON.
9+
/// </summary>
10+
/// <seealso cref="Newtonsoft.Json.JsonConverter" />
11+
public class ContextJsonConverter : JsonConverter<JsonLdContext>
12+
{
13+
/// <inheritdoc />
14+
public override JsonLdContext ReadJson(JsonReader reader, Type objectType, JsonLdContext existingValue, bool hasExistingValue, JsonSerializer serializer)
15+
{
16+
var context = hasExistingValue ? existingValue : new JsonLdContext();
17+
18+
string name;
19+
string language;
20+
if (reader.TokenType == JsonToken.String)
21+
{
22+
name = (string)reader.Value;
23+
language = null;
24+
}
25+
else
26+
{
27+
var o = JObject.Load(reader);
28+
29+
var nameProperty = o.Property("name", StringComparison.OrdinalIgnoreCase);
30+
name = nameProperty?.Value?.ToString() ?? "http://schema.org";
31+
32+
var languageProperty = o.Property("@language", StringComparison.OrdinalIgnoreCase);
33+
language = languageProperty?.Value?.ToString();
34+
}
35+
36+
context.Name = name;
37+
context.Language = language;
38+
return context;
39+
}
40+
41+
/// <inheritdoc />
42+
public override void WriteJson(JsonWriter writer, JsonLdContext value, JsonSerializer serializer)
43+
{
44+
if (string.IsNullOrWhiteSpace(value.Language))
45+
{
46+
writer.WriteValue(value.Name);
47+
}
48+
else
49+
{
50+
writer.WriteStartObject();
51+
writer.WritePropertyName("name");
52+
writer.WriteValue(value.Name);
53+
writer.WritePropertyName("@language");
54+
writer.WriteValue(value.Language);
55+
writer.WriteEndObject();
56+
}
57+
}
58+
}
59+
}

Source/Schema.NET/JsonLdContext.cs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
namespace Schema.NET
2+
{
3+
using System;
4+
using System.Runtime.Serialization;
5+
6+
/// <summary>
7+
/// The @context for a JSON-LD document.
8+
/// See https://w3c.github.io/json-ld-syntax
9+
/// </summary>
10+
public class JsonLdContext : IEquatable<JsonLdContext>
11+
{
12+
/// <summary>
13+
/// Gets or sets the name.
14+
/// </summary>
15+
[DataMember(Name = "name", Order = 0)]
16+
public string Name { get; set; } = "http://schema.org";
17+
18+
/// <summary>
19+
/// Gets or sets the language.
20+
/// </summary>
21+
[DataMember(Name = "@language", Order = 1)]
22+
public string Language { get; set; }
23+
24+
/// <summary>
25+
/// Performs an implicit conversion from <see cref="JsonLdContext"/> to <see cref="string"/>.
26+
/// </summary>
27+
/// <param name="context">The context.</param>
28+
/// <returns>The result of the conversion.</returns>
29+
public static implicit operator string(JsonLdContext context) => context.Name;
30+
31+
/// <summary>
32+
/// Implements the operator ==.
33+
/// </summary>
34+
/// <param name="left">The left.</param>
35+
/// <param name="right">The right.</param>
36+
/// <returns>
37+
/// The result of the operator.
38+
/// </returns>
39+
public static bool operator ==(JsonLdContext left, JsonLdContext right) => left.Equals(right);
40+
41+
/// <summary>
42+
/// Implements the operator !=.
43+
/// </summary>
44+
/// <param name="left">The left.</param>
45+
/// <param name="right">The right.</param>
46+
/// <returns>
47+
/// The result of the operator.
48+
/// </returns>
49+
public static bool operator !=(JsonLdContext left, JsonLdContext right) => !(left == right);
50+
51+
/// <inheritdoc />
52+
public bool Equals(JsonLdContext other)
53+
{
54+
if (other is null)
55+
{
56+
return false;
57+
}
58+
59+
if (object.ReferenceEquals(this, other))
60+
{
61+
return true;
62+
}
63+
64+
return this.Name == other.Name &&
65+
this.Language == other.Language;
66+
}
67+
68+
/// <inheritdoc />
69+
public override bool Equals(object obj) => this.Equals(obj as JsonLdContext);
70+
71+
/// <inheritdoc />
72+
public override int GetHashCode() => HashCode.Of(this.Name).And(this.Language);
73+
74+
/// <inheritdoc />
75+
public override string ToString() => this.Name;
76+
}
77+
}

Source/Schema.NET/JsonLdObject.cs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
1-
namespace Schema.NET
1+
namespace Schema.NET
22
{
33
using System;
4-
using System.Runtime.Serialization;
5-
4+
using System.Runtime.Serialization;
5+
using Newtonsoft.Json;
6+
67
/// <summary>
7-
/// The base object
8+
/// The base JSON-LD object.
89
/// See https://json-ld.org/spec/latest/json-ld
910
/// </summary>
1011
[DataContract]
1112
public class JsonLdObject
1213
{
1314
/// <summary>
14-
/// Gets or sets the context used to define the short-hand names that are used throughout a JSON-LD document.
15+
/// Gets the context used to define the short-hand names that are used throughout a JSON-LD document.
1516
/// These short-hand names are called terms and help developers to express specific identifiers in a compact
1617
/// manner.
1718
/// When two people communicate with one another, the conversation takes place in a shared environment,
@@ -22,8 +23,16 @@ public class JsonLdObject
2223
/// Simply speaking, a context is used to map terms to IRIs. Terms are case sensitive and any valid string that
2324
/// is not a reserved JSON-LD keyword can be used as a term.
2425
/// </summary>
25-
[DataMember(Name = "@context", Order = 0)]
26-
public virtual string Context { get; }
26+
[DataMember(Name = "@context", Order = 0)]
27+
[JsonConverter(typeof(ContextJsonConverter))]
28+
public virtual JsonLdContext Context { get; internal set; } = new JsonLdContext();
29+
30+
/// <summary>
31+
/// Gets or sets the type, used to uniquely identify things that are being described in the document with IRIs
32+
/// or blank node identifiers.
33+
/// </summary>
34+
[DataMember(Name = "@type", Order = 1)]
35+
public virtual string Type { get; }
2736

2837
/// <summary>
2938
/// 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
3544
/// </summary>
3645
[DataMember(Name = "@id", Order = 2)]
3746
public virtual Uri Id { get; set; }
38-
39-
/// <summary>
40-
/// Gets or sets the type, used to uniquely identify things that are being described in the document with IRIs
41-
/// or blank node identifiers.
42-
/// </summary>
43-
[DataMember(Name = "@type", Order = 1)]
44-
public virtual string Type { get; }
4547
}
4648
}

Source/Schema.NET/Schema.NET.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
<ItemGroup Label="Package References">
4444
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" PrivateAssets="all" Version="2.9.2" />
4545
<!-- See https://github.com/Microsoft/dotnet/tree/master/releases/reference-assemblies -->
46-
<PackageReference Condition="'$(OS)' != 'Windows_NT'" Include="Microsoft.NETFramework.ReferenceAssemblies" PrivateAssets="All" Version="1.0.0-preview.2" />
46+
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" PrivateAssets="All" Version="1.0.0-preview.2" />
4747
<PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" Version="1.0.0-beta2-19270-01" />
4848
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
4949
<PackageReference Include="StyleCop.Analyzers" PrivateAssets="All" Version="1.1.118" />

Source/Schema.NET/ValuesJsonConverter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace Schema.NET
1010
using Newtonsoft.Json.Linq;
1111

1212
/// <summary>
13-
/// Converts a <see cref="IValues"/> object to JSON.
13+
/// Converts a <see cref="IValues"/> object to and from JSON.
1414
/// </summary>
1515
/// <seealso cref="JsonConverter" />
1616
public class ValuesJsonConverter : JsonConverter

Source/Schema.NET/core/Thing.cs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace Schema.NET
1+
namespace Schema.NET
22
{
33
using System;
44
using System.Runtime.Serialization;
@@ -76,12 +76,6 @@ public partial interface IThing
7676
[DataContract]
7777
public partial class Thing : IThing
7878
{
79-
/// <summary>
80-
/// Gets the context for the object, specifying that it comes from schema.org.
81-
/// </summary>
82-
[DataMember(Name = "@context", Order = 0)]
83-
public override string Context => "http://schema.org";
84-
8579
/// <summary>
8680
/// Gets the name of the type as specified by schema.org.
8781
/// </summary>
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
namespace Schema.NET.Test
2+
{
3+
using Newtonsoft.Json;
4+
using Xunit;
5+
6+
public class ContextJsonConverterTest
7+
{
8+
[Fact]
9+
public void ReadJson_StringContext_ContextHasName()
10+
{
11+
var json = "{\"@context\":\"foo\",\"@type\":\"Thing\"}";
12+
13+
var thing = JsonConvert.DeserializeObject<Thing>(json);
14+
15+
Assert.NotNull(thing.Context);
16+
Assert.Equal("foo", thing.Context.Name);
17+
Assert.Null(thing.Context.Language);
18+
}
19+
20+
[Fact]
21+
public void ReadJson_ObjectContextWithName_ContextHasName()
22+
{
23+
var json = "{\"@context\":{\"name\":\"foo\"},\"@type\":\"Thing\"}";
24+
25+
var thing = JsonConvert.DeserializeObject<Thing>(json);
26+
27+
Assert.NotNull(thing.Context);
28+
Assert.Equal("foo", thing.Context.Name);
29+
Assert.Null(thing.Context.Language);
30+
}
31+
32+
[Fact]
33+
public void ReadJson_ObjectContextWithNameAndLanguage_ContextHasNameAndLanguage()
34+
{
35+
var json = "{\"@context\":{\"name\":\"foo\",\"@language\":\"en\"},\"@type\":\"Thing\"}";
36+
37+
var thing = JsonConvert.DeserializeObject<Thing>(json);
38+
39+
Assert.NotNull(thing.Context);
40+
Assert.Equal("foo", thing.Context.Name);
41+
Assert.Equal("en", thing.Context.Language);
42+
}
43+
44+
[Fact]
45+
public void WriteJson_StringContext_ContextHasName()
46+
{
47+
var json = new Thing().ToString();
48+
49+
Assert.Equal("{\"@context\":\"http://schema.org\",\"@type\":\"Thing\"}", json);
50+
}
51+
52+
[Fact]
53+
public void WriteJson_ObjectContextWithLanguage_ContextHasName()
54+
{
55+
var thing = new Thing();
56+
thing.Context.Language = "en";
57+
58+
var json = thing.ToString();
59+
60+
Assert.Equal("{\"@context\":{\"name\":\"http://schema.org\",\"@language\":\"en\"},\"@type\":\"Thing\"}", json);
61+
}
62+
}
63+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
namespace Schema.NET.Test
2+
{
3+
using System.Collections.Generic;
4+
using Xunit;
5+
6+
public class JsonLdContextTest
7+
{
8+
public static IEnumerable<object[]> EqualContexts => new List<object[]>
9+
{
10+
new object[] { new JsonLdContext(), new JsonLdContext() },
11+
new object[] { new JsonLdContext() { Name = "a" }, new JsonLdContext() { Name = "a" } },
12+
new object[]
13+
{
14+
new JsonLdContext() { Name = "a", Language = "b" },
15+
new JsonLdContext() { Name = "a", Language = "b" },
16+
},
17+
};
18+
19+
public static IEnumerable<object[]> NotEqualContexts => new List<object[]>
20+
{
21+
new object[] { new JsonLdContext(), null },
22+
new object[] { new JsonLdContext(), new JsonLdContext() { Name = "a" } },
23+
new object[] { new JsonLdContext() { Name = "a" }, new JsonLdContext() },
24+
new object[] { new JsonLdContext() { Name = "a" }, new JsonLdContext() { Name = "b" } },
25+
new object[]
26+
{
27+
new JsonLdContext() { Name = "a", Language = "b" },
28+
new JsonLdContext() { Name = "a", Language = "c" },
29+
},
30+
};
31+
32+
public static IEnumerable<object[]> ToStringContexts => new List<object[]>
33+
{
34+
new object[] { new JsonLdContext(), "http://schema.org" },
35+
new object[] { new JsonLdContext() { Name = "a" }, "a" },
36+
};
37+
38+
[Theory]
39+
[MemberData(nameof(EqualContexts))]
40+
public void Equals_IsEqual_ReturnsTrue(JsonLdContext a, JsonLdContext b) => Assert.True(a.Equals(b));
41+
42+
[Theory]
43+
[MemberData(nameof(NotEqualContexts))]
44+
public void Equals_IsNotEqual_ReturnsFalse(JsonLdContext a, JsonLdContext b) => Assert.False(a.Equals(b));
45+
46+
[Theory]
47+
[MemberData(nameof(EqualContexts))]
48+
public void EqualsOperator_IsEqual_ReturnsTrue(JsonLdContext a, JsonLdContext b) => Assert.True(a == b);
49+
50+
[Theory]
51+
[MemberData(nameof(NotEqualContexts))]
52+
public void EqualsOperator_IsNotEqual_ReturnsFalse(JsonLdContext a, JsonLdContext b) => Assert.False(a == b);
53+
54+
[Theory]
55+
[MemberData(nameof(EqualContexts))]
56+
public void NotEqualsOperator_IsEqual_ReturnsFalse(JsonLdContext a, JsonLdContext b) => Assert.False(a != b);
57+
58+
[Theory]
59+
[MemberData(nameof(NotEqualContexts))]
60+
public void NotEqualsOperator_IsNotEqual_ReturnsTrue(JsonLdContext a, JsonLdContext b) => Assert.True(a != b);
61+
62+
[Theory]
63+
[MemberData(nameof(ToStringContexts))]
64+
public void ToString_(JsonLdContext context, string expectedValue) =>
65+
Assert.Equal(expectedValue, context.ToString());
66+
}
67+
}

0 commit comments

Comments
 (0)