private string hashRelateBlankNode(string related, IDictionary <string, IDictionary <string, string> > quad, IdentifierIssuer issuer, string position) { /* * 1) Set the identifier to use for related, preferring first the * canonical identifier for related if issued, second the identifier * issued by issuer if issued, and last, if necessary, the result of * the Hash First Degree Quads algorithm, passing related. */ string id; if (this.canonicalIssuer.hasID(related)) { id = this.canonicalIssuer.getId(related); } else if (issuer.hasID(related)) { id = issuer.getId(related); } else { id = hashFirstDegreeQuads(related); } /* * 2) Initialize a string input to the value of position. * Note: We use a hash object instead. */ if (!position.Equals("g")) { return(NormalizeUtils.sha256Hash(Encoding.ASCII.GetBytes(position + getRelatedPredicate(quad) + id))); } else { return(NormalizeUtils.sha256Hash(Encoding.ASCII.GetBytes(position + id))); } }
private IDictionary <string, Object> hashNDegreeQuads(IdentifierIssuer issuer, string id) { /* * 1) Create a hash to related blank nodes map for storing hashes that * identify related blank nodes. * Note: 2) and 3) handled within `createHashToRelated` */ IDictionary <string, IList <string> > hashToRelated = this.createHashToRelated(issuer, id); /* * 4) Create an empty string, data to hash. * Note: We create a hash object instead. */ string mdString = ""; /* * 5) For each related hash to blank node list mapping in hash to * related blank nodes map, sorted lexicographically by related hash: */ sortMapKeys(hashToRelated); foreach (var hash in hashToRelated.Keys) { var blankNodes = hashToRelated[hash]; // 5.1) Append the related hash to the data to hash. mdString += hash; // 5.2) Create a string chosen path. string chosenPath = " "; // 5.3) Create an unset chosen issuer variable. IdentifierIssuer chosenIssuer = null; // 5.4) For each permutation of blank node list: string path = ""; List <string> recursionList = null; IdentifierIssuer issuerCopy = null; bool skipToNextPerm = false; NormalizeUtils.Permutator permutator = new NormalizeUtils.Permutator(JArray.FromObject(blankNodes)); while (permutator.HasNext()) { var permutation = permutator.Next(); // 5.4.1) Create a copy of issuer, issuer copy. issuerCopy = (IdentifierIssuer)issuer.Clone(); // 5.4.2) Create a string path. path = ""; /* * 5.4.3) Create a recursion list, to store blank node * identifiers that must be recursively processed by this * algorithm. */ recursionList = new List <string>(); // 5.4.4) For each related in permutation: foreach (var related in permutation) { /* * 5.4.4.1) If a canonical identifier has been issued for * related, append it to path. */ if (this.canonicalIssuer.hasID(related.ToString())) { path += this.canonicalIssuer.getId(related.ToString()); } // 5.4.4.2) Otherwise: else { /* * 5.4.4.2.1) If issuer copy has not issued an * identifier for related, append related to recursion * list. */ if (!issuerCopy.hasID(related.ToString())) { recursionList.Add(related.ToString()); } /* * 5.4.4.2.2) Use the Issue Identifier algorithm, * passing issuer copy and related and append the result * to path. */ path += issuerCopy.getId(related.ToString()); } /* * 5.4.4.3) If chosen path is not empty and the length of * path is greater than or equal to the length of chosen * path and path is lexicographically greater than chosen * path, then skip to the next permutation. */ if (chosenPath.Length != 0 && path.Length >= chosenPath.Length && path.CompareTo(chosenPath) == 1) { skipToNextPerm = true; break; } } } if (skipToNextPerm) { continue; } // 5.4.5) For each related in recursion list: foreach (var related in recursionList) { /* * 5.4.5.1) Set result to the result of recursively * executing the Hash N-Degree Quads algorithm, passing * related for identifier and issuer copy for path * identifier issuer. */ IDictionary <string, object> result = hashNDegreeQuads(issuerCopy, related); /* * 5.4.5.2) Use the Issue Identifier algorithm, passing * issuer copy and related and append the result to path. */ path += "<" + (string)result["hash"] + ">"; /* * 5.4.5.4) Set issuer copy to the identifier issuer in * result. */ issuerCopy = (IdentifierIssuer)result["issuer"]; /* * 5.4.5.5) If chosen path is not empty and the length of * path is greater than or equal to the length of chosen * path and path is lexicographically greater than chosen * path, then skip to the next permutation. */ if (chosenPath.Length != 0 && path.Length >= chosenPath.Length && path.CompareTo(chosenPath) == 1) { skipToNextPerm = true; break; } } if (skipToNextPerm) { continue; } /* * 5.4.6) If chosen path is empty or path is lexicographically * less than chosen path, set chosen path to path and chosen * issuer to issuer copy. */ if (chosenPath.Length == 0 || path.CompareTo(chosenPath) == -1) { chosenPath = path; chosenIssuer = issuerCopy; } // 5.5) Append chosen path to data to hash. mdString += chosenPath; // 5.6) Replace issuer, by reference, with chosen issuer. issuer = chosenIssuer; /* * 6) Return issuer and the hash that results from passing data to hash * through the hash algorithm. */ } /* * 6) Return issuer and the hash that results from passing data to hash * through the hash algorithm. */ IDictionary <string, object> hashQuad = new Dictionary <string, object>(); hashQuad.Add("hash", NormalizeUtils.sha256Hash(Encoding.ASCII.GetBytes(mdString))); hashQuad.Add("issuer", issuer); return(hashQuad); }
/* * STATUS : working on it */ private string hashFirstDegreeQuads(string id) { IDictionary <string, IList <Object> > info = this.blankNodeInfo[id]; if (info.ContainsKey("hash")) { return(info["hash"].ToString()); } // 1) Initialize nquads to an empty list. It will be used to store quads // in N-Quads format. IList <string> nquads = new List <string>(); // 2) Get the list of quads quads associated with the reference blank // node identifier in the blank node to quads map. IList <Object> quads = info["quads"]; // 3) For each quad quad in quads: foreach (var quad in quads) { // 3.1) Serialize the quad in N-Quads format with the following // special rule: // 3.1.1) If any component in quad is an blank node, then serialize // it using a special identifier as follows: // copy = {} IDictionary <string, IDictionary <string, string> > copy = new Dictionary <string, IDictionary <string, string> >(); /* 3.1.2) If the blank node's existing blank node identifier * matches the reference blank node identifier then use the * blank node identifier _:a, otherwise, use the blank node * identifier _:z. * STATUS: working */ RDFDataset.Quad quadMap = (RDFDataset.Quad)quad; foreach (var key in quadMap) { IDictionary <string, string> component = new Dictionary <string, string>(); component.Add(key.Key, key.Value.ToString()); if (key.Equals("predicate")) { copy.Add(key.Key, component); continue; } copy.Add(key.Key, modifyFirstDegreeComponent(component, id)); } RDFDataset.Quad copyQuad = new RDFDataset.Quad(copy, copy.ContainsKey("name") && copy["name"] != null ? (copy["name"])["value"] : null); nquads.Add(RDFDatasetUtils.ToNQuad(copyQuad, copyQuad.ContainsKey("name") && copyQuad["name"] != null ? (string)((IDictionary <string, object>)copyQuad["name"])["value"] : null)); // 4) Sort nquads in lexicographical order. } Collections.SortInPlace(nquads); // 5) Return the hash that results from passing the sorted, joined // nquads through the hash algorithm. return(NormalizeUtils.sha256HashnQuads(nquads)); }