JSON-LD Contexts
JSON-LD (JSON for Linking Data) extends regular JSON with semantic meaning by mapping field names to globally unique URIs. ZineCore2 provides JSON-LD contexts for each profile, enabling integration with RDF systems, SPARQL queries, and the broader semantic web.
What is JSON-LD?
JSON-LD adds a @context to regular JSON, transforming simple data into linked data:
{
"@context": "https://zinecore.org/v2/context/zinecore2",
"title": "Riot Grrrl",
"creator": ["Kathleen Hanna"],
"subject": ["feminism"]
}
This maps title → dcterms:title, creator → dcterms:creator, and so on, giving each field a globally unique identifier.
Available Contexts
- ZineCore2: zinecore2-context.jsonld
- AgentCore2: agentcore2-context.jsonld
- HoldingCore2: holdingcore2-context.jsonld
- RepoCore2: repocore2-context.jsonld
Quick Testing
Use the JSON-LD Playground to expand, compact, and frame JSON-LD documents without installing anything.
Content Negotiation
ZineCore2 context URIs support content negotiation:
# Request HTML documentation (default)
curl https://zinecore.org/v2/context/zinecore2
# Request JSON-LD context
curl -H "Accept: application/ld+json" \
https://zinecore.org/v2/context/zinecore2
This allows the same URI to serve both human-readable docs and machine-readable contexts.
Using JSON-LD Contexts
Expanding JSON-LD
Expansion converts compact field names to full URIs:
Input (compact):
{
"@context": "https://zinecore.org/v2/context/zinecore2",
"title": "Riot Grrrl",
"creator": ["Kathleen Hanna"],
"date": "1991"
}
Output (expanded):
[
{
"http://purl.org/dc/terms/title": [
{ "@value": "Riot Grrrl" }
],
"http://purl.org/dc/terms/creator": [
{ "@value": "Kathleen Hanna" }
],
"http://purl.org/dc/terms/date": [
{ "@value": "1991" }
]
}
]
With jsonld.js (JavaScript)
npm install jsonld
import jsonld from 'jsonld';
const doc = {
"@context": "https://zinecore.org/v2/context/zinecore2",
"title": "Riot Grrrl",
"creator": ["Kathleen Hanna"],
"date": "1991",
"subject": ["feminism", "punk-culture"]
};
// Expand to full URIs
const expanded = await jsonld.expand(doc);
console.log(JSON.stringify(expanded, null, 2));
// Compact with a different context
const compacted = await jsonld.compact(expanded, {
"@context": "https://zinecore.org/v2/context/zinecore2"
});
// Convert to N-Quads (RDF)
const nquads = await jsonld.toRDF(doc, { format: 'application/n-quads' });
console.log(nquads);
With PyLD (Python)
pip install PyLD
from pyld import jsonld
import json
doc = {
"@context": "https://zinecore.org/v2/context/zinecore2",
"title": "Riot Grrrl",
"creator": ["Kathleen Hanna"],
"date": "1991",
"subject": ["feminism", "punk-culture"]
}
# Expand
expanded = jsonld.expand(doc)
print(json.dumps(expanded, indent=2))
# Convert to RDF (N-Quads)
nquads = jsonld.to_rdf(doc, {'format': 'application/n-quads'})
print(nquads)
# Compact with context
compacted = jsonld.compact(expanded, "https://zinecore.org/v2/context/zinecore2")
print(json.dumps(compacted, indent=2))
Integration with RDF Systems
Loading into a Triple Store
Convert JSON-LD to N-Triples and load into Apache Jena, Blazegraph, or other RDF databases:
from pyld import jsonld
from rdflib import Graph
# Convert JSON-LD to RDF
doc = {
"@context": "https://zinecore.org/v2/context/zinecore2",
"title": "Riot Grrrl",
"creator": ["Kathleen Hanna"]
}
nquads = jsonld.to_rdf(doc, {'format': 'application/n-quads'})
# Load into RDFLib graph
g = Graph()
g.parse(data=nquads, format='nquads')
# Query with SPARQL
query = """
PREFIX dcterms: <http://purl.org/dc/terms/>
SELECT ?title ?creator
WHERE {
?zine dcterms:title ?title .
?zine dcterms:creator ?creator .
}
"""
for row in g.query(query):
print(f"Title: {row.title}, Creator: {row.creator}")
SPARQL Queries
Once loaded into a triple store, query across multiple records:
PREFIX dcterms: <http://purl.org/dc/terms/>
PREFIX zine: <https://zinecore.org/v2/zine#>
# Find all zines about feminism published in the 1990s
SELECT ?title ?creator ?date
WHERE {
?z dcterms:title ?title ;
dcterms:creator ?creator ;
dcterms:date ?date ;
dcterms:subject ?subject .
FILTER(CONTAINS(STR(?subject), "feminism"))
FILTER(REGEX(?date, "^199"))
}
ORDER BY ?date
Dublin Core Alignment
ZineCore2 contexts map primarily to Dublin Core Terms (dcterms) with custom extensions under the zine: namespace:
Core Dublin Core Mappings
| ZineCore2 Field | Maps To |
|---|---|
| title | dcterms:title |
| creator | dcterms:creator |
| contributor | dcterms:contributor |
| publisher | dcterms:publisher |
| date | dcterms:date |
| subject | dcterms:subject |
| abstract | dcterms:description |
| language | dcterms:language |
| format | dcterms:format |
| rights | dcterms:rights |
| identifier | dcterms:identifier |
| source | dcterms:source |
| relation | dcterms:relation |
ZineCore2 Extensions
| ZineCore2 Field | Maps To | Notes |
|---|---|---|
| genre | zine:genre | No standard DC equivalent |
| issue_designation | zine:issueDesignation | Zine-specific |
| binding_features | zine:binding | Physical characteristics |
| public_notes | zine:publicNotes | Curatorial notes |
See the ZineCore2 profile page for complete field mappings.
Framing JSON-LD
Framing reshapes JSON-LD into a specific structure, useful for generating nested representations:
const frame = {
"@context": "https://zinecore.org/v2/context/zinecore2",
"@type": "Zine",
"title": {},
"creator": {}
};
const framed = await jsonld.frame(doc, frame);
This is particularly useful when combining data from multiple sources or creating specific views of your data.
Cross-Profile Linking
When linking between profiles, use full URIs or ensure both contexts are loaded:
{
"@context": [
"https://zinecore.org/v2/context/zinecore2",
"https://zinecore.org/v2/context/agentcore2"
],
"@id": "https://example.org/zines/riot-grrrl",
"@type": "Zine",
"title": "Riot Grrrl",
"creator": {
"@id": "https://example.org/agents/kathleen-hanna",
"@type": "Agent",
"display_name": "Kathleen Hanna",
"agent_kind": "Person"
}
}
This creates a nested representation where the creator is fully resolved.
Linked Data Best Practices
Use Persistent URIs
When creating @id values for your records, use persistent, dereferenceable URIs:
{
"@context": "https://zinecore.org/v2/context/zinecore2",
"@id": "https://archive.example.org/zines/12345",
"title": "Riot Grrrl"
}
Link to External Identifiers
Use identifier with @type for typed identifiers:
{
"identifier": [
{
"@type": "ISBN",
"@value": "978-0-123456-78-9"
},
{
"@type": "OCLC",
"@value": "ocm12345678"
}
]
}
Link to Controlled Vocabularies
When using ZineCore2 vocabularies, you can reference the full vocabulary URIs:
{
"subject": [
{ "@id": "https://zinecore.org/v2/vocab/subjects/feminism" },
{ "@id": "https://zinecore.org/v2/vocab/subjects/punk-culture" }
]
}
Or use the compact form (more common):
{
"subject": ["feminism", "punk-culture"]
}
Both are valid; the context maps codes to full URIs automatically.
Validation and JSON-LD
JSON-LD validation is separate from JSON Schema validation:
- JSON Schema validates structure and data types
- SHACL (Shapes Constraint Language) validates RDF graph structures
For most use cases, JSON Schema validation is sufficient. Use SHACL if you need to validate graph patterns or relationships in an RDF triple store.
Tools and Libraries
JavaScript/TypeScript
- jsonld.js - Full JSON-LD processor
- json-ld-types - TypeScript types for JSON-LD
Python
- PyLD - JSON-LD processor for Python
- rdflib-jsonld - RDFLib JSON-LD plugin
Ruby
- json-ld - Ruby implementation
Java
- Titanium JSON-LD - Java JSON-LD processor
Command Line
- jsonld-cli - Command-line JSON-LD tool
Use Cases
Library Catalogs
Integrate ZineCore2 records with BIBFRAME or Schema.org:
{
"@context": [
"https://zinecore.org/v2/context/zinecore2",
"http://schema.org/"
],
"@type": ["Zine", "CreativeWork"],
"title": "Riot Grrrl",
"creator": ["Kathleen Hanna"]
}
Linked Open Data
Publish ZineCore2 records as part of a linked data cloud, connecting to Wikidata, VIAF, and other authority files:
{
"@context": "https://zinecore.org/v2/context/agentcore2",
"display_name": "Kathleen Hanna",
"wikidata": "http://www.wikidata.org/entity/Q467251",
"orcid": "https://orcid.org/0000-0000-0000-0000"
}
Semantic Search
Use JSON-LD to enable semantic search capabilities:
- Query across multiple metadata schemas
- Discover related resources via linked data
- Integrate with knowledge graphs
Next Steps
- Use the JSON-LD Playground to experiment with expansion and compaction
- Read about JSON Schema validation
- Explore the Vocabulary API for accessing controlled terms as linked data