Definitions

A definition in a Metaschema module declares a reusable information element within an information model.

In graph theoretical terms, a definition provides a declaration of a graph node and any associated edges that form a given subgraph shape.

In object-oriented terms, a definition provides a declaration of a class, along with any associated class members.

The following subsections describe the common syntax for all definition types, followed by the semantic and syntax details of each type of definition. The 3 types of definitions are <define-flag>, <define-field>, and <define-assembly>.

Common Definition Data

All definition types share a common syntax composed of the following XML attributes and elements.

Attributes:

AttributeData TypeUseDefault Value
@deprecatedversion (string)optional(no default)
@nametokenrequired(no default)
@scopelocal or globaloptionalglobal

Elements:

ElementData TypeUse
<formal-name>string0 or 1
<description>markup-line0 or 1
<prop>special0 to ∞
<use-name>token0 or 1
<remarks>special0 or 1
<example>special0 to ∞

These attributes and elements are described in the following subsections.

@deprecated Version

The optional @deprecated attribute communicates that use of the given information element implemented by the definition is intended to be discontinued, starting with the information model revision indicated by the attribute’s value.

This attribute’s value MUST be a version string that is equal to or comes before the <schema-version> declared in the Metaschema module header.

Declaring the @deprecated attribute communicates to content creators that all use of the annotated information element is to be avoided. This annotation can be used in documentation generation and in Metaschema-aware tools that provide context around use of the definition.

The following example illustrates deprecating the flag named flag-name starting with the information model semantic version 1.1.0.

1
2
3
<define-flag
  name="flag-name"
  deprecated="1.1.0"/>

@name

The @name attribute provides the definition’s identifier, which can be used in other parts of a module, or in an importing Metaschema module, to reference the definition.

In top-level definitions, this attribute’s value MUST be a token that is unique among sibling definitions of the same type.

Note: The names of flags, fields, and assemblies are expected to be maintained as separate identifier sets. This allows a flag definition, a field definition, and an assembly definition to each have the same name in a given Metaschema module.

@scope

The optional @scope attribute is used to communicate the intended visibility of the definition when accessed by another module through an <import> element.

  • global - Indicates that the definition MUST be made available for reference within importing modules. Definitions in the same and importing modules can reference it. This is the default behavior when @scope is not declared.
  • local - Indicates that the definition MUST NOT be made available for reference within importing modules. Only definitions in the same module can reference it.

Note: References to definitions in the same module are always possible regardless of scope.

The scope of a definition affects how the definition’s name is resolved.

<formal-name>

The optional <formal-name> element provides a human-readable, short string label for the definition for use in documentation.

The <formal-name> label is intended to provide an easy to recognize, meaningful name for the definition.

While not required, it is best practice to include a <formal-name>.

<description>

The optional <description> element is a single line of markup that describes the semantic meaning and use of the definition.

The description ties the definition to the related information element concept in the information domain that the definition is representing. This information is ideal for use in documentation.

While not required, it is best practice to include a <description>.

<prop>

The optional <prop> element provides a structure for declaring arbitrary properties, which consist of a @namespace, @name, and @value.

AttributeData TypeUseDefault Value
@namespaceurioptionalhttp://csrc.nist.gov/ns/oscal/metaschema/1.0
@nametokenrequired(no default)
@valuetokenrequired(no default)

The @name and @namespace is used in combination to define a semantically unique name, represented by the @name attribute, within the managed namespace defined by the @namespace attribute. If the @namespace attribute is omitted, the @name MUST be considered in the http://csrc.nist.gov/ns/oscal/metaschema/1.0 namespace.

The @value attribute represents the lexical value assignment for the semantically unique name represented by the combination of the @name and @namespace. The lexical values of the @value attribute may be restricted for the specific semantically unique name, but such restrictions are not enforced directly in this model.

A property is useful for annotating a definition with additional information that might describe, in a structured way, the semantics, use, nature, or other significant information related to the definition. In many cases, a property might be used to tailor generated documentation or to support an experimental, non-standardized feature in Metaschema.

Naming and <use-name>

The optional <use-name> changes the effective name to use for the information element in a data model.

The <use-name> element is optional and MAY only occur once.

By default the effective name of the information element in a data model is taken from the @name attribute. The <use-name> value overrides this behavior.

Use of a <use-name> frees the module maintainer allowing them to use a sensible @name for the definition, while providing control over the name used in an instance of the definition in a data model.

The first matching condition determines the effective name for the definition:

  1. A <use-name> is provided on the definition. The effective name is the value of the <use-name> element on the definition.
  2. No <use-name> is provided on the definition. The effective name is the value of the @name attribute on the definition.

For example:

1
2
3
<define-flag name="flag-a">
  <use-name>flag-b</use-name>
</define-flag>

In the example above, the effective name of the definition is flag-b. If the <use-name> was omitted, the effective name would be flag-a.

The following content is valid to the model above.

{
  "field": {
    "flag-b": "value"
  }
}
---
field:
  flag-b: "value"
<field flag-b="value"/>

<remarks>

The optional <remarks> element provides a place to add notes related to the use of the definition. Remarks can be used to clarify the semantics of the definition in specific conditions, or to better describe how the definition may be more fully utilized within a model.

The <remarks> element is optional and may occur multiple times.

It supports an optional @class attribute that can be used to identify format specific remarks, to be handled appropriately (or ignored when not useful) in a downstream application. Valid values for @class are:

  • XML: The remark applies to the XML format binding.
  • JSON: The remark applies to the JSON or YAML format bindings.

<example>

The optional <example> element is used to provide inline examples, which illustrate the use of the information element being defined. Examples are provided in XML, which can then be automatically converted into other formats.

The example element is optional and may occur multiple times.

top-level <define-flag>

A flag definition, represented by the <define-flag> element, is used to declare a reusable flag within a Metaschema module.

A flag definition provides the means to implement a simple, named information element with a value.

Flag definitions are leaf nodes in a Metaschema-based model that are intended to represent granular particles of identifying and qualifying information.

The flag’s value is strongly typed using one of the built in simple data types identified by the @as-type attribute.

The syntax of a flag is composed of the following XML attributes and elements.

Attributes:

AttributeData TypeUseDefault Value
@as-typetokenoptionalstring
@defaultstringoptional(no default)
@deprecatedversion (string)optional(no default)
@nametokenrequired(no default)
@scopelocal or globaloptionalglobal

Elements:

ElementData TypeUse
<formal-name>string0 or 1
<description>markup-line0 or 1
<prop>special0 to ∞
<use-name>token0 or 1
<constraint>special0 or 1
<remarks>special0 or 1
<example>special0 to ∞

The attributes and elements specific to the <define-flag> are described in the following subsections. The elements and attributes common to all definitions are defined earlier in this specification.

@as-type

The @as-type attribute declares the type of the flag’s value. If not provided, the default value is string.

The @as-type attribute must have a value that corresponds to one of the simple data types. As a result, markup in flag values is not permitted.

@default

The @default attribute specifies the default value for the flag. When a flag is specified as an optional child of a <define-field> or <define-assembly>, this value SHOULD be considered set for a content instance if the flag is omitted in that instance.

<json-key>

Both the <define-field> and <define-assembly> definition types support the definition of a <json-key>.

A <json-key> is used to identify a flag instance on the definition that is used to group a collection of named model instances with the same name related to the definition when serializing to the JSON format. This is controlled using the group-as element using the in-json="BY_KEY" attribute value.

For more information see using <group-as in-json="BY_KEY">.

top-level <define-field>

A field definition, represented by the <define-field> element, is used to declare a reusable field within a metaschema module.

A field definition provides the means to implement a complex named information element with a value and an optional set of flag instances.

A field definition is an edge node in a Metaschema-based model. Fields are typically used to provide supporting information for a containing assembly definition. The optional flag instances, declared on a field definition, typically characterize or identify the field’s value. With optional use of flags, a field can be more or less complex, depending on the modeling need.

The field’s value is strongly typed using one of the built in simple data types or markup data types identified by the @as-type attribute.

The syntax of an field definition is composed of the following XML attributes and elements.

Attributes:

AttributeData TypeUseDefault Value
@as-typetokenoptionalstring
@collapsibleyes or nooptionalno
@defaultstringoptional(no default)
@deprecatedversion (string)optional(no default)
@nametokenrequired(no default)
@scopelocal or globaloptionalglobal

Elements:

ElementData TypeUse
<formal-name>string0 or 1
<description>markup-line0 or 1
<prop>special0 to ∞
<use-name>token0 or 1
json-keyspecial0 or 1
json-value-key or
json-value-key-flag
special0 or 1
flag or
define-flag
special0 or ∞
<constraint>special0 or 1
<remarks>special0 or 1
<example>special0 to ∞

The attributes and elements specific to the <define-field> are described in the following subsections. The elements and attributes common to all definitions are defined earlier in this specification.

@as-type

The optional @as-type attribute declares the type of the field’s value. If not provided, the default type is string.

The @as-type attribute must have a value that corresponds to one of the built in simple data types or markup data types.

@collapsible

The optional @collapsible attribute controls a JSON and YAML specific behavior that allows multiple fields having the same set of flag values to be collapsed into a single object with a value property that is an array of values. This makes JSON and YAML formatted data more concise.

If @collapsible is not specified, the default value is no.

The following behaviors are REQUIRED to be used for each value of @collapsible.

  • no - Do not collapse. This is the default behavior when @collapsible is not declared.
  • yes - Collapse values that have flags with equivalent values.

A flag value is equivalent if the value, or default value if not provided, is an exact match. A non-default flag is considered to have no value and will match the same flag on another instance that has no value.

Field instances whose flags all match are considered to be in the same collapse group. Collapsing works by combining the values for all the instances in the the same collapse group.

When collapsing values in the same collapse group the ordering of the field values MUST be in the same order as their original field instances. The ordering of all collapse groups MUST follow the ordering of the first field instance added to the collapse group.

For example, given field instances in the sequence { A, B, C, D }, if { A, C } are a collapse group, and { B, D } are a different collapse group. Then { A, C } would be ordered before { B, D }, since A is ordered before B.

Note: Collapsing may affect the relative ordering of field instances. If two field instances are non-adjacent and their flags match, then the later field instance will be moved to be adjacent to the first. Do not use the collapsible feature if maintaining field sequences is important to your use.

An example a collapsible field definition might look like the following.

<define-assembly name="assembly">
  <root-name>assembly</root-name>
  <model>
    <define-field name="field" max-occurs="unbounded" collapsible="yes">
      <group-as name="fields" in-json="ARRAY"/>
      <define-flag name="flag-default-a" default="a"/>
      <define-flag name="flag-required" required="yes"/>
      <define-flag name="flag-optional"/>
    </define-field>
  </model>
</define-assembly>

An example set of content instances follow. XML is provided first to illustrate the use of uncollapsed fields, since this feature applies to JSON and YAML only. The JSON and YAML collapsed versions follow.

1
2
3
4
5
<assembly>
  <field flag-required="required 1">field-value-1</field>
  <field flag-required="required 2">field-value-2</field>
  <field flag-default-a="a" flag-required="required 1">field-value-3</field>
</assembly>

The XML example above illustrates 2 fields, on lines 2 and 4, which will be collapsed together into the same collapse group in the resulting JSON and YAML conversion. This is because they have the same flag values: a for the flag named flag-default-a, required 1 for the flag named flag-required, and no value for the flag named flag-optional. The field on line 3 would be in a second collapse group.

When converted to JSON or YAML, these fields will be collapsed based on their collapse grouping, resulting in the following content instances.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
{
"assembly": {
  "fields": [
    {
      "flag-required": "required 1",
      "STRVALUE": [ "field-value-1", "field-value-3"]
    },
    {
      "flag-required": "required 2",
      "STRVALUE": "field-value-2"
    }
  ]
}
1
2
3
4
5
6
7
8
9
---
assembly:
  fields:
  - flag-required: "required 1"
    STRVALUE:
    - "field-value-1"
    - "field-value-3"
  - flag-required: "required 2"
    STRVALUE: "field-value-2"

If the JSON or YAML instance is converted back to XML, the sequencing of the fields will change due to use of the collapsible feature as follows.

1
2
3
4
5
<assembly>
  <field flag-required="required 1">field-value-1</field>
  <field flag-required="required 1">field-value-3</field>
  <field flag-required="required 2">field-value-2</field>
</assembly>

In the example above, the fields from the first collapse group would appear before the fields from the second collapse group. This is because the resulting JSON and YAML instance has no way of indicating the original sequencing, so it must rely on the sequencing provided by the ordering of the collapse groups and the values within each group.

@default

The @default attribute specifies the default value for the field. When a flag is specified as an optional child of a <define-field> or <define-assembly>, this value should be considered set for a content instance if the field is omitted in that instance.

A @defaultvalue MUST only be provided when the data type specified by the @as-type is a simple data types. Specifying a @default value for a markup data type MUST result in a Metaschema format error.

Implementations when writing content instances MAY omit writing default values in order to produce a more concise expression of the content.

<flag> Instance Children

A field may have zero or more flag instance children.

See flag instances

<define-flag> Inline Definition

See inline <define-flag>.

JSON Value Keys

TODO: P2: discuss use only when flags may be present. TODO: P2: Address issue https://github.com/usnistgov/metaschema/issues/316

In XML, the value of a field appears as the textual data content of the field’s element. In JSON and YAML, a property name is needed for the value. The <json-value-key> and <json-value-key-flag> elements provide a means to control the behavior of how this value is represented.

If no <json-value-key> or <json-value-key-flag> element is declared, a property name value will be chosen based on the data type as follows:

  • If the field’s @as-type is markup-line, then the property name will be RICHTEXT.
  • If the field’s @as-type is markup-multiline, then the property name will be prose.
  • Otherwise, the property name will be STRVALUE.

This logic may result in less than ideal property names. Metaschema provides the and` elements to override this behavior. Use of these elements are mutually exclusive.

The following subsections describe the use of these elements.

<json-value-key>

The <json-value-key> element can be declared to set the property name for the field’s value. Its text value child MUST be used as the property name for the field’s value.

For example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<define-assembly name="assembly">
  <root-name>assembly</root-name>
  <model>
    <define-field name="field" max-occurs="unbounded">
      <json-value-key>value</json-value-key>
      <group-as name="fields" in-json="ARRAY"/>
      <define-flag name="flag-default-a" default="a"/>
    </define-field>
  </model>
</define-assembly>

Would allow the following content in JSON and YAML.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
  "assembly": {
    "fields": [
      {
        "flag-default-a": "b",
        "value": "value1"
      }
    ]
  }
}
1
2
3
4
5
---
assembly:
  fields:
  - flag-default-a: "b"
    value: "value1"

<json-value-key-flag>

The <json-value-key> element can be declared to use the value of specific flag on the field as the property name for the field’s value.

The @flag-name attribute MUST reference the name of a flag on the field whose value is to be used as the property name.

This results in a property that is a combination of the referenced flag’s value and the field’s value.

For example:

TODO: P2: complete this example.

top-level <define-assembly>

An assembly definition, represented by the <define-assembly> element, is used to declare a reusable assembly within a Metaschema module.

An assembly definition provides the means to implement a complex, composite, named information element that collects and organizes other information elements, with no value of its own.

An assembly definition consists of an optional set of flags and an optional sequence of model instances.

An assembly definition is a compositional node in a Metaschema-based model. Assemblies are typically used to represent complex data objects, combining multiple information elements together into a composite object representing a larger semantic concept. An assembly’s flag instances will typically characterize or identify this composite object, while its model instances represent the information being composed.

An assembly is similar to a field, except it contains structured content (objects or elements), not text or unstructured “rich text.” The contents permitted in a particular (type of) assembly are indicated in its model element.

An assembly definition has no value, so the @as-type and @default attributes are not permitted.

The syntax of an assembly definition is composed of the following XML attributes and elements.

Attributes:

AttributeData TypeUseDefault Value
@deprecatedversion (string)optional(no default)
@nametokenrequired(no default)
@scopelocal or globaloptionalglobal

Elements:

ElementData TypeUse
<formal-name>string0 or 1
<description>markup-line0 or 1
<prop>special0 to ∞
<use-name> or
<root-name>
token0 or 1
json-keyspecial0 or 1
flag or
define-flag
special0 or ∞
<model>special0 or 1
<constraint>special0 or 1
<remarks>special0 or 1
<example>special0 to ∞

The attributes and elements specific to the <define-assembly> are described in the following subsections. The elements and attributes common to all definitions are defined earlier in this specification.

<root-name>

Declares the name to use when using the assembly as a top-level information element. Indicates that the assembly is an allowable root.

For example:

1
2
3
<define-assembly name="assembly">
  <root-name>assembly</root-name>
</define-assembly>

Would allow the following content in JSON, YAML, and XML.

1
2
3
{
  "assembly": { }
}
1
2
---
assembly: -
1
<assembly/>

<flag> Instance Children

An assembly may have zero or more flag instance children.

See flag instances.

<define-flag> Inline Definition

An assembly may have zero or more flag instance children, which can be inline definitions.

See inline <define-flag>.

<model>

The <model> element is used to establish the assembly’s model. To do this, zero or more model instances are declared.

Zero or more of the following elements are allowed.