Setup applying RDF node understanding.

Next, the actual nodes need to be created in order to construct the
proper intermediate form and translate the parsed data into a meaningful
structure that can be used to generate code.

Ideally, this could also potentially allow code generation in other
languages too. And different ways to read in ActivityStreams
specifications and extensions. But that would be way off in the future.
このコミットが含まれているのは:
Cory Slep 2018-11-29 22:53:48 +01:00
コミット 94569ca549
2個のファイルの変更192行の追加4行の削除

ファイルの表示

@ -33,18 +33,53 @@ type VocabularyValue struct {
Zero string
}
func (v *VocabularyValue) SetName(s string) {
v.Name = s
}
func (v *VocabularyValue) SetURI(s string) error {
var e error
v.URI, e = url.Parse(s)
return e
}
var (
_ NameSetter = &VocabularyValue{}
_ URISetter = &VocabularyValue{}
)
// VocabularyType represents a single ActivityStream type in a vocabulary.
type VocabularyType struct {
Name string
URI *url.URL
Notes string
DisjointWith []VocabularyReference
Extends []VocabularyReference
Extends []VocabularyReference // TODO: Object improperly extends Link
Properties []VocabularyReference // TODO: Check for duplication
WithoutProperties []VocabularyReference // TODO: Missing for IntransitiveActivity
Examples []VocabularyExample
}
func (v *VocabularyType) SetName(s string) {
v.Name = s
}
func (v *VocabularyType) SetURI(s string) error {
var e error
v.URI, e = url.Parse(s)
return e
}
func (v *VocabularyType) SetNotes(s string) {
v.Notes = s
}
var (
_ NameSetter = &VocabularyType{}
_ URISetter = &VocabularyType{}
_ NotesSetter = &VocabularyType{}
)
// VocabularyProperty represents a single ActivityStream property type in a
// vocabulary.
type VocabularyProperty struct {
@ -59,6 +94,26 @@ type VocabularyProperty struct {
NaturalLanguageMap bool
}
func (v *VocabularyProperty) SetName(s string) {
v.Name = s
}
func (v *VocabularyProperty) SetURI(s string) error {
var e error
v.URI, e = url.Parse(s)
return e
}
func (v *VocabularyProperty) SetNotes(s string) {
v.Notes = s
}
var (
_ NameSetter = &VocabularyProperty{}
_ URISetter = &VocabularyProperty{}
_ NotesSetter = &VocabularyProperty{}
)
// VocabularyExample documents an Example for an ActivityStream type or property
// in the vocabulary.
type VocabularyExample struct {
@ -67,6 +122,21 @@ type VocabularyExample struct {
Example map[string]interface{}
}
func (v *VocabularyExample) SetName(s string) {
v.Name = s
}
func (v *VocabularyExample) SetURI(s string) error {
var e error
v.URI, e = url.Parse(s)
return e
}
var (
_ NameSetter = &VocabularyExample{}
_ URISetter = &VocabularyExample{}
)
// VocabularyReference refers to another Vocabulary reference, either a
// VocabularyType, VocabularyValue, or a VocabularyProperty. It may refer to
// another Vocabulary's type or property entirely.
@ -75,3 +145,18 @@ type VocabularyReference struct {
URI *url.URL
Vocab string // If present, must match key in ParsedVocabulary.References
}
func (v *VocabularyReference) SetName(s string) {
v.Name = s
}
func (v *VocabularyReference) SetURI(s string) error {
var e error
v.URI, e = url.Parse(s)
return e
}
var (
_ NameSetter = &VocabularyReference{}
_ URISetter = &VocabularyReference{}
)

ファイルの表示

@ -15,23 +15,126 @@ type JSONLD map[string]interface{}
// ParsingContext contains the results of the parsing as well as scratch space
// required for RDFNodes to be able to statefully apply changes.
type ParsingContext struct {
Result ParsedVocabulary
Result *ParsedVocabulary
Current interface{}
}
type NameSetter interface {
SetName(string)
}
type URISetter interface {
SetURI(string) error
}
type NotesSetter interface {
SetNotes(string)
}
// RDFNode is able to operate on a specific key if it applies towards its
// ontology (determined at creation time). It applies the value in its own
// specific implementation on the context.
type RDFNode interface {
Apply(key string, value interface{}, ctx ParsedVocabulary) (bool, error)
Enter(key string, ctx *ParsingContext) (bool, error)
Exit(key string, ctx *ParsingContext) (bool, error)
Apply(key string, value interface{}, ctx *ParsingContext) (bool, error)
}
// ParseVocabulary parses the specified input as an ActivityStreams context that
// specifies a Core, Extended, or Extension vocabulary.
func ParseVocabulary(registry *RDFRegistry, input JSONLD) (vocabulary *ParsedVocabulary, err error) {
_, err = parseJSONLDContext(registry, input)
var nodes []RDFNode
nodes, err = parseJSONLDContext(registry, input)
if err != nil {
return
}
vocabulary = &ParsedVocabulary{}
ctx := &ParsingContext{
Result: vocabulary,
}
err = apply(nodes, input, ctx)
return
}
// apply takes a specification input to populate the ParsingContext, based on
// the capabilities of the RDFNodes created from ontologies.
func apply(nodes []RDFNode, input JSONLD, ctx *ParsingContext) error {
for k, v := range input {
// Skip the context as it has already been parsed to create the
// nodes.
if k == JSON_LD_CONTEXT {
continue
}
if mapValue, ok := v.(map[string]interface{}); ok {
if err := enterFirstNode(nodes, k, ctx); err != nil {
return err
} else if err = apply(nodes, mapValue, ctx); err != nil {
return err
} else if err = exitFirstNode(nodes, k, ctx); err != nil {
return err
}
} else if arrValue, ok := v.([]interface{}); ok {
for _, val := range arrValue {
// First, enter for this key
if err := enterFirstNode(nodes, k, ctx); err != nil {
return err
}
// Recur or handle the value as necessary.
if mapValue, ok := val.(map[string]interface{}); ok {
if err := apply(nodes, mapValue, ctx); err != nil {
return err
}
} else if err := applyFirstNode(nodes, k, val, ctx); err != nil {
return err
}
// Finally, exit for this key
if err := exitFirstNode(nodes, k, ctx); err != nil {
return err
}
}
} else if err := applyFirstNode(nodes, k, v, ctx); err != nil {
return err
}
}
return nil
}
// enterFirstNode will Enter the first RDFNode that returns true or an error.
func enterFirstNode(nodes []RDFNode, key string, ctx *ParsingContext) error {
for _, node := range nodes {
if applied, err := node.Enter(key, ctx); applied {
return nil
} else if err != nil {
return err
}
}
return nil
}
// exitFirstNode will Exit the first RDFNode that returns true or an error.
func exitFirstNode(nodes []RDFNode, key string, ctx *ParsingContext) error {
for _, node := range nodes {
if applied, err := node.Exit(key, ctx); applied {
return nil
} else if err != nil {
return err
}
}
return nil
}
// applyFirstNode will Apply the first RDFNode that returns true or an error.
func applyFirstNode(nodes []RDFNode, key string, value interface{}, ctx *ParsingContext) error {
for _, node := range nodes {
if applied, err := node.Apply(key, value, ctx); applied {
return nil
} else if err != nil {
return err
}
}
return nil
}
// parseJSONLDContext implements a super basic JSON-LD @context parsing
// algorithm in order to build a set of nodes which will be able to parse the
// rest of the document.