Download, parse, cache, expand, and compact JSON-LD @context documents. The semantic layer that makes NGSI-LD interoperable across systems and organizations.
fwJsonld is the JSON-LD @context processing engine for the FiWorks stack. It downloads remote @context documents using the fwHttp client, parses them into dual fwHash tables (name→URI and URI→name), caches the result in a thread-safe context cache, and performs full expansion and compaction of NGSI-LD entities.
This is the library that turns short attribute names like "temperature" into fully qualified URIs like "https://uri.fiware.org/ns/data-models#temperature" and back again — the core operation that makes NGSI-LD a linked-data protocol rather than just another JSON API.
schema:name → https://schema.org/namefwJsonld uses trace levels 150–199. See the full trace level table for all assignments across the fw-lib stack.
// Single term definition in a context
typedef struct FwJsonldItem {
char* name; // Short name (e.g., "temperature")
char* id; // Expanded IRI (e.g., "https://uri.etsi.org/ngsi-ld/temperature")
char* type; // Type annotation ("@id", "@vocab", "DateTime", etc.) or NULL
} FwJsonldItem;
// Parsed context with dual hash tables
typedef struct FwJsonldContext {
char* url; // URL of this context (NULL for inline)
KHashTable* nameHT; // name -> FwJsonldItem (for expansion)
KHashTable* valueHT; // IRI -> FwJsonldItem (for compaction)
char* vocab; // @vocab value or NULL
bool isArray; // true = array of child contexts
} FwJsonldContext;
Each context maintains two hash tables: one for expansion (name → IRI) and one for compaction (IRI → name), enabling O(1) lookup in both directions.
int fwJsonldInit(FaAlloc* fwAllocP, const char* coreContextUrl);
void fwJsonldCleanup(void);
Initialize the library: creates the context cache and downloads the NGSI-LD core context. Pass NULL for coreContextUrl to use the default (v1.8). Returns 0 on success, -1 on failure.
| Function | Description |
|---|---|
fwJsonldContextFromTree(contextNode, fwAllocP) | Parse an @context from a FtNode tree — handles string (URL), object (inline), and array forms |
fwJsonldContextFromObject(objectNode, fwAllocP, url) | Parse an inline context object; two-pass algorithm to resolve prefix values |
fwJsonldContextFromUrl(url, fwAllocP) | Download and parse a context URL; checks cache first, deduplicates concurrent downloads |
char* fwJsonldExpand(FwJsonldContext* contextP, const char* name,
FaAlloc* fwAllocP, FwJsonldItem** itemPP);
const char* fwJsonldCompact(FwJsonldContext* contextP, const char* iri);
char* fwJsonldPrefixExpand(FwJsonldContext* contextP, const char* name,
FaAlloc* fwAllocP);
Expansion lookup chain (first match wins):
urn:, http://, https://) — return as-is: — attempt prefix expansion@vocab fallbackFwJsonldContext* fwJsonldCacheLookup(const char* url);
void fwJsonldCacheInsert(FwJsonldContext* contextP);
FwJsonldContext* fwJsonldCoreContext(void);
bool fwJsonldAlreadyExpanded(const char* value);
Per the JSON-LD specification, when a context is an array the last context has highest priority. This means inline context definitions can override definitions from a downloaded core context:
{
"@context": [
"https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.8.jsonld",
{ "temperature": "https://my-override.example.com/temp" }
]
}
Here the inline context overrides any definition of "temperature" from the core context.
#include "fwJsonld/fwJsonld.h"
#include "fwAlloc/FaAlloc.h"
#include "fwJson/fwJson.h"
int main(void)
{
FaAlloc fwAlloc;
char buf[64 * 1024];
faBufferInit(&fwAlloc, buf, sizeof(buf), 32 * 1024, NULL, "main");
// Initialize library (downloads + caches core context)
if (fwJsonldInit(&fwAlloc, NULL) != 0)
return 1;
// Parse an inline @context
char* json = faStrdup(&fwAlloc, "{\"temperature\": \"https://example.com/temp\"}");
FjParser* fwJsonP = fjBufferCreate(NULL, &fwAlloc);
FtNode* tree = kjParse(fwJsonP, json);
FwJsonldContext* ctx = fwJsonldContextFromObject(tree, &fwAlloc, NULL);
// Expand: short name -> full IRI
char* expanded = fwJsonldExpand(ctx, "temperature", &fwAlloc, NULL);
// expanded == "https://example.com/temp"
// Compact: full IRI -> short name
const char* compacted = fwJsonldCompact(ctx, "https://example.com/temp");
// compacted == "temperature"
// Prefix expansion: given context {"schema": "https://schema.org/"}
// fwJsonldExpand(ctx, "schema:name", &fwAlloc, NULL) -> "https://schema.org/name"
fwJsonldCleanup();
return 0;
}