jsonld

package module
v0.0.0-...-d974adc Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 26, 2026 License: MIT Imports: 19 Imported by: 10

README

go-jsonld

Package jsonld provides JSON-LD encoders and decoders, for the Go programming language.

And in particular, handles the way the ActivityPub, ActivityStreams, and the Fediverse uses JSON-LD.

Documention

Online documentation, which includes examples, can be found at: http://godoc.org/github.com/reiver/go-jsonld

GoDoc

Multiple NameSpaces

There are two ways to handle multiple JSON-LD namespaces:

  1. Separate structs — one struct per namespace, passed together to jsonld.Marshal.
  2. Per-field override tags — a single struct with a default namespace and jsonld.namespace/jsonld.prefix tags on individual fields to assign them to different namespaces.

Example: Single Namespace

import "github.com/reiver/go-jsonld"

// ...

// Note that "jsonld" struct-tags are used on the first 2 fields,
// and "json" struct-tags are used on the rest of the fields.
type MyStruct struct {
	NameSpace jsonld.NameSpace `jsonld:"http://example.com/ns"`
	Prefix    jsonld.Prefix    `jsonld:"ex"`

	Once   bool   `json:"once"`
	Twice  int    `json:"twice"`
	Thrice string `json:"thrice,omitempty"`
	Fource uint   `json:"fource"`
}

// ...

var value MyStruct // = ...

bytes, err := jsonld.Marshal(value)

Example: Multiple Namespaces (Separate Structs)

Use separate structs when each namespace is an independent concern:

import "github.com/reiver/go-jsonld"

// ...

type Person struct {
	NameSpace jsonld.NameSpace `jsonld:"http://ns.example/person"`
	Prefix    jsonld.Prefix    `jsonld:"person"`

	GivenName         string `json:"given-name,omitempty"`
	AdditionalNames []string `json:"additional-names,omitempty"`
	FamilyName        string `json:"family-name,omitempty"`
}

type Programmer struct {
	NameSpace jsonld.NameSpace `jsonld:"http://example.com/programmer"`
	Prefix    jsonld.Prefix    `jsonld:"programmer"`

	ProgrammingLanguage string `json:"programming-language,omitempty"`
}

// ...

var person Person // = ...
var programmer Programmer // = ...

bytes, err := jsonld.Marshal(person, programmer)

Example: Multiple Namespaces (Per-Field Override Tags)

Use jsonld.namespace and jsonld.prefix struct tags on individual fields to assign them to a different namespace than the struct's default:

import "github.com/reiver/go-jsonld"

// ...

type MyType struct {
	NameSpace jsonld.NameSpace `jsonld:"http://apple.example/ns"`
	Prefix    jsonld.Prefix    `jsonld:"aaa"`

	One   string `json:"one"`
	Two   string `json:"two"   jsonld.namespace:"http://banana.example/ns" jsonld.prefix:"bbb"`
	Three string `json:"three" jsonld.namespace:"http://cherry.example/ns" jsonld.prefix:"ccc"`
	Four  string `json:"four"`
	Five  string `json:"five"  jsonld.namespace:"http://banana.example/ns" jsonld.prefix:"bbb"`
}

// ...

var value MyType // = ...

bytes, err := jsonld.Marshal(value)

Fields without jsonld.namespace/jsonld.prefix tags (One, Four) use the struct's default namespace (aaa / http://apple.example/ns). Fields with both tags (Two, Five) are grouped under their declared namespace (bbb / http://banana.example/ns).

Both jsonld.namespace and jsonld.prefix must be specified together — providing one without the other is an error. Using the same prefix with different namespaces (or vice versa) across fields is also an error.

Import

To import package jsonld use import code like the follownig:

import "github.com/reiver/go-jsonld"

Installation

To install package jsonld do the following:

GOPROXY=direct go get github.com/reiver/go-jsonld

Author

Package jsonld was written by Charles Iliya Krempeaux

Documentation

Index

Examples

Constants

View Source
const (
	ErrBytesEmpty           = erorr.Error("empty bytes")
	ErrInvalidTypeValue     = erorr.Error("JSON-LD invalid type value")
	ErrNilReceiver          = erorr.Error("nil receiver")
	ErrJSONUnmarshalFailure = erorr.Error("JSON-unmarshal failure")
	ErrJSONTypeUnsupported  = erorr.Error("unsupported JSON type")
)

Variables

This section is empty.

Functions

func Marshal

func Marshal(values ...any) ([]byte, error)

Marshal returns the (merged) JSON-LD encoding of a series of values.

Each value is typically a struct with NameSpace and Prefix fields to declare its JSON-LD namespace. Multiple namespaces can be achieved by passing multiple structs, or by using "jsonld.namespace" and "jsonld.prefix" struct tags on individual fields within a single struct.

Example with multiple structs:

bytes, err := jsonld.Marshal(activitypub, activitystreams, security, toot, schema)

Example with per-field override tags in a single struct:

type MyType struct {
	NameSpace jsonld.NameSpace `jsonld:"http://apple.example/ns"`
	Prefix    jsonld.Prefix    `jsonld:"aaa"`

	One string `json:"one"`
	Two string `json:"two" jsonld.namespace:"http://banana.example/ns" jsonld.prefix:"bbb"`
}

bytes, err := jsonld.Marshal(MyType{One: "1", Two: "2"})

Slice fields tagged with "jsonld.compact" marshal single-element slices as bare values instead of single-element arrays:

type MyType struct {
	URL []string `json:"url,jsonld.compact"`
}

// []string{"http://example.com"} → "http://example.com"
// []string{"http://a.com", "http://b.com"} → ["http://a.com","http://b.com"]
Example (CompactMultipleStrings)
package main

import (
	"fmt"

	"github.com/reiver/go-jsonld"
)

func main() {
	var value struct {
		URL []string `json:"url,jsonld.compact"`
	}
	value.URL = []string{"http://example.com/page", "http://example.com/other"}

	data, err := jsonld.Marshal(value)
	if nil != err {
		fmt.Println("ERROR:", err)
		return
	}
	fmt.Printf("%s\n", data)

}
Output:
{"url":["http://example.com/page","http://example.com/other"]}
Example (CompactSingleObject)
package main

import (
	"fmt"

	"github.com/reiver/go-jsonld"
)

func main() {
	type Link struct {
		HRef string `json:"href"`
		Rel  string `json:"rel,omitempty"`
	}

	var value struct {
		URL []Link `json:"url,jsonld.compact"`
	}
	value.URL = []Link{{HRef: "http://example.com/page"}}

	data, err := jsonld.Marshal(value)
	if nil != err {
		fmt.Println("ERROR:", err)
		return
	}
	fmt.Printf("%s\n", data)

}
Output:
{"url":{"href":"http://example.com/page"}}
Example (CompactSingleString)
package main

import (
	"fmt"

	"github.com/reiver/go-jsonld"
)

func main() {
	var value struct {
		URL []string `json:"url,jsonld.compact"`
	}
	value.URL = []string{"http://example.com/page"}

	data, err := jsonld.Marshal(value)
	if nil != err {
		fmt.Println("ERROR:", err)
		return
	}
	fmt.Printf("%s\n", data)

}
Output:
{"url":"http://example.com/page"}

func Unmarshal

func Unmarshal(data []byte, dst any) error

Unmarshal parses JSON-LD data and stores the result in the value pointed to by dst.

This supports the "jsonld.compact" modifier, allowing single-element arrays to be represented as bare values in JSON-LD.

dst must be a pointer.

Example:

var result struct {
	URL []string `json:"url,jsonld.compact"`
}

err := jsonld.Unmarshal(data, &result)
Example (CompactArray)
package main

import (
	"fmt"

	"github.com/reiver/go-jsonld"
)

func main() {
	var result struct {
		URL []string `json:"url,jsonld.compact"`
	}

	err := jsonld.Unmarshal([]byte(`{"url":["http://example.com/page","http://example.com/other"]}`), &result)
	if nil != err {
		fmt.Println("ERROR:", err)
		return
	}
	fmt.Println(result.URL)

}
Output:
[http://example.com/page http://example.com/other]
Example (CompactBareString)
package main

import (
	"fmt"

	"github.com/reiver/go-jsonld"
)

func main() {
	var result struct {
		URL []string `json:"url,jsonld.compact"`
	}

	err := jsonld.Unmarshal([]byte(`{"url":"http://example.com/page"}`), &result)
	if nil != err {
		fmt.Println("ERROR:", err)
		return
	}
	fmt.Println(result.URL)

}
Output:
[http://example.com/page]

func UnmarshalJSONStringOrJSONObject

func UnmarshalJSONStringOrJSONObject[resultT any, stringT any, objectT any](bytes []byte, target *resultT) error

UnmarshalJSONStringOrJSONObject is used to JSON-unmarshal something that can have both a JSON string and JSON object form.

For example, where the JSON could be:

"http://example.com/something/123"

Or alternatively could be:

{
  "@id":     "http://example.com/something/123",
  "@type":   "Something",
  "name":    "Joe Blow",
  "summary": "Some bloke."
}

Example usage:

var url ProtoLink

err := jsonld.UnmarshalJSONStringOrJSONObject[activitypub.ProtoLink, activitypub.HRef, activitypub.Link](bytes, &url)

See also:

Example
package main

import (
	"fmt"

	"github.com/reiver/go-jsonld"
)

type ProtoLink interface {
	ProtoLink()
}

type HRef string

func (HRef) ProtoLink() {}

type Link struct {
	HRef     string `json:"href"`
	HRefLang string `json:"hreflang"`
	Rel      string `json:"rel"`
	Type     string `json:"type"`
}

func (Link) ProtoLink() {}

func main() {
	var jsons [][]byte = [][]byte{
		[]byte(`null`),
		[]byte(`false`),
		[]byte(`true`),
		[]byte(`-1`),
		[]byte(`0`),
		[]byte(`1`),
		[]byte(`""`),
		[]byte(`"Banana"`),
		[]byte(`"http://example.com/apple/banana/cherry.ext"`),
		[]byte(`{}`),
		[]byte(`{"href":"https://example.com/path/to/file.txt"}`),
		[]byte(`{"href":"https://example.com/path/to/file.txt","rel":"self"}`),
	}

	for _, jsonBytes := range jsons {
		fmt.Println()
		fmt.Println("=-=-=-=-=")
		fmt.Println()

		// Output the raw JSON
		fmt.Println("JSON:")
		fmt.Printf("%s\n", jsonBytes)
		fmt.Println()

		var actual ProtoLink
		err := jsonld.UnmarshalJSONStringOrJSONObject[ProtoLink, HRef, Link](jsonBytes, &actual)
		if nil != err {
			fmt.Println("ERROR: ", err)
			continue
		}

		fmt.Printf("type: %T\n", actual)
	}

}
Output:
=-=-=-=-=

JSON:
null

type: <nil>

=-=-=-=-=

JSON:
false

ERROR:  failed to json-unmarshal; ⦅unsupported JSON type⦆

=-=-=-=-=

JSON:
true

ERROR:  failed to json-unmarshal; ⦅unsupported JSON type⦆

=-=-=-=-=

JSON:
-1

ERROR:  failed to json-unmarshal; ⦅unsupported JSON type⦆

=-=-=-=-=

JSON:
0

ERROR:  failed to json-unmarshal; ⦅unsupported JSON type⦆

=-=-=-=-=

JSON:
1

ERROR:  failed to json-unmarshal; ⦅unsupported JSON type⦆

=-=-=-=-=

JSON:
""

type: jsonld_test.HRef

=-=-=-=-=

JSON:
"Banana"

type: jsonld_test.HRef

=-=-=-=-=

JSON:
"http://example.com/apple/banana/cherry.ext"

type: jsonld_test.HRef

=-=-=-=-=

JSON:
{}

type: jsonld_test.Link

=-=-=-=-=

JSON:
{"href":"https://example.com/path/to/file.txt"}

type: jsonld_test.Link

=-=-=-=-=

JSON:
{"href":"https://example.com/path/to/file.txt","rel":"self"}

type: jsonld_test.Link

func UnmarshalJSONStringOrJSONObjectOrJSONArray

func UnmarshalJSONStringOrJSONObjectOrJSONArray[resultT any, stringT any, objectT any](bytes []byte, target *[]resultT) error

UnmarshalJSONStringOrJSONObjectOrJSONArray is used to JSON-unmarshal something that can have a JSON string, JSON object, and a JSON array form.

For example, where the JSON could be:

"http://example.com/something/123"

Or alternatively could be:

{
  "@id":     "http://example.com/something/123",
  "@type":   "Something",
  "name":    "Joe Blow",
  "summary": "Some bloke."
}

Or alternatively could be:

[
  "http://example.com/something/123",
  {
    "@id":     "http://example.com/something/456",
    "@type":   "Something",
    "name":    "Jane Doe",
    "summary": "Some lady."
  }
]

Example usage:

var urls []ProtoLink

err := jsonld.UnmarshalJSONStringOrJSONObjectOrJSONArray[activitypub.ProtoLink, activitypub.HRef, activitypub.Link](bytes, &urls)

See also:

Types

type ContextNameSpace

type ContextNameSpace struct {
	NameSpace string
	Prefix    string
	Names     []string
}

ContextNameSpace represents a single namespace from a JSON-LD @context.

ContextOf returns a slice of ContextNameSpace — one per namespace found in the struct. A struct with per-field "jsonld.namespace" and "jsonld.prefix" override tags will produce multiple ContextNameSpace values: one for the default namespace and one for each override namespace.

For marshaling a slice of ContextNameSpace values to JSON, see Contexts.

func ContextOf

func ContextOf(value any) ([]ContextNameSpace, error)

ContextOf returns the JSON-LD context namespace(s) for a struct value.

Returns nil if the struct has no namespace information (no NameSpace, no Prefix, no field names).

For a single-namespace struct:

type MyStruct struct {
	NameSpace jsonld.NameSpace `jsonld:"http://example.com/ns#"`
	Prefix    jsonld.Prefix    `jsonld:"ex"`

	Apple  string `json:"apple"`
	Banana int    `json:"banana"`
	Cherry bool   `json:"cherry"`
}

For a multi-namespace struct, use the "jsonld.namespace" and "jsonld.prefix" struct tags on individual fields to assign them to a different namespace than the struct's default:

type MyStruct struct {
	NameSpace jsonld.NameSpace `jsonld:"http://apple.example/ns"`
	Prefix    jsonld.Prefix    `jsonld:"aaa"`

	One   string `json:"one"`
	Two   string `json:"two"   jsonld.namespace:"http://banana.example/ns" jsonld.prefix:"bbb"`
	Three string `json:"three" jsonld.namespace:"http://cherry.example/ns" jsonld.prefix:"ccc"`
}

Both "jsonld.namespace" and "jsonld.prefix" must be specified together. Providing one without the other is an error. Using the same prefix with different namespaces (or vice versa) across fields is also an error.

func DeepContextsOf

func DeepContextsOf(value any) ([]ContextNameSpace, error)

func (ContextNameSpace) IsEmpty

func (receiver ContextNameSpace) IsEmpty() bool

IsEmpty returns true if the ContextNameSpace has no namespace, no prefix, and no names.

type Contexts

type Contexts []ContextNameSpace

func (Contexts) MarshalJSON

func (contexts Contexts) MarshalJSON() ([]byte, error)

type Direction

type Direction struct {
	// contains filtered or unexported fields
}

Direction is used as the value of the JSON-LD "@direction" construct.

func DirectionLTR

func DirectionLTR() Direction

func DirectionNull

func DirectionNull() Direction

func DirectionRTL

func DirectionRTL() Direction

func (Direction) IsEmpty

func (receiver Direction) IsEmpty() bool

func (Direction) MarshalJSON

func (receiver Direction) MarshalJSON() ([]byte, error)

func (*Direction) UnmarshalJSON

func (receiver *Direction) UnmarshalJSON(bytes []byte) error

type ID

type ID struct {
	// contains filtered or unexported fields
}

ID is used as the value of the JSON-LD "@id" construct.

ID is an optional-type (also sometimes called an option-type or maybe-type).

For example:

type Node struct {
	ID jsonld.ID `json:"@id"`
}

See also:

func NoID

func NoID() ID

NoID returns a "nothing" ID.

"nothing" in the sense of optional-type (also sometimes called an option-type or maybe-type).

For example:

id := jsonld.NoID()

Although, more typically, it would more likely be used in code similar to:

type Node struct {
	ID jsonld.ID `json:"@id"`
}

var node Node = Node{
	ID: jsonld.NoID(),
}

See also:

func SomeID

func SomeID(id string) ID

SomeID returns a "something" ID.

"something" in the sense of optional-type (also sometimes called an option-type or maybe-type).

For example:

id := jsonld.SomeID("http://example.com/banana")

Although, more typically, it would more likely be used in code similar to:

type Node struct {
	ID jsonld.ID `json:"@id"`
}

var node Node = Node{
	ID: jsonld.SomeID("http://example.com/banana"),
}

Note that SomeID will normalze the value stored in ID. So, for example, this:

id := jsonld.SomeID("HTTPS://EXAMPLE.COM/banana")

Would get stored as:

"https://example.com/banana"

(Also, note that Blank Node Identifiers and their Blank Node Labels will be left as with respect to normalization. I.e., they won't be changed.)

See also:

func (ID) Get

func (receiver ID) Get() (string, bool)

Get is used to get the identifier inside of ID if there is anything inside of it.

If there is "nothing" inside of the ID, then it will return false for the second return value.

If there is "something" inside of the ID, then it wll return true for the second return value, and the first return value will be a string with the value of what is inside of it.

For example:

value, found := id.Get()

See also:

func (ID) GetElse

func (receiver ID) GetElse(alternative string) string

GetElse is used to get the identifier inside of ID if there is anything inside of it.

If there is "nothing" inside of the ID, then it will return provided alternative value.

If there is "something" inside of the ID, then it wll return a string with the value of what is inside of it.

For example:

value := id.GetElse(alternative)

See also:

func (ID) GoString

func (receiver ID) GoString() string

GoString returns an ID as a string that represents Go code.

Typically, this would be used implicitly with fmt.Printf, fmt.Sprintf, fmt.Fprintf, etc. For example:

type Node struct {
	ID jsonld.ID `json:"@id"`
}

var node Node = Node{
	ID: jsonld.SomeID("http://example.com/banana"),
}

fmt.Printf("@id = %#v\n", node.ID)

(Note the "%#v" verb used in the example code.)

See also:

func (ID) IsEmpty

func (receiver ID) IsEmpty() bool

IsEmpty returns whether the ID is empty or not.

ID is an optional-type (also sometimes called an option-type or maybe-type). An ID is empty if it is "nothing", and it not empty when it is "something". "nothing" and "something" are in the sense of optional-type.

For example:

if id.IsEmpty() {
	// ...
}

See also:

func (ID) MarshalJSON

func (receiver ID) MarshalJSON() ([]byte, error)

MarshalJSON json-marshals an ID into raw JSON as []byte.

Typically, this would be used implicitly with json.Marshal. For example:

type Node struct {
	ID jsonld.ID `json:"@id"`
}

var node Node = Node {
	ID: jsonld.SomeID("http://example.com/banana"),
}

data, err := json.Marshal(node)

See also:

func (*ID) UnmarshalJSON

func (receiver *ID) UnmarshalJSON(bytes []byte) error

UnmarshalJSON json-unmarshals raw JSON as []byte into an ID.

Typically, this would be used implicitly with json.Unmarshal. For example:

type Node struct {
	ID jsonld.ID `json:"@id"`
}

var node Node

err := json.Unmarshal(data, &node)

See also:

type NameSpace

type NameSpace struct{}

NameSpace is used to specify a default JSON-LD name-space for a struct that can be marshaled to JSON-LD.

For example:

type MyType struct {
	NameSpace jsonld.NameSpace `jsonld:"http://example.com/ns#"`
	Prefix    jsonld.Prefix    `jsonld:"ex"`

	GivenNames string `json:"givenNames"`
	FamilyName string `json:"familyName"`
}

This would result in a JSON-LD @context similar to:

"@context":{"ex":"http://example.com/ns#", ...}

And, another example:

type MyOtherType struct {
	JSONLDNameSpace jsonld.NameSpace `jsonld:"http://fruitbasket.example/ns/"`
	JSONLDPrefix    jsonld.Prefix    `jsonld:"fb"`

	NumApples   uint `json:"NumApples"`
	NumBananas  uint `json:"NumBananas"`
	NumCherries uint `json:"NumCherries"`
}

This would result in a JSON-LD @context similar to:

"@context":{"fb":"http://fruitbasket.example/ns/", ...}

And also, for example:

type YetAnotherType struct {
	NS jsonld.NameSpace `jsonld:"http://count.example/ns/"`

	Once   uint `json:"once"`
	Twice  uint `json:"twice"`
	Thrice uint `json:"thrice"`
	Fource uint `json:"fource"`
}

This would result in a JSON-LD @context similar to:

"@context":["http://count.example/ns/", ...]

One thing to notice is that — it does not matter what the name of the field of type jsonld.NameSpace is. In the first example it was "NameSpace". In the second example it was "JSONLDNameSpace". In the third example is was "NS". You coud name it anything you want (so long it is a valid Go field-name). The name isn't the important part — the important part is the tag.

func (NameSpace) JSONOmitAlways

func (NameSpace) JSONOmitAlways()

This makes it so the JSON package used omits this, when used as a field on a struct or a value in a map, from the resulting JSON.

type Prefix

type Prefix struct{}

Prefix is used to specify a default JSON-LD prefix for a struct that can be marshaled to JSON-LD.

For example:

type MyType struct {
	NameSpace jsonld.NameSpace `jsonld:"http://example.com/ns#"`
	Prefix    jsonld.Prefix    `jsonld:"ex"`

	GivenNames string `json:"givenNames"`
	FamilyName string `json:"familyName"`
}

This would result in a JSON-LD @context similar to:

"@context":{"ex":"http://example.com/ns#", ...}

And, another example:

type MyOtherType struct {
	JSONLDNameSpace jsonld.NameSpace `jsonld:"http://fruitbasket.example/ns/"`
	JSONLDPrefix    jsonld.Prefix    `jsonld:"fb"`

	NumApples   uint `json:"NumApples"`
	NumBananas  uint `json:"NumBananas"`
	NumCherries uint `json:"NumCherries"`
}

This would result in a JSON-LD @context similar to:

"@context":{"fb":"http://fruitbasket.example/ns/", ...}

One thing to notice is that — it does not matter what the name of the field of type jsonld.Prefix is. In the first example it was "NameSpace". In the second example it was "JSONLDNameSpace". You coud name it anything you want (so long it is a valid Go field-name). The name isn't the important part — the important part is the tag.

func (Prefix) JSONOmitAlways

func (Prefix) JSONOmitAlways()

This makes it so the JSON package used omits this, when used as a field on a struct or a value in a map, from the resulting JSON.

type Strings

type Strings = strings.Strings

Strings is a type that can be zero, one, or many strings.

In JSON, all of these would be valid values for this type:

null

"hello"

[]

["hello"]

{"once","twice"}

{"once","twice","thrice"}

{"once","twice","thrice","fource"}

func NoStrings

func NoStrings() Strings

NoStrings returns a Strings with no value.

func SomeString

func SomeString(value string) Strings

SomeString returns a Strings with some value, and in paticular containing a single string.

func SomeStrings

func SomeStrings(values ...string) Strings

SomeString returns a Strings with some value, and in paticular containing zero, one, two, three, ..., strings..

type Types

type Types struct {
	// contains filtered or unexported fields
}

Types is used as the value of the JSON-LD "@type" construct.

func NoType

func NoType() Types

func SomeType

func SomeType(t string) Types

func SomeTypes

func SomeTypes(tt ...string) Types

func (Types) IsEmpty

func (receiver Types) IsEmpty() bool

func (Types) MarshalJSON

func (receiver Types) MarshalJSON() ([]byte, error)

func (Types) Strings

func (receiver Types) Strings() []string

func (*Types) UnmarshalJSON

func (receiver *Types) UnmarshalJSON(bytes []byte) error

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL