diff --git a/src/json-ld.net/Core/JsonLdApi.cs b/src/json-ld.net/Core/JsonLdApi.cs index 60d61b8..186d913 100644 --- a/src/json-ld.net/Core/JsonLdApi.cs +++ b/src/json-ld.net/Core/JsonLdApi.cs @@ -1072,14 +1072,34 @@ internal virtual void GenerateNodeMap(JToken element, JObject /// internal virtual void GenerateNodeMap(JToken element, JObject nodeMap, string activeGraph, JToken activeSubject, string activeProperty, JObject list) + { + GenerateNodeMap(element, nodeMap, activeGraph, activeSubject, activeProperty, list, skipSetContainsCheck: false); + } + + private void GenerateNodeMap(JToken element, JObject nodeMap, + string activeGraph, JToken activeSubject, string activeProperty, JObject list, bool skipSetContainsCheck) { // 1) if (element is JArray) { + JsonLdSet set = null; + + if (list == null) + { + set = new JsonLdSet(); + } + // 1.1) foreach (JToken item in (JArray)element) { - GenerateNodeMap(item, nodeMap, activeGraph, activeSubject, activeProperty, list); + skipSetContainsCheck = false; + + if (set != null) + { + skipSetContainsCheck = set.Add(item); + } + + GenerateNodeMap(item, nodeMap, activeGraph, activeSubject, activeProperty, list, skipSetContainsCheck); } return; } @@ -1204,7 +1224,7 @@ internal virtual void GenerateNodeMap(JToken element, JObject if (list == null) { // 6.6.2.1+2) - JsonLdUtils.MergeValue(node, activeProperty, reference); + JsonLdUtils.MergeValue(node, activeProperty, reference, skipSetContainsCheck); } else { diff --git a/src/json-ld.net/Core/JsonLdSet.cs b/src/json-ld.net/Core/JsonLdSet.cs new file mode 100644 index 0000000..a43edc0 --- /dev/null +++ b/src/json-ld.net/Core/JsonLdSet.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json.Linq; + +namespace JsonLD.Core +{ + internal sealed class JsonLdSet + { + private readonly Lazy> _objects; + + internal JsonLdSet() + { + _objects = new Lazy>(() => new HashSet(StringComparer.Ordinal)); + } + + internal bool Add(JToken token) + { + if (token == null) + { + throw new ArgumentNullException(nameof(token)); + } + + if (token is JObject) + { + var id = token["@id"]; + + return id != null && _objects.Value.Add(id.Value()); + } + + return false; + } + } +} \ No newline at end of file diff --git a/src/json-ld.net/Core/JsonLdUtils.cs b/src/json-ld.net/Core/JsonLdUtils.cs index b0d61b8..fc07804 100644 --- a/src/json-ld.net/Core/JsonLdUtils.cs +++ b/src/json-ld.net/Core/JsonLdUtils.cs @@ -148,8 +148,12 @@ public static bool DeepContains(JArray values, JToken value) return false; } - internal static void MergeValue(JObject obj, string key, JToken - value) + internal static void MergeValue(JObject obj, string key, JToken value) + { + MergeValue(obj, key, value, skipSetContainsCheck: false); + } + + internal static void MergeValue(JObject obj, string key, JToken value, bool skipSetContainsCheck) { if (obj == null) { @@ -161,8 +165,10 @@ internal static void MergeValue(JObject obj, string key, JToken values = new JArray(); obj[key] = values; } - if ("@list".Equals(key) || (value is JObject && ((IDictionary - )value).ContainsKey("@list")) || !DeepContains(values, (JToken)value)) + if (skipSetContainsCheck || + "@list".Equals(key) || + (value is JObject && ((IDictionary)value).ContainsKey("@list")) || + !DeepContains(values, (JToken)value)) { values.Add(value); }