220 lines
6.1 KiB
Go
220 lines
6.1 KiB
Go
package jsonld
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
)
|
|
|
|
// From the JSON-LD spec 3.3
|
|
// https://www.w3.org/TR/json-ld/#dfn-keyword
|
|
const (
|
|
// @context
|
|
// Used to define the short-hand names that are used throughout a JSON-LD document.
|
|
// These short-hand names are called terms and help developers to express specific identifiers in a compact manner.
|
|
// The @context keyword is described in detail in section 5.1 The Context.
|
|
ContextKw Term = "@context"
|
|
// @id
|
|
//Used to uniquely identify things that are being described in the document with IRIs or blank node identifiers.
|
|
// This keyword is described in section 5.3 Node Identifiers.
|
|
IdKw Term = "@id"
|
|
// @value
|
|
// Used to specify the data that is associated with a particular property in the graph.
|
|
// This keyword is described in section 6.9 String Internationalization and section 6.4 Typed Values.
|
|
ValueKw Term = "@value"
|
|
// @language
|
|
// Used to specify the language for a particular string value or the default language of a JSON-LD document.
|
|
// This keyword is described in section 6.9 String Internationalization.
|
|
LanguageKw Term = "@language"
|
|
//@type
|
|
//Used to set the data type of a node or typed value. This keyword is described in section 6.4 Typed Values.
|
|
TypeKw Term = "@type"
|
|
// @container
|
|
// Used to set the default container type for a term. This keyword is described in section 6.11 Sets and Lists.
|
|
ContainerKw Term = "@container"
|
|
//@list
|
|
//Used to express an ordered set of data. This keyword is described in section 6.11 Sets and Lists.
|
|
ListKw Term = "@list"
|
|
// @set
|
|
// Used to express an unordered set of data and to ensure that values are always represented as arrays.
|
|
// This keyword is described in section 6.11 Sets and Lists.
|
|
SetKw Term = "@set"
|
|
// @reverse
|
|
// Used to express reverse properties. This keyword is described in section 6.12 Reverse Properties.
|
|
ReverseKw Term = "@reverse"
|
|
// @index
|
|
// Used to specify that a container is used to index information and that processing should continue deeper
|
|
// into a JSON data structure. This keyword is described in section 6.16 Data Indexing.
|
|
IndexKw Term = "@index"
|
|
// @base
|
|
// Used to set the base IRI against which relative IRIs are resolved. T
|
|
// his keyword is described in section 6.1 Base IRI.
|
|
BaseKw Term = "@base"
|
|
// @vocab
|
|
// Used to expand properties and values in @type with a common prefix IRI.
|
|
// This keyword is described in section 6.2 Default Vocabulary.
|
|
VocabKw Term = "@vocab"
|
|
// @graph
|
|
// Used to express a graph. This keyword is described in section 6.13 Named Graphs.
|
|
GraphKw Term = "@graph"
|
|
)
|
|
|
|
// ContentType is the content type of JsonLD documents
|
|
const ContentType = `application/ld+json; profile="https://www.w3.org/ns/activitystreams"`
|
|
|
|
type (
|
|
// Ref basic type
|
|
LangRef string
|
|
// Term represents the JSON-LD term for @context maps
|
|
Term string
|
|
// IRI is a International Resource Identificator
|
|
IRI string
|
|
// Terms is an array of Term values
|
|
Terms []Term
|
|
)
|
|
|
|
// Nillable
|
|
type Nillable interface {
|
|
IsNil() bool
|
|
}
|
|
|
|
type IRILike interface {
|
|
IsCompact() bool
|
|
IsAbsolute() bool
|
|
IsRelative() bool
|
|
}
|
|
|
|
func (i IRI) IsCompact() bool {
|
|
return !i.IsAbsolute() && strings.Contains(string(i), ":")
|
|
}
|
|
func (i IRI) IsAbsolute() bool {
|
|
return strings.Contains(string(i), "https://")
|
|
}
|
|
func (i IRI) IsRelative() bool {
|
|
return !i.IsAbsolute()
|
|
}
|
|
|
|
var keywords = Terms{
|
|
BaseKw,
|
|
ContextKw,
|
|
ContainerKw,
|
|
GraphKw,
|
|
IdKw,
|
|
IndexKw,
|
|
LanguageKw,
|
|
ListKw,
|
|
ReverseKw,
|
|
SetKw,
|
|
TypeKw,
|
|
ValueKw,
|
|
VocabKw,
|
|
}
|
|
|
|
const NilTerm Term = "-"
|
|
const NilLangRef LangRef = "-"
|
|
|
|
type ContextObject struct {
|
|
ID interface{} `jsonld:"@id,omitempty,collapsible"`
|
|
Type interface{} `jsonld:"@type,omitempty,collapsible"`
|
|
}
|
|
|
|
// Context is of of the basic JSON-LD elements.
|
|
// It represents an array of ContextElements
|
|
type Context []ContextElement
|
|
|
|
// ContextElement is used to map terms to IRIs or JSON objects.
|
|
// Terms are case sensitive and any valid string that is not a reserved JSON-LD
|
|
// keyword can be used as a term.
|
|
type ContextElement struct {
|
|
Term Term
|
|
IRI IRI
|
|
}
|
|
|
|
func GetContext() Context {
|
|
return Context{}
|
|
}
|
|
|
|
//type Context Collapsible
|
|
|
|
// Collapsible is an interface used by the JSON-LD marshaller to collapse a struct to one single value
|
|
type Collapsible interface {
|
|
Collapse() interface{}
|
|
}
|
|
|
|
// Collapse returns the plain text collapsed value of the current Context object
|
|
func (c Context) Collapse() interface{} {
|
|
if len(c) == 1 && len(c[0].IRI) > 0 {
|
|
return c[0].IRI
|
|
}
|
|
for _, el := range c {
|
|
if el.Term == NilTerm {
|
|
|
|
}
|
|
}
|
|
|
|
return c
|
|
}
|
|
|
|
// Collapse returns the plain text collapsed value of the current IRI string
|
|
func (i IRI) Collapse() interface{} {
|
|
return i
|
|
}
|
|
|
|
// MarshalText basic stringify function
|
|
func (i IRI) MarshalText() ([]byte, error) {
|
|
return []byte(i), nil
|
|
}
|
|
|
|
// MarshalJSON returns the JSON document represented by the current Context
|
|
// This should return :
|
|
// If only one element in the context and the element has no Term -> json marshaled string
|
|
// If multiple elements in the context without Term -> json marshaled array of strings
|
|
// If multiple elements where at least one doesn't have a Term and one has a Term -> json marshaled array
|
|
// If multiple elements where all have Terms -> json marshaled object
|
|
func (c Context) MarshalJSON() ([]byte, error) {
|
|
mapIRI := make(map[Term]IRI, 0)
|
|
arr := make([]interface{}, 0)
|
|
i := 0
|
|
if len(c) == 1 && len(c[0].IRI) > 0 {
|
|
return json.Marshal(c[0].IRI)
|
|
}
|
|
for _, el := range c {
|
|
t := el.Term
|
|
iri := el.IRI
|
|
if t.IsNil() {
|
|
arr = append(arr, iri)
|
|
i += 1
|
|
} else {
|
|
if len(iri) > 0 {
|
|
mapIRI[t] = iri
|
|
}
|
|
}
|
|
}
|
|
if len(mapIRI) > 0 {
|
|
if len(arr) == 0 {
|
|
return json.Marshal(mapIRI)
|
|
}
|
|
arr = append(arr, mapIRI)
|
|
}
|
|
return json.Marshal(arr)
|
|
}
|
|
|
|
// UnmarshalJSON tries to load the Context from the incoming json value
|
|
func (c *Context) UnmarshalJSON(data []byte) error {
|
|
return nil
|
|
}
|
|
|
|
// IsNil returns if current LangRef is equal to empty string or to its nil value
|
|
func (l LangRef) IsNil() bool {
|
|
return len(l) == 0 || l == NilLangRef
|
|
}
|
|
|
|
// IsNil returns if current IRI is equal to empty string
|
|
func (i IRI) IsNil() bool {
|
|
return len(i) == 0
|
|
}
|
|
|
|
// IsNil returns if current Term is equal to empty string or to its nil value
|
|
func (i Term) IsNil() bool {
|
|
return len(i) == 0 || i == NilTerm
|
|
}
|