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 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. // VocabularyType represents a single ActivityStream type in a vocabulary.
type VocabularyType struct { type VocabularyType struct {
Name string Name string
URI *url.URL URI *url.URL
Notes string Notes string
DisjointWith []VocabularyReference DisjointWith []VocabularyReference
Extends []VocabularyReference Extends []VocabularyReference // TODO: Object improperly extends Link
Properties []VocabularyReference // TODO: Check for duplication Properties []VocabularyReference // TODO: Check for duplication
WithoutProperties []VocabularyReference // TODO: Missing for IntransitiveActivity WithoutProperties []VocabularyReference // TODO: Missing for IntransitiveActivity
Examples []VocabularyExample 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 // VocabularyProperty represents a single ActivityStream property type in a
// vocabulary. // vocabulary.
type VocabularyProperty struct { type VocabularyProperty struct {
@ -59,6 +94,26 @@ type VocabularyProperty struct {
NaturalLanguageMap bool 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 // VocabularyExample documents an Example for an ActivityStream type or property
// in the vocabulary. // in the vocabulary.
type VocabularyExample struct { type VocabularyExample struct {
@ -67,6 +122,21 @@ type VocabularyExample struct {
Example map[string]interface{} 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 // VocabularyReference refers to another Vocabulary reference, either a
// VocabularyType, VocabularyValue, or a VocabularyProperty. It may refer to // VocabularyType, VocabularyValue, or a VocabularyProperty. It may refer to
// another Vocabulary's type or property entirely. // another Vocabulary's type or property entirely.
@ -75,3 +145,18 @@ type VocabularyReference struct {
URI *url.URL URI *url.URL
Vocab string // If present, must match key in ParsedVocabulary.References 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 // ParsingContext contains the results of the parsing as well as scratch space
// required for RDFNodes to be able to statefully apply changes. // required for RDFNodes to be able to statefully apply changes.
type ParsingContext struct { 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 // 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 // ontology (determined at creation time). It applies the value in its own
// specific implementation on the context. // specific implementation on the context.
type RDFNode interface { 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 // ParseVocabulary parses the specified input as an ActivityStreams context that
// specifies a Core, Extended, or Extension vocabulary. // specifies a Core, Extended, or Extension vocabulary.
func ParseVocabulary(registry *RDFRegistry, input JSONLD) (vocabulary *ParsedVocabulary, err error) { 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 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 // 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 // algorithm in order to build a set of nodes which will be able to parse the
// rest of the document. // rest of the document.