-
Notifications
You must be signed in to change notification settings - Fork 2
NIEM JSON normalization
We want JSON data to be as simple as possible, without sacrificing the ability for anyone who understands NIEM to understand the data. JSON-LD goes a long way, but there are a couple of issues:
- We want to enable developers to omit "@context" on messages, when the message is identified as a message defined by a message specification that provides a context.
- We want to enable the use of literal (vs. object) values in messages, for simplicity, in cases where it doesn't match the NIEM data model.
In short, we want to support messages that look like this:
{
"person": {
"age": {
"decimalValue": 42.5,
"unit": "ANN"
},
"birth": {
"date": "1978-01-01"
}
}
}We don't want to require that messages look like this:
{
"@context": {
"nc": "http://release.niem.gov/niem/niem-core/5.0/#",
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
"unece": "http://release.niem.gov/niem/codes/unece_rec20/5.0/#",
"xs": "http://www.w3.org/2001/XMLSchema#"
},
"nc:Person": {
"nc:PersonAgeMeasure": {
"unece:TimeUnitCode": {
"rdf:value": {
"@value": "ANN",
"@type": "xs:token"
}
},
"nc:MeasureDecimalValue": {
"rdf:value": {
"@value": "42.5",
"@type": "xs:decimal"
}
}
},
"nc:PersonBirthDate": {
"nc:Date": {
"rdf:value": {
"@value": "1978-01-01",
"@type": "xs:date"
}
}
}
}
}We make the plain NIEM JSON document fully conformant to JSON-LD and the NIEM data model through a process called NIEM JSON normalization. This process yields a NIEM JSON-LD document.
We define NIEM JSON normalization which performs the following transformations
- Apply the context to the JSON data
- Convert literals to objects with typed values
This process enables plain old json objects to be converted to best-practice JSON-LD.
Question for later: is there a simpler syntax for named graphs (to support @structures:relationshipMetadata that could be applied in this process?
Note: We're using the term "JSON document" analagous to "XML document", even though it's not necessarily a document. The JSON RFC (RFC 8259) uses the term "JSON text", which is awkward. The JSON Schema specification uses "JSON document".
We expect a JSON-LD context to be a part of a message specification for a JSON exchange. We don't want to add JSON-LD contexts inline to runtime data. We also don't really want to clutter up JSON data with @context properties.
This step applies the context from the message specification to an instance.
In the NIEM JSON Specification v4.0, we specified literal-to-object conversion.
This step extends that process by providing for explicit typing, applying RDF-friendly XML Schema data types.
Take this XML data:
<?xml version="1.0" encoding="US-ASCII"?>
<nc:PersonBirthDate xmlns:nc="http://release.niem.gov/niem/niem-core/5.0/">
<nc:Date>1978-01-01</nc:Date>
</nc:PersonBirthDate>
As an example, this Plain NIEM JSON represents the same data:
{
"birth": {
"date": "1978-01-01"
}
}This context is provided for the plain JSON:
{
"nc": "http://release.niem.gov/niem/niem-core/5.0/#",
"birth": "nc:PersonBirthDate",
"date": "nc:Date"
}After step 1, with the context applied (and using a context defining namespaces for readability), the result is:
{
"@context": {
"nc": "http://release.niem.gov/niem/niem-core/5.0/#"
},
"nc:PersonBirthDate": {
"nc:Date": "1978-01-01"
}
}Step 2, literal-to-object conversion, consists of:
-
Iterate over each property that has a literal value, where the property's definition requires an object value
-
Identify the nearest base type that appears within the list of RDF-compatible XSD types provided by RDF Concepts Section 5.1, The XML Schema Built-in Datatypes
-
Replace the literal value of the property with an object that follows the template, where:
-
$literal-valueis the literal value -
$typeis the nearest base type on the list
{ "rdf:value": { "@value": "$literal-value", "@type": "$type" } } -
Property nc:Date is defined by the NIEM data model to be an object type, with a simple value of type xs:date, which is on the list of RDF-compatible XSD types. Converting yields:
{
"@context": {
"nc": "http://release.niem.gov/niem/niem-core/5.0/#",
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
"xs": "http://www.w3.org/2001/XMLSchema#"
},
"nc:PersonBirthDate": {
"nc:Date": {
"rdf:value": {
"@value": "1978-01-01",
"@type": "xs:date"
}
}
}
}
Take the following XML example:
<?xml version="1.0" encoding="US-ASCII"?>
<nc:Person xmlns:nc="http://release.niem.gov/niem/niem-core/5.0/"
xmlns:unece="http://release.niem.gov/niem/codes/unece_rec20/5.0/">
<nc:PersonAgeMeasure>
<nc:MeasureDecimalValue>42.5</nc:MeasureDecimalValue>
<unece:TimeUnitCode>ANN</unece:TimeUnitCode>
</nc:PersonAgeMeasure>
<nc:PersonBirthDate>
<nc:Date>1978-01-01</nc:Date>
</nc:PersonBirthDate>
</nc:Person>We'd like to enable a very simple JSON representation, utilizing properties preferred by the developers of the message specification:
{
"person": {
"age": {
"decimalValue": 42.5,
"unit": "ANN"
},
"birth": {
"date": "1978-01-01"
}
}
}This can be facilitated with a context:
{
"nc": "http://release.niem.gov/niem/niem-core/5.0/#",
"unece": "http://release.niem.gov/niem/codes/unece_rec20/5.0/#",
"person": "nc:Person",
"age": "nc:PersonAgeMeasure",
"decimalValue": "nc:MeasureDecimalValue",
"unit": "unece:TimeUnitCode",
"birth": "nc:PersonBirthDate",
"date": "nc:Date"
}JSON-LD compaction yields the following JSON-LD instance. For maximum readability, we here use a context that only has aliases for namespaces. playground link
{
"@context": {
"nc": "http://release.niem.gov/niem/niem-core/5.0/#",
"unece": "http://release.niem.gov/niem/codes/unece_rec20/5.0/#"
},
"nc:Person": {
"nc:PersonAgeMeasure": {
"unece:TimeUnitCode": "ANN",
"nc:MeasureDecimalValue": 42.5
},
"nc:PersonBirthDate": {
"nc:Date": "1978-01-01"
}
}
}
Within this instance, there are 3 places where the values are literals, but the NIEM data model says they should be objects:
-
unece:TimeUnitCode, which has a string literal, but should have an object with a value based onxs:token. -
nc:MeasureDecimalValue, which has a number literal, but should have an object with a value based onxs:decimal. Note that JSON-LD by default will type a non-integer number literal asxs:double. -
nc:Date, which has a string literal, but should have an object with a value of typexs:date.
Step 2: literal-to-object conversion
This stage converts literal values to objects holding properly-typed literal values. Each step includes examples from above.
-
Iterate over each property that has a literal value, where the property's definition requires an object value
- In the above example,
unece:TimeUnitCode,nc:MeasureDecimalValue, andnc:Datehave literal values that should be objects.
- In the above example,
-
On each property, identify the expected simple type of the simple content of the property according to the NIEM data model.
-
unece:TimeUnitCodehas typeunece:TimeCodeType, which has simple content of typeunece:TimeCodeSimpleType. -
nc:MeasureDecimalValuehas typeniem-xs:decimal, which has simple content of typexs:decimal. -
nc:Datehas typeniem-xs:date, which has simple content of typexs:date.
-
-
Identify the nearest base type that appears within the list provided by RDF Concepts Section 5.1, The XML Schema Built-in Datatypes
-
unece:TimeCodeSimpleTyperestrictsxs:token, which is on the list. -
xs:decimalis on the list. -
xs:dateis on the list.
-
-
Replace the literal value of the property with an object that follows the template, where:
-
$literal-valueis the literal value -
$typeis the nearest base type on the list
{ "rdf:value": { "@value": "$literal-value", "@type": "$type" } }-
For example, replace
"unece:TimeCode": "ANN"with:"unece:TimeCode: { "rdf:value": { "@value": "ANN", "@type": "xs:token" } }The remaining properties appear in the full instance below.
-
{
"@context": {
"nc": "http://release.niem.gov/niem/niem-core/5.0/#",
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
"unece": "http://release.niem.gov/niem/codes/unece_rec20/5.0/#",
"xs": "http://www.w3.org/2001/XMLSchema#"
},
"nc:Person": {
"nc:PersonAgeMeasure": {
"unece:TimeUnitCode": {
"rdf:value": {
"@value": "ANN",
"@type": "xs:token"
}
},
"nc:MeasureDecimalValue": {
"rdf:value": {
"@value": "42.5",
"@type": "xs:decimal"
}
}
},
"nc:PersonBirthDate": {
"nc:Date": {
"rdf:value": {
"@value": "1978-01-01",
"@type": "xs:date"
}
}
}
}
}