Semantics API¶
The semantics package provides a Go implementation of the H5P semantics format, which is used to define form fields, validation rules, and UI behaviors for H5P content types.
Overview¶
H5P semantics are JSON schemas that describe how content types should be configured and validated. The semantics package converts these JSON definitions into type-safe Go structs.
Core Types¶
Field¶
The Field
struct represents a single field in an H5P semantics definition:
type Field struct {
Name string `json:"name,omitempty"`
Type string `json:"type"`
Label string `json:"label,omitempty"`
Description string `json:"description,omitempty"`
Importance string `json:"importance,omitempty"`
Optional bool `json:"optional,omitempty"`
Default interface{} `json:"default,omitempty"`
// Polymorphic options field
Options interface{} `json:"options,omitempty"`
// Type-specific fields...
}
SelectOption¶
Represents an option in a select field:
SemanticDefinition¶
The top-level semantics array:
Polymorphic Options Field¶
The semantics implementation handles H5P's polymorphic use of the "options" field, which serves different purposes depending on the field type.
Problem¶
In H5P semantics, the same JSON field name "options" is used for two completely different data structures:
- Select fields: Array of objects with "value" and "label" properties
- Library fields: Array of library names/versions as strings
Solution¶
The Go implementation uses a single Options interface{}
field with helper methods for type-safe access:
// Field has a polymorphic Options field
type Field struct {
Options interface{} `json:"options,omitempty"`
// ...
}
Helper Methods¶
GetSelectOptions()¶
Retrieves options for select field types:
Example:
field := Field{
Type: "select",
Options: []interface{}{
map[string]interface{}{
"value": "true",
"label": "True",
},
map[string]interface{}{
"value": "false",
"label": "False",
},
},
}
selectOptions := field.GetSelectOptions()
if selectOptions != nil {
for _, opt := range selectOptions {
fmt.Printf("Value: %s, Label: %s\n", opt.Value, opt.Label)
}
}
GetLibraryOptions()¶
Retrieves options for library field types:
Example:
field := Field{
Type: "library",
Options: []interface{}{
"H5P.MultiChoice 1.16",
"H5P.TrueFalse 1.8",
},
}
libraryOptions := field.GetLibraryOptions()
if libraryOptions != nil {
for _, lib := range libraryOptions {
fmt.Printf("Available library: %s\n", lib)
}
}
SetSelectOptions()¶
Sets options for select fields:
Example:
field := &Field{Type: "select"}
field.SetSelectOptions([]SelectOption{
{Value: "small", Label: "Small"},
{Value: "medium", Label: "Medium"},
{Value: "large", Label: "Large"},
})
SetLibraryOptions()¶
Sets options for library fields:
Example:
field := &Field{Type: "library"}
field.SetLibraryOptions([]string{
"H5P.MultiChoice 1.16",
"H5P.Essay 1.5",
"H5P.TrueFalse 1.8",
})
Field Types¶
The semantics format supports various field types:
Basic Types¶
text
- Text input fieldsnumber
- Numeric input fieldsboolean
- Checkbox fieldsselect
- Dropdown selection fields
Complex Types¶
group
- Groups of related fieldslist
- Dynamic arrays of itemslibrary
- Content type selection fields
Example Field Definitions¶
Text Field:
field := Field{
Name: "title",
Type: "text",
Label: "Title",
Description: "Enter a title for your content",
Importance: "high",
MaxLength: 100,
}
Select Field:
field := Field{
Name: "size",
Type: "select",
Label: "Size",
}
field.SetSelectOptions([]SelectOption{
{Value: "small", Label: "Small"},
{Value: "large", Label: "Large"},
})
Library Field:
field := Field{
Name: "content",
Type: "library",
Label: "Content Type",
}
field.SetLibraryOptions([]string{
"H5P.MultiChoice 1.16",
"H5P.TrueFalse 1.8",
})
Type Validation¶
The helper methods include built-in validation:
GetSelectOptions()
returnsnil
if options are not in select formatGetLibraryOptions()
returnsnil
if options are not in library format- Methods handle both JSON unmarshaling (
[]interface{}
) and direct assignment scenarios
// Safe usage pattern
field := loadFieldFromJSON(data)
if selectOptions := field.GetSelectOptions(); selectOptions != nil {
// Handle as select field
processSelectField(selectOptions)
} else if libraryOptions := field.GetLibraryOptions(); libraryOptions != nil {
// Handle as library field
processLibraryField(libraryOptions)
} else {
// Handle other field types or invalid options
handleOtherFieldType(field)
}
Advanced Usage¶
Loading from JSON¶
func loadSemantics(jsonData []byte) (SemanticDefinition, error) {
var semantics SemanticDefinition
err := json.Unmarshal(jsonData, &semantics)
if err != nil {
return nil, err
}
return semantics, nil
}
Iterating Through Fields¶
func processSemantics(semantics SemanticDefinition) {
for _, field := range semantics {
fmt.Printf("Processing field: %s (type: %s)\n", field.Name, field.Type)
switch field.Type {
case "select":
if opts := field.GetSelectOptions(); opts != nil {
fmt.Printf(" Select options: %d choices\n", len(opts))
}
case "library":
if libs := field.GetLibraryOptions(); libs != nil {
fmt.Printf(" Library options: %d libraries\n", len(libs))
}
case "group":
if field.Fields != nil {
fmt.Printf(" Group with %d sub-fields\n", len(field.Fields))
}
}
}
}
Standards Compliance¶
The semantics implementation follows the official H5P semantics specification:
The implementation handles all standard H5P semantic field types and attributes while providing type safety and validation in Go.