-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 5ac254c
Showing
16 changed files
with
772 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
|
||
# Created by https://www.toptal.com/developers/gitignore/api/intellij+all,go | ||
# Edit at https://www.toptal.com/developers/gitignore?templates=intellij+all,go | ||
|
||
### Go ### | ||
# Binaries for programs and plugins | ||
*.exe | ||
*.exe~ | ||
*.dll | ||
*.so | ||
*.dylib | ||
|
||
# Test binary, built with `go test -c` | ||
*.test | ||
|
||
# Output of the go coverage tool, specifically when used with LiteIDE | ||
*.out | ||
|
||
# Dependency directories (remove the comment below to include it) | ||
# vendor/ | ||
|
||
### Go Patch ### | ||
/vendor/ | ||
/Godeps/ | ||
|
||
### Intellij+all ### | ||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider | ||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 | ||
|
||
# User-specific stuff | ||
.idea/**/workspace.xml | ||
.idea/**/tasks.xml | ||
.idea/**/usage.statistics.xml | ||
.idea/**/dictionaries | ||
.idea/**/shelf | ||
|
||
# Generated files | ||
.idea/**/contentModel.xml | ||
|
||
# Sensitive or high-churn files | ||
.idea/**/dataSources/ | ||
.idea/**/dataSources.ids | ||
.idea/**/dataSources.local.xml | ||
.idea/**/sqlDataSources.xml | ||
.idea/**/dynamic.xml | ||
.idea/**/uiDesigner.xml | ||
.idea/**/dbnavigator.xml | ||
|
||
# Gradle | ||
.idea/**/gradle.xml | ||
.idea/**/libraries | ||
|
||
# Gradle and Maven with auto-import | ||
# When using Gradle or Maven with auto-import, you should exclude module files, | ||
# since they will be recreated, and may cause churn. Uncomment if using | ||
# auto-import. | ||
# .idea/artifacts | ||
# .idea/compiler.xml | ||
# .idea/jarRepositories.xml | ||
# .idea/modules.xml | ||
# .idea/*.iml | ||
# .idea/modules | ||
# *.iml | ||
# *.ipr | ||
|
||
# CMake | ||
cmake-build-*/ | ||
|
||
# Mongo Explorer plugin | ||
.idea/**/mongoSettings.xml | ||
|
||
# File-based project format | ||
*.iws | ||
|
||
# IntelliJ | ||
out/ | ||
|
||
# mpeltonen/sbt-idea plugin | ||
.idea_modules/ | ||
|
||
# JIRA plugin | ||
atlassian-ide-plugin.xml | ||
|
||
# Cursive Clojure plugin | ||
.idea/replstate.xml | ||
|
||
# Crashlytics plugin (for Android Studio and IntelliJ) | ||
com_crashlytics_export_strings.xml | ||
crashlytics.properties | ||
crashlytics-build.properties | ||
fabric.properties | ||
|
||
# Editor-based Rest Client | ||
.idea/httpRequests | ||
|
||
# Android studio 3.1+ serialized cache file | ||
.idea/caches/build_file_checksums.ser | ||
|
||
### Intellij+all Patch ### | ||
# Ignores the whole .idea folder and all .iml files | ||
# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 | ||
|
||
.idea/ | ||
|
||
# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 | ||
|
||
*.iml | ||
modules.xml | ||
.idea/misc.xml | ||
*.ipr | ||
|
||
# Sonarlint plugin | ||
.idea/sonarlint | ||
|
||
# End of https://www.toptal.com/developers/gitignore/api/intellij+all,go |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
# gordf | ||
|
||
The gordf module is an RDF library for Go. | ||
|
||
## Current features | ||
- Parse N-Triples from file | ||
- Naive memory graph data structure | ||
- Idiomatic querying of the memory graph | ||
- Structs to represent URI and literals (both typed and lang tags) | ||
|
||
## Planned features | ||
- Blank Nodes | ||
- Parsing other RDF formats such as Turtle | ||
- Serialise to disk in RDF formats (N-Triple, Turtle, etc) | ||
- Idiomatic representation of CURIES E.g. `rdf:type` -> `RDF{l: "type"}` | ||
|
||
## Example usage | ||
```go | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
rdf "gordf/gordf" | ||
"gordf/parser" | ||
) | ||
|
||
func main() { | ||
g := rdf.Graph{} | ||
|
||
parser.ParseFile(&g, "data.nt", "nt") | ||
|
||
rdfType := rdf.NewURI("http://www.w3.org/1999/02/22-rdf-syntax-ns#type") | ||
schemaName := rdf.NewURI("http://schema.org/name") | ||
|
||
for triple := range g.Triples(rdf.None{}, rdfType, rdf.NewURI("http://schema.org/Organization")) { | ||
for triple := range g.Triples(triple.S, schemaName, rdf.None{}) { | ||
fmt.Println(triple) | ||
} | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module gordf | ||
|
||
go 1.15 | ||
|
||
require github.com/iand/ntriples v0.0.0-20170827115059-bd9c67713a4a |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
github.com/iand/ntriples v0.0.0-20170827115059-bd9c67713a4a h1:k72398bGJXVOPPITdRiexxvB//2NwoEjgR+f58/qyps= | ||
github.com/iand/ntriples v0.0.0-20170827115059-bd9c67713a4a/go.mod h1:mVRj8HGAAuBOqqY3RaUzs2B7leqqoKx/L9KD9mUrnKo= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
package gordf |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
package gordf | ||
|
||
import ( | ||
"gordf/set" | ||
) | ||
|
||
// A Graph struct with three indexes of the different possible triple permutations for fast query access. | ||
type Graph struct { | ||
spo map[Node]map[Node]set.Set | ||
pos map[Node]map[Node]set.Set | ||
osp map[Node]map[Node]set.Set | ||
} | ||
|
||
func (g *Graph) Add(s, p, o Node) { | ||
addToIndex(&g.spo, s, p, o) | ||
addToIndex(&g.pos, p, o, s) | ||
addToIndex(&g.osp, o, s, p) | ||
} | ||
|
||
func addToIndex(index *map[Node]map[Node]set.Set, a, b, c Node) { | ||
// Initialise the current index if it is nil. | ||
if *index == nil { | ||
*index = make(map[Node]map[Node]set.Set) | ||
} | ||
|
||
// If a not in index | ||
if _, ok := (*index)[a]; !ok { | ||
(*index)[a] = make(map[Node]set.Set) | ||
s := set.Set{} | ||
s.Add(c) | ||
(*index)[a][b] = s | ||
} else { | ||
// if b not in index | ||
if _, ok := (*index)[a][b]; !ok { | ||
s := set.Set{} | ||
s.Add(c) | ||
(*index)[a][b] = s | ||
} else { | ||
s := (*index)[a][b] | ||
s.Add(c) | ||
} | ||
} | ||
} | ||
|
||
func (g *Graph) Triples(s, p, o Node) chan Triple { | ||
triples := make(chan Triple) | ||
|
||
go func() { | ||
// if s is not None | ||
if _, ok := s.(None); !ok { | ||
// if P is not None | ||
if _, ok := p.(None); !ok { | ||
// if O is not None | ||
// sub pred obj | ||
if _, ok := o.(None); !ok { | ||
// if O in spo index | ||
if (*g).spo[s][p].Exists(o) { | ||
triples <- Triple{S: s, P: p, O: o} | ||
} | ||
} else { | ||
// sub pred None | ||
retObjects := (*g).spo[s][p] | ||
for retObj := range retObjects.Range() { | ||
retObjNode, _ := retObj.(Node) | ||
triples <- Triple{S: s, P: p, O: retObjNode} | ||
} | ||
} | ||
} else { | ||
// sub None obj | ||
if _, ok := o.(None); !ok { | ||
retPredicates := (*g).osp[o][s] | ||
for retPred := range retPredicates.Range() { | ||
retPredNode, _ := retPred.(Node) | ||
triples <- Triple{S: s, P: retPredNode, O: o} | ||
} | ||
} else { | ||
// sub None None | ||
retPredicates := (*g).spo[s] | ||
for retPred := range retPredicates { | ||
retObjects := (*g).spo[s][retPred] | ||
for retObj := range retObjects.Range() { | ||
retObjNode, _ := retObj.(Node) | ||
triples <- Triple{S: s, P: retPred, O: retObjNode} | ||
} | ||
} | ||
} | ||
} | ||
} else { | ||
if _, ok := p.(None); !ok { | ||
// None pred obj | ||
if _, ok := o.(None); !ok { | ||
retSubjects := (*g).pos[p][o] | ||
for retSub := range retSubjects.Range() { | ||
retSubNode, _ := retSub.(Node) | ||
triples <- Triple{S: retSubNode, P: p, O: o} | ||
} | ||
} else { | ||
// None pred None | ||
retObjects := (*g).pos[p] | ||
for retObj := range retObjects { | ||
retSubjects := (*g).pos[p][retObj] | ||
for retSub := range retSubjects.Range() { | ||
retSubNode, _ := retSub.(Node) | ||
triples <- Triple{S: retSubNode, P: p, O: retObj} | ||
} | ||
} | ||
} | ||
} else { | ||
// None None obj | ||
if _, ok := o.(None); !ok { | ||
retSubjects := (*g).osp[o] | ||
for retSub := range retSubjects { | ||
retPredicates := (*g).osp[o][retSub] | ||
for retPred := range retPredicates.Range() { | ||
retPredNode, _ := retPred.(Node) | ||
triples <- Triple{S: retSub, P: retPredNode, O: o} | ||
} | ||
} | ||
} else { | ||
// None None None | ||
retSubjects := (*g).spo | ||
for retSub := range retSubjects { | ||
retPredicates := (*g).spo[retSub] | ||
for retPred := range retPredicates { | ||
retObjects := (*g).spo[retSub][retPred] | ||
for retObj := range retObjects.Range() { | ||
retObjNode, _ := retObj.(Node) | ||
triples <- Triple{S: retSub, P: retPred, O: retObjNode} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
close(triples) | ||
}() | ||
|
||
return triples | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package gordf | ||
|
||
import "fmt" | ||
|
||
// The Literal struct implements the Node interface. | ||
type Literal struct { | ||
value interface{} | ||
datatype URI | ||
language string | ||
} | ||
|
||
func (literal Literal) Equals(n Node) bool { | ||
literal2, ok := n.(Literal) | ||
if ok { | ||
return literal.value == literal2.value | ||
} | ||
return false | ||
} | ||
|
||
func (literal Literal) Value() string { | ||
return fmt.Sprintf("%v", literal.value) | ||
} | ||
|
||
func (literal Literal) String() string { | ||
|
||
// Literal is a number. | ||
// TODO: Check if checking these types is enough for numbers. I think just checking int is enough | ||
// as it should be the set of all ints, but not 100% sure. | ||
_, okInt := literal.value.(int) | ||
_, okFloat32 := literal.value.(float32) | ||
_, okFloat64 := literal.value.(float64) | ||
if okInt || okFloat32 || okFloat64 { | ||
return fmt.Sprintf(`%v`, literal.value) | ||
} | ||
|
||
// Literal is a bool. | ||
_, ok := literal.value.(bool) | ||
if ok { | ||
return fmt.Sprintf(`"%v"^^<http://www.w3.org/2001/XMLSchema#boolean>`, literal.value) | ||
} | ||
|
||
// Literal is a string with a language tag and a datatype. | ||
if literal.language != "" && literal.datatype.value != "" { | ||
return fmt.Sprintf(`"%v"@%v^^%v`, literal.value, literal.language, literal.datatype) | ||
} | ||
|
||
// Literal is a string and has either a language tag or datatype. | ||
if literal.datatype.value != "" { | ||
return fmt.Sprintf(`"%v"^^%v`, literal.value, literal.datatype) | ||
} else if literal.language != "" { | ||
return fmt.Sprintf(`"%v"@%v`, literal.value, literal.language) | ||
} | ||
|
||
// Literal is a string and has no language tag or datatype. | ||
return fmt.Sprintf(`"%v"`, literal.value) | ||
} | ||
|
||
func NewLiteralWithLanguageAndDatatype(value string, datatype URI, language string) Literal { | ||
return Literal{value: value, datatype: datatype, language: language} | ||
} | ||
|
||
func NewLiteralWithDatatype(value string, datatype URI) Literal { | ||
return Literal{value: value, datatype: datatype} | ||
} | ||
|
||
func NewLiteralWithLanguage(value string, language string) Literal { | ||
return Literal{value: value, language: language} | ||
} | ||
|
||
func NewLiteral(value interface{}) Literal { | ||
return Literal{value: value} | ||
} |
Oops, something went wrong.