/// <summary>Hashes all of the quads about a blank node.</summary> /// <remarks>Hashes all of the quads about a blank node.</remarks> /// <param name="id">the ID of the bnode to hash quads for.</param> /// <param name="bnodes">the mapping of bnodes to quads.</param> /// <param name="namer">the canonical bnode namer.</param> /// <returns>the new hash.</returns> private static string HashQuads(string id, IDictionary <string, IDictionary <string, object> > bnodes, UniqueNamer namer) { // return cached hash if (bnodes[id].ContainsKey("hash")) { return((string)bnodes[id]["hash"]); } // serialize all of bnode's quads var quads = (IList <RdfDataset.Quad>)bnodes[id]["quads"]; IList <string> nquads = new List <string>(); for (var i = 0; i < quads.Count; ++i) { object name; nquads.Add(RdfDatasetUtils.ToNQuad(quads[i], quads[i].TryGetValue("name", out name) ? (string)((IDictionary <string, object>)name)["value"] : null, id)); } // sort serialized quads nquads.SortInPlace(StringComparer.Ordinal); // return hashed quads var hash = Sha1hash(nquads); bnodes[id]["hash"] = hash; return(hash); }
// generates unique and duplicate hashes for bnodes /// <exception cref="JsonLD.Core.JsonLdError"></exception> public virtual object HashBlankNodes(IEnumerable <string> unnamed_) { #if !PORTABLE IList <string> unnamed = new List <string>(unnamed_); IList <string> nextUnnamed = new List <string>(); IDictionary <string, IList <string> > duplicates = new Dictionary <string, IList <string > >(); IDictionary <string, string> unique = new Dictionary <string, string>(); // NOTE: not using the same structure as javascript here to avoid // possible stack overflows // hash quads for each unnamed bnode for (var hui = 0;; hui++) { if (hui == unnamed.Count) { // done, name blank nodes var named = false; IList <string> hashes = new List <string>(unique.Keys); hashes.SortInPlace(); foreach (var hash in hashes) { var 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 <string>(); duplicates = new Dictionary <string, IList <string> >(); unique = new Dictionary <string, string>(); continue; } // name the duplicate hash bnods // names duplicate hash bnodes // enumerate duplicate hash groups in sorted order hashes = new List <string>(duplicates.Keys); hashes.SortInPlace(); // process each group for (var pgi = 0;; pgi++) { if (pgi == hashes.Count) { // done, create JSON-LD array // return createArray(); IList <string> normalized = new List <string>(); // 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 (var cai = 0; cai < quads.Count; ++cai) { var quad = quads[cai]; foreach (var attr in new[] { "subject", "object", "name" }) { if (quad.ContainsKey(attr)) { var qa = (IDictionary <string, object>)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 <string, object>)((IDictionary <string, object>)quad) ["name"])["value"] : null)); } // sort normalized output normalized.SortInPlace(); // handle output format if (options.format != null) { if ("application/nquads".Equals(options.format)) { var rval = string.Empty; foreach (var n in normalized) { rval += n; } return(rval); } else { throw new JsonLdError(JsonLdError.Error.UnknownFormat, options.format); } } var rval_1 = string.Empty; foreach (var n_1 in normalized) { rval_1 += n_1; } return(RdfDatasetUtils.ParseNQuads(rval_1)); } // name each group member var group = duplicates[hashes[pgi]]; IList <HashResult> results = new List <HashResult>(); for (var n_2 = 0;; n_2++) { if (n_2 == group.Count) { // name bnodes in hash order results.SortInPlace(new _IComparer_145()); foreach (var r in results) { // name all bnodes in path namer in // key-entry order // Note: key-order is preserved in // javascript foreach (var key in r.pathNamer.Existing().GetKeys()) { namer.GetName(key); } } // processGroup(i+1); break; } else { // skip already-named bnodes var bnode = group[n_2]; if (namer.IsNamed(bnode)) { continue; } // hash bnode paths var pathNamer = new UniqueNamer("_:b"); pathNamer.GetName(bnode); var result = HashPaths(bnode, bnodes, namer, pathNamer); results.Add(result); } } } } // hash unnamed bnode var bnode_1 = unnamed[hui]; var 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 <string> tmp = new List <string>(); tmp.Add(unique[hash_1]); tmp.Add(bnode_1); duplicates[hash_1] = tmp; nextUnnamed.Add(unique[hash_1]); nextUnnamed.Add(bnode_1); Collections.Remove(unique, hash_1); } else { unique[hash_1] = bnode_1; } } } #else throw new PlatformNotSupportedException(); #endif }