Skip to content

Commit 72a6a1e

Browse files
authored
SF-3184 Add USJ support to the draft API (#2988)
1 parent e8d2d74 commit 72a6a1e

23 files changed

+1920
-0
lines changed

src/SIL.Converters.Usj/IUsj.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System.Collections;
2+
3+
namespace SIL.Converters.Usj
4+
{
5+
/// <summary>
6+
/// An interface for Unified Scripture JSON (USJ) types.
7+
/// </summary>
8+
public interface IUsj
9+
{
10+
/// <summary>
11+
/// The JSON representation of scripture contents from USFM/USX.
12+
/// </summary>
13+
/// <value>This will either be a <see cref="UsjMarker"/> or <see cref="string"/>.</value>
14+
/// <remarks>Nullable. The contents will be laid out in order.</remarks>
15+
ArrayList Content { get; set; }
16+
17+
/// <summary>
18+
/// The USJ spec type.
19+
/// </summary>
20+
string Type { get; set; }
21+
22+
/// <summary>
23+
/// The USJ spec version.
24+
/// </summary>
25+
string Version { get; set; }
26+
}
27+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using Newtonsoft.Json.Serialization;
2+
3+
namespace SIL.Converters.Usj
4+
{
5+
/// <summary>
6+
/// Ensures that the JSON properties for the USJ data model are in lower case.
7+
/// </summary>
8+
internal class LowerCaseNamingStrategy : NamingStrategy
9+
{
10+
/// <inheritdoc />
11+
protected override string ResolvePropertyName(string name) => name.ToLowerInvariant();
12+
}
13+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netstandard2.0</TargetFramework>
5+
</PropertyGroup>
6+
7+
<ItemGroup>
8+
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
9+
</ItemGroup>
10+
11+
</Project>

src/SIL.Converters.Usj/Usj.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
namespace SIL.Converters.Usj
2+
{
3+
/// <summary>
4+
/// Unified Scripture JSON (USJ) - The JSON variant of USFM and USX data models.
5+
/// These types follow this schema: <c>https://github.com/usfm-bible/tcdocs/blob/usj/grammar/usj.js</c>
6+
/// </summary>
7+
public class Usj : UsjBase, IUsj
8+
{
9+
/// <summary>
10+
/// The supported USJ spec type.
11+
/// </summary>
12+
public static readonly string UsjType = "USJ";
13+
14+
/// <summary>
15+
/// The supported USJ spec version.
16+
/// </summary>
17+
public static readonly string UsjVersion = "3.1";
18+
19+
/// <summary>
20+
/// The USJ spec version.
21+
/// </summary>
22+
public string Version { get; set; }
23+
}
24+
}

src/SIL.Converters.Usj/UsjBase.cs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using System.Collections;
2+
using System.Collections.Generic;
3+
using Newtonsoft.Json;
4+
5+
namespace SIL.Converters.Usj
6+
{
7+
/// <summary>
8+
/// Elements shared between <see cref="Usj"/> and <see cref="UsjMarker"/>.
9+
/// </summary>
10+
[JsonObject(NamingStrategyType = typeof(LowerCaseNamingStrategy), ItemNullValueHandling = NullValueHandling.Ignore)]
11+
public abstract class UsjBase
12+
{
13+
/// <summary>
14+
/// For <see cref="Usj"/>, this is the USJ spec type.
15+
/// For <see cref="UsjMarker"/>, this is the kind/category of node or element this is,
16+
/// corresponding the USFM marker and USX node.
17+
/// </summary>
18+
/// <example><c>para</c>, <c>verse</c>, <c>char</c>.</example>
19+
public string Type { get; set; }
20+
21+
/// <summary>
22+
/// The JSON representation of scripture contents from USFM/USX.
23+
/// </summary>
24+
/// <value>This will either be a <see cref="UsjMarker"/> or <see cref="string"/>.</value>
25+
/// <remarks>
26+
/// Nullable.
27+
/// If there are no contents, this will be null for <see cref="UsjMarker"/>, or empty for <see cref="Usj"/>.
28+
/// The contents will be laid out in order.
29+
/// </remarks>
30+
[JsonConverter(typeof(UsjContentConverter))]
31+
public ArrayList Content { get; set; }
32+
33+
/// <summary>
34+
/// Additional attributes that are not a part of the USJ specification.
35+
/// This is only used for <see cref="UsjMarker"/>.
36+
/// </summary>
37+
/// <remarks>
38+
/// These are typically <c>closed</c>, <c>colspan</c>, etc.
39+
/// </remarks>
40+
[JsonExtensionData]
41+
public Dictionary<string, object> AdditionalData { get; } = new Dictionary<string, object>();
42+
}
43+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
using System;
2+
using System.Collections;
3+
using Newtonsoft.Json;
4+
using Newtonsoft.Json.Linq;
5+
6+
namespace SIL.Converters.Usj
7+
{
8+
/// <summary>
9+
/// Converts the contents of the Content <see cref="ArrayList"/> to and from JSON, preserving
10+
/// the two supported content types: <see cref="string"/> and <see cref="UsjMarker"/>.
11+
/// </summary>
12+
public class UsjContentConverter : JsonConverter<ArrayList>
13+
{
14+
/// <inheritdoc />
15+
public override ArrayList ReadJson(
16+
JsonReader reader,
17+
Type objectType,
18+
ArrayList existingValue,
19+
bool hasExistingValue,
20+
JsonSerializer serializer
21+
)
22+
{
23+
var jArray = JArray.Load(reader);
24+
var list = new ArrayList();
25+
26+
foreach (JToken item in jArray)
27+
{
28+
if (item.Type == JTokenType.String)
29+
{
30+
list.Add(item.ToString());
31+
}
32+
else
33+
{
34+
var usjMarker = item.ToObject<UsjMarker>();
35+
list.Add(usjMarker);
36+
}
37+
}
38+
39+
return list;
40+
}
41+
42+
/// <inheritdoc />
43+
public override void WriteJson(JsonWriter writer, ArrayList value, JsonSerializer serializer)
44+
{
45+
JArray jArray = new JArray();
46+
foreach (object item in value)
47+
{
48+
if (item is string str)
49+
{
50+
jArray.Add(str);
51+
}
52+
else if (item is UsjMarker usjMarker)
53+
{
54+
jArray.Add(JToken.FromObject(usjMarker));
55+
}
56+
}
57+
58+
jArray.WriteTo(writer);
59+
}
60+
}
61+
}

src/SIL.Converters.Usj/UsjMarker.cs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
namespace SIL.Converters.Usj
2+
{
3+
/// <summary>
4+
/// A Scripture Marker and its contents.
5+
/// </summary>
6+
public class UsjMarker : UsjBase
7+
{
8+
/// <summary>
9+
/// The corresponding marker in USFM or style in USX.
10+
/// </summary>
11+
/// <example><c>p</c>, <c>v</c>, <c>nd</c>.</example>
12+
public string Marker { get; set; }
13+
14+
/// <summary>
15+
/// The milestone start ID, which indicates the Book-chapter-verse value in the paragraph based structure.
16+
/// </summary>
17+
/// <remarks>Nullable.</remarks>
18+
public string Sid { get; set; }
19+
20+
/// <summary>
21+
/// Milestone end ID, which matches the milestone start ID <see cref="Sid"/>.
22+
/// <see cref="Eid"/> is not specified in the USJ spec, but is kept for USX compatibility.
23+
/// </summary>
24+
/// <remarks>Nullable.</remarks>
25+
public string Eid { get; set; }
26+
27+
/// <summary>
28+
/// Chapter number or verse number.
29+
/// </summary>
30+
/// <remarks>Nullable.</remarks>
31+
public string Number { get; set; }
32+
33+
/// <summary>
34+
/// The 3-letter book code in ID element.
35+
/// </summary>
36+
/// <remarks>Nullable.</remarks>
37+
public string Code { get; set; }
38+
39+
/// <summary>
40+
/// Alternate chapter number or verse number.
41+
/// </summary>
42+
/// <remarks>Nullable.</remarks>
43+
public string AltNumber { get; set; }
44+
45+
/// <summary>
46+
/// Published character of a chapter or verse.
47+
/// </summary>
48+
/// <value>
49+
/// This can be a letter (I, II, etc.), a number (1, 2, ...), or both.
50+
/// It is only displayed in the published version of the scripture text.
51+
/// </value>
52+
/// <remarks>Nullable.</remarks>
53+
public string PubNumber { get; set; }
54+
55+
/// <summary>
56+
/// Caller character for footnotes and cross-refs.
57+
/// </summary>
58+
/// <remarks>Nullable.</remarks>
59+
public string Caller { get; set; }
60+
61+
/// <summary>
62+
/// Alignment of table cells.
63+
/// </summary>
64+
/// <remarks>Nullable.</remarks>
65+
public string Align { get; set; }
66+
67+
/// <summary>
68+
/// Category of extended study bible sections.
69+
/// </summary>
70+
/// <remarks>Nullable.</remarks>
71+
public string Category { get; set; }
72+
}
73+
}

0 commit comments

Comments
 (0)