Enabling reuse of JSD schema elements

Inevitably, the initial syntax for declaring structure in the previous section is clumsy and needs refinement. We also need to start building in the capacity to create reusable elements that are aligned to OO so that we can define schemas efficiently.

Referring back UML, we need to be able to define “Classes” that represent the definition of structure through owned “Properties”. In UML, there are a number of different elements that declare structure other than Classes, such as “Interfaces” and “DataTypes”. In UML, these all inherit a common derivation from “Classifier”, but, for now, we will simply create an array of “classes” that will define the reusable elements of the schema.

At this point, using the JSD for JSD as our primary example may become confusing and so we will adopt a different scenario based on a simple “person” model. If we consider the instance document below:

{
    "$schema": "https://whitecottage.org.uk/person",
    "first-name": "John",
    "last-name": "Doe",
    "age": 58
} 

To define the schema for this instance document, we need to start by creating a “classifier” to define this structure:

{
    "$schema": "https://whitecottage.org.uk/JSD/2025-06/",
    "target-schema": "https://whitecottage.org.uk/person",
    "schema-location": "https://whitecottage.org.uk/person/person.jsd",
    "classes": [
    {
        "name": "person",
        "properties": {
            "first-name": {
                "type": "string"
            },
            "last-name": {
                "type": "string"
            },
            "age": {
                "type": "number"
            }
        }
    }
    ]
}

We are now in a position to use the “person” class to define the type of the root of the JSON document, but we need a way to refer to the class definition. For completeness, we must allow the instance document to take any valid JSON type, but classes necessarily define the structure of objects. One option would be to allow a simple “type” property to be followed by a “class” property if the value of the “type” property is “object”. This fine in that the type declaration and the class identifier are in unambiguous scope (the document itself) but it is, arguably, a little messy as it does not encapsulate all of the data that describes the type (the fact that it is an “object” with a defined “class”). One could consider that all types could benefit from additional qualification, and so a better option might be to implement type specification by using a different property key for each primitive type and making its value an object that then contains any qualifying data. A potential refinement of this approach could be to allow the value of the type specifier to be either an object (in the case of multiple type qualifiers), or a single value type if there is only a single qualifying value (e.g. class name). These three options are illustrated below:

    ...
    "type": "object",
    "class": "person"
    ...

    ...
    "object": {
        "class": "person"
    }
    ...

    ...
    "object": "person"
    ...

For now, we will start with the more verbose second option, noting that we have the option to refine it later. That makes our person.jsd file look like this:

{
    "$schema": "https://whitecottage.org.uk/JSD/2025-06/",
    "target-schema": "https://whitecottage.org.uk/person",
    "schema-location": "https://whitecottage.org.uk/person/person.jsd",
    "classes": [
        {
            "name": "person",
            "properties": {
                "first-name": {
                    "string": {}
                },
                "last-name": {
                    "string": {}
                },
                "age": {
                    "number": {}
                }
            }
        }
    ],
    "object": {
        "class": "person"
    }
}

Thinking back, once again, to the JSD for JSD, another consideration to address when deciding how we define structure is the specification of the property names of an object. The JSON Schema approach we have so far reused is to declare named properties of the “properties” object. This has the significant advantages of being simple and intuitive, but the schema of the “properties” object cannot be defined like this, as the property names of the “properties” object are necessarily not defined by the schema language.

On the one hand, adopting a slightly more verbose approach would not impose the need for the use of unnamed properties, while on the other hand, it is a potentially useful feature for JSD to support. If we were to adopt the more verbose approach, then we would make the “properties” element an array of objects that define properties, thus:

{
    "$schema": "https://whitecottage.org.uk/JSD/2025-06/",
    "target-schema": "https://whitecottage.org.uk/person",
    "schema-location": "https://whitecottage.org.uk/person/person.jsd",
    "classes": [
        {
            "name": "person",
            "properties": [
                {
                    "name": "first-name",
                    "string": {}
                },
                {
                    "name": "last-name",
                    "string": {}
                },
                {
                    "name": "age",
                    "number": {}
                }
            ]
        }
    ],
    "object": {
        "class": "person"
    }
}

What is interesting here is that the “properties” array above does make it easy to specify anonymous yet typed properties, simply by omitting the “name” or making it null. Given that JSON is quite comfortable with interchanging types, we could allow the “properties” element to be either an object or an array in order to support both styles. Furthermore, the required type ambiguity can easily be implemented by allowing multiple definitions for each property that may have values of different types.

While this example demonstrates the potential for reuse through the definition of classes, it also suggests that, similarly to XML Schema, in some cases it may be desirable to allow “anonymous class definitions where all of the structure is declared inline. The Person schema (so far) does not actually define any reuse (let alone polymorphism) and could be represented more simply as:

{
    "$schema": "https://whitecottage.org.uk/JSD/2025-06/",
    "target-schema": "https://whitecottage.org.uk/person",
    "schema-location": "https://whitecottage.org.uk/person",
    "object": {
        "properties": [
            {
                "name": "first-name",
                "string": {}
            },
            {
                "name": "last-name",
                "string": {}
            },
            {
                "name": "age",
                "number": {}
            }
        ]
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.