<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Archiving and Interchange DTD v1.0 20120330//EN" "JATS-archivearticle1.dtd">
<article xmlns:xlink="http://www.w3.org/1999/xlink">
  <front>
    <journal-meta />
    <article-meta>
      <title-group>
        <article-title>A Proposal for an OpenMath JSON Encoding</article-title>
      </title-group>
      <contrib-group>
        <contrib contrib-type="author">
          <string-name>Tom Wiesing</string-name>
          <xref ref-type="aff" rid="aff0">0</xref>
        </contrib>
        <contrib contrib-type="author">
          <string-name>Michael Kohlhase</string-name>
          <xref ref-type="aff" rid="aff0">0</xref>
        </contrib>
        <contrib contrib-type="author">
          <string-name>Computer Science</string-name>
          <xref ref-type="aff" rid="aff0">0</xref>
        </contrib>
        <contrib contrib-type="author">
          <string-name>FAU Erlangen-Nurnberg</string-name>
          <xref ref-type="aff" rid="aff0">0</xref>
        </contrib>
        <contrib contrib-type="author">
          <string-name>Germany http://kwarc.info</string-name>
          <xref ref-type="aff" rid="aff0">0</xref>
        </contrib>
        <aff id="aff0">
          <label>0</label>
          <institution>Copyright c by the paper's authors. Copying permitted for private and academic purposes. In: O. Hasan</institution>
          ,
          <addr-line>J. Davenport, M. Kohlhase</addr-line>
          ,
          <institution>(eds.): Proceedings of the 29th Openmath Workshop</institution>
          ,
          <addr-line>Hagenberg, 2018, published at</addr-line>
        </aff>
      </contrib-group>
      <pub-date>
        <year>2020</year>
      </pub-date>
      <abstract>
        <p>OpenMath is a semantic representation format of mathematical objects and formulae. There are several encodings of OpenMath Objects, most notably the XML and Binary encodings. In this paper we propose another one based on JSON { a lightweight data-interchange format used heavily in the Web Applications area. We survey two existing OpenMath JSON encodings already and show how their advantages can be combined and their disadvantages be alleviated. We give a thorough speci cation of the encoding, present a JSON schema implemented in TypeScript, and provide a web service that validates JSONencoded OpenMath and transforms OpenMath objects between XML and JSON encodings.</p>
      </abstract>
    </article-meta>
  </front>
  <body>
    <sec id="sec-1">
      <title>Introduction</title>
      <p>Primitive JSON data types are strings (e.g. "Hello world"), Numbers (e.g. 42 or
3.14159265), Booleans (true and false) and null. Composite JSON types are either
(non-homogeneous) arrays (e.g. [1, "two", false]) or key-value pairs called objects (e.g.
{"foo": "bar", "answer": 42}).</p>
      <p>Constructs corresponding to JSON objects are found in most programming languages.
Furthermore, the syntax is very simple; hence many languages have built-in facilities for translating
their existing data structures to and from JSON. The use for an OpenMath JSON encoding is
clear: It would enable easy use of OpenMath across many languages.</p>
      <p>In the next Section we survey two existing OpenMath JSON encodings. Section 3 proposes
a new encoding that combines the advantages and alleviates their disadvantages. We give a
thorough speci cation of the encoding, present a JSON schema implemented in TypeScript,
and provide a web service that validates JSON-encoded OpenMath and transforms OpenMath
objects between XML and JSON encodings. Section 5 concludes the paper.
2</p>
      <p>Existing JSON Encodings for OpenMath
There are existing approaches for encoding OpenMath as JSON. We will discuss two particular
ones here.</p>
      <sec id="sec-1-1">
        <title>XML as JSON</title>
        <p>The JSONML standard [jsonml:webpage] allows generic encoding of arbitrary XML as JSON.
This can easily be adapted to the case of OpenMath. To encode an OpenMath object as JSON,
one rst encodes it as XML and then makes use of JSONML in a second step. Using this
method, the term plus(x; 5) would correspond to:
"OMS",
{"cd": "arith1", "name": "plus"}
"OMA",
[
"OMI",
"5"</p>
        <p>This translation has the advantage that it is near-trivial to translate between the XML and</p>
      </sec>
      <sec id="sec-1-2">
        <title>JSON encodings of OpenMath. It also has some disadvantages:</title>
        <p>The encoding does not use the native JSON datatypes. One of the advantages of JSON is
that it can encode most basic data types directly, without having to turn the data values
into strings. To encode the oating point value 1e-10 (a valid JSON number literal) using
the JSONML encoding, one can not directly place it into the result. Instead, one has to turn
it into a string rst. Despite many JSON implementations providing such a functionality,
in practice this would require frequent translation between strings and high-level datatypes.
This is not what JSON is intended for, instead the provided data types should be used.
The awkwardness of some of the XML encoding remains. Due to the nature of XML the
XML encoding sometimes needs to introduce elements that do not directly correspond to
any OpenMath objects. For example, the OMATP element is used to encode a set of
attribute / value pairs. This introduces unnecessary overhead into JSON, as an array of
values could be used instead.</p>
        <p>Many languages use JSON-like structures to implement structured data types. Thus it
stands to reason that an OpenMath JSON encoding should also provide a schema to allow
languages to implement OpenMath easily. This is not the case for a JSONML encoding.</p>
      </sec>
      <sec id="sec-1-3">
        <title>OpenMath-JS</title>
        <p>{
"t":"a",
"c": [</p>
        <p>{
The openmath-js [openmathjs:webpage] encoding takes a di erent approach. It is an
(incomplete) implementation of OpenMath in JavaScript and was developed by Nathan Carter for use
with Lurch [CarterMonks:OM:CICM-WS-WiP2013] on the web. It is written in literate
co ee script, a derivative language of JavaScript.</p>
        <p>In this encoding, the term plus(x; 5) would correspond to:
}
},
{
}
"t":"sy",
"cd":"arith1",
"n":"plus"
"t":"v",
"n":"x"
"t":"i",
"v":"5"</p>
        <p>This encoding solves some of the disadvantages of the JSONML encoding, however it still has
some drawbacks:</p>
        <p>It was written as a JavaScript, not JSON, encoding. The existing library provides JavaScript
functions to encode OpenMath objects. However, the resulting JSON has only minimal
names. This makes it di cult for humans to read and write directly.</p>
      </sec>
      <sec id="sec-1-4">
        <title>No formal schema exists, like in the JSONML encoding.</title>
        <p>3</p>
        <p>The OpenMath-JSON encoding
Given the disadvantages with the existing encodings we propose a new one that combines the
advantages and alleviates the problems. In particular, the new encoding should be close to the
OpenMath XML encoding, and at the same time make use of native JSON concepts.</p>
        <p>Furthermore, we want to formalize this encoding by providing a JSON schema for easy
validation, which is not achieved by any existing approach.</p>
        <p>Concretely, we will use JSON Schema [handrewsjsonschema:18]. This de nes a vocabulary
allowing us to validate and annotate JSON documents. Additionally, tools for programatic
veri cation exist in many languages.</p>
        <p>Unfortunately, JSON schema is often tedious to read and write for humans. This is
especially true when it comes to recursively de ned data structures. OpenMath has many recursive
structures. Instead of writing our encoding in JSON Schema directly, we decided to write the
schema in a di erent language and then compile it to JSON Schema.</p>
        <p>For this purpose, we decided to make use of TypeScript [typescript:webpage]. TypeScript
is a language derived from JavaScript { TypeScript les are JavaScript plus type annotations.
As such, it can be easily written and understood by humans. On top of TypeScript, we make
use of a compiler [vega-ts-jscon-schema-generator:webpage] from TypeScript de nitions
into JSON Schema.</p>
      </sec>
      <sec id="sec-1-5">
        <title>In general, objects in our encoding look similar to the following:</title>
        <p>{
}
"kind": "OMV",
"id": "something",
"name": "x"</p>
        <p>The kind attribute speci es which kind of OpenMath object this is. These values correspond
to the element names used in the XML encoding. This correspondence lays the foundations
of easy translation between the two. In TypeScript this property is also referred to as a Type</p>
      </sec>
      <sec id="sec-1-6">
        <title>Guard, because it guards the type of object that is represented. As in the XML encoding it is possible to make use of structure sharing. For this purpose the id attribute can be used. We will come back to this in more detail below, when we de ne to the OMR type.</title>
        <p>In the following we will go over the details of our encoding. For this we will make use of
a TypeScript-like syntax, that is easily readable. In our description we omit the id attribute,
which can be added to any encoded object. The complete source code of our encoding { and
details on how to use it { can be found on Github [URL:openmathjson:github].
"kind": "OMOBJ",
/** optional version of openmath being used */
"openmath"?: "2.0",
/** the actual object */
"object": omel /* any element */
Concretely, the integer 3 encapsulated in an object constructor using this encoding is as follows:
"kind": "OMOBJ",
"openmath": "2.0",
"object": {
"kind": "OMI",
"integer": 3
}</p>
      </sec>
      <sec id="sec-1-7">
        <title>Let us have a look at this rst example attribute for attribute.</title>
        <p>The rst attribute { kind { represents the type of OpenMath object in question. Notice that
it occurs twice { once in the OMOBJ and a second time in the wrapped OMI. We will talk in detail
about integer representation below, and hence only care about this rst one.</p>
        <p>The second attribute { openmath { is de ned as optional by our schema. This indicates the
version of OpenMath that is being used { "2.0" in our case.</p>
        <p>The third and nal attribute is the object attribute. This contains the wrapped object {
it is de ned as of omel type. This type omel can contain any OpenMath object { concretely
primitive objects (Symbols OMS, Variables OMV, Integers OMI, Floats OMF, Bytes OMB, Strings
OMSTR), composite objects (Application OMA, Attribution OMATTR, Binding OMBIND) or Errors</p>
      </sec>
      <sec id="sec-1-8">
        <title>OME and References OMR. In this particular case, we just have the integer 3.</title>
        <p>3.2</p>
        <sec id="sec-1-8-1">
          <title>Symbols { OMS</title>
          <p>An OpenMath Symbol is encoded as follows:
"kind": "OMS",
/** the base for the cd, optional */
"cdbase"?: uri, /* any valid URI */,
/** content dictonary the symbol is in, any name */
"cd": name,
/** name of the symbol */
"name": name /* any valid symbol name */</p>
          <p>Notice the uri and name types in the de nition. These are not directly JSON types. We
de ne the uri type to be a any JSON string that represents a valid URI. Similarly, we de ne
the name type to be any JSON string that represents a valid symbol name.</p>
        </sec>
      </sec>
      <sec id="sec-1-9">
        <title>For example to encode the sin symbol from the transc1 CD:</title>
        <p>"kind": "OMV",
/** name of the variable */
"name": name</p>
      </sec>
      <sec id="sec-1-10">
        <title>We again make use of the name type here. For example to encode a variable x:</title>
        <p>"kind": "OMV",
"name": "x"
3.4 Integers { OMI
"kind": "OMI",
//
// exactly one of the following
//
/* any json integer */
"integer": integer,
/* any string matching ^-?[0-9]+$ */
"decimal": decimalInteger,
/* any string matching ^-?x[0-9A-F]+.$ */
"hexadecimal": hexInteger
Unlike the previous elements, our encoding allows integers to be encoded in three di erent ways.</p>
      </sec>
      <sec id="sec-1-11">
        <title>In particular, we de ne them as follows:</title>
      </sec>
      <sec id="sec-1-12">
        <title>We allow integers to be represented as one of the following: JSON Integers Representing an OpenMath Integer as a JSON integer allows making use of datatypes that JSON o ers. This was one of the goals we wanted to achieve with our encoding.</title>
        <p>JSON has no integer type in and of itself { it only provides a number type. To work around
this in our schema, we de ne a custom integer type by restricting the number type to</p>
        <p>OpenMath integers can be of arbitrary size. While the JSON speci cation does not limit
the size of numbers, it also allows any implementation the freedom to pick some limit. Thus
this representation only work well for reasonably sized integers. But for larger numbers,
the other two variants should be used.</p>
        <p>Decimal Strings A second way to encode an OpenMath Integer is to make use of the
straightforward decimal string encoding. This is any string consisting only of digits (and potentially
having a minus sign in the case of a negative integer).</p>
        <p>Hexademical String We can allow to encode an OpenMath Integer as a hexadecimal integer.</p>
        <p>To make this di erent from decimally encoded integers, we require a lower-case x to be
placed before the string. This also has the advantage that this corresponds exactly to the</p>
      </sec>
      <sec id="sec-1-13">
        <title>XML encoding. We can thus encode the integer 120 in three di erent ways:</title>
        <p>{
}
{
as a JSON integer
{
}
"kind": "OMI",
"integer": -120
as a decimal-encoded string
"kind": "OMI",
"decimal": "-120"
as a hexadecimal-encoded string
"kind": "OMI",
"hexadecimal": "-x78"
Like integers, we allow oats to be encoded in three di erent ways:
//
// exactly one of the following
//
/* any json number */
"float": number,
/* any string matching</p>
        <p>(-?)([0-9]+)?(\.[0-9]+)?([eE](-?)[0-9]+)? */
"decimal": decimalFloat,
/* any string matching ^([0-9A-F]+)$ */
"hexadecimal": hexFloat</p>
      </sec>
      <sec id="sec-1-14">
        <title>Here, the di erent cases work exactly like in the integer case. We can represent a oat either as a native JSON number, a string in decimal representation or a string in hexadecimal representation. Just like above, the string representations correspond to the ones allowed by the XML encoding.</title>
        <p>For example the oating point number 10 10 can be represented in three di erent ways:
{
}
{
}
{
as a JSON oat
"kind": "OMF",
"float": 1e-10
as a decimal-encoded string
"kind": "OMF",
"decimal": "0.0000000001"
as a hexadecimal-encoded string
"kind": "OMF",
"hexaecimal": "3DDB7CDFD9D7BDBB"
3.6</p>
        <sec id="sec-1-14-1">
          <title>Bytes { OMB</title>
          <p>Bytes can be encoded in two di erent ways:
"kind": "OMB",
//
// exactly one of the following
//
/** an array of bytes</p>
          <p>where a byte is an integer from 0 to 255 */
"bytes": byte[],
/** a base64 encoded string */
"base64": base64string
Array of bytes This encoding again makes use of JSON data structures { representing bytes
as a concrete list of bytes. As the byte datatype does not exist directly in JSON, we
represent a single byte as an integer between 0 and 255 (inclusive).</p>
          <p>Base64 encoded string A base64-encoded string of bytes corresponds to the XML encoding.</p>
          <p>For example we can encode the ascii bytes of the string hello world
as a byte array
"kind": "OMB",
"bytes": [
104, 101, 108, 108, 111, 32,
119, 111, 114, 108, 100
as a base64-encoded string
"kind": "OMB",
"base64": "aGVsbG8gd29ybGQ="
3.7</p>
        </sec>
        <sec id="sec-1-14-2">
          <title>Strings { OMS</title>
          <p>The encoding of strings is straightforward { we can make use of native JSON strings.
"kind": "OMSTR",
/** the string */
"string": string</p>
        </sec>
      </sec>
      <sec id="sec-1-15">
        <title>Thus the string "Hello world" is encoded as follows:</title>
        <p>"kind": "OMSTR",
"string": "Hello world"
3.8</p>
        <sec id="sec-1-15-1">
          <title>Applications { OMA</title>
          <p>OpenMath Applications are encoded as follows:
"kind": "OMA",
/** the base for the cd, optional */
"cdbase"?: uri,
/** the term that is being applied */
"applicant": omel,
/** the arguments that the applicant
is being applied to. Optional and
assumed to be empty if omitted */
"arguments"?: omel[]</p>
        </sec>
      </sec>
      <sec id="sec-1-16">
        <title>Here we again make use of the already known omel and uri types. For example when encoding sin(x) we get:</title>
        <p>"kind": "OMA",
"applicant": {
"kind": "OMS",
"cd": "transc1",
"name": "sin"
},
"arguments": [{
"kind": "OMV",
"name": "x"
}]
3.9</p>
        <sec id="sec-1-16-1">
          <title>Attributions { OMATTR</title>
        </sec>
      </sec>
      <sec id="sec-1-17">
        <title>OpenMath Attributions are encoded as follows:</title>
        <p>"kind": "OMATTR",
/** the base for the cd, optional */
"cdbase": uri,
/** attributes attributed to this object, non-empty */
"attributes": ([</p>
        <p>OMS, omel|OMFOREIGN
])[],
/** object that is being attributed */
"object": omel</p>
        <sec id="sec-1-17-1">
          <title>Bindings { OMB</title>
          <p>We encode bindings as:
"kind": "OMBIND",
/** the base for the cd, optional */
"cdbase"?: uri,
/** the binder being used */
"binder": omel,
/** the variables being bound, non-empty */
"variables": (OMV | attvar)[],
/** the object that is being bound */
"object": omel</p>
          <p>Note that each attribute is represented as a pair of the name of the attribute and its
corresponding value. This gives us the attributes property in the de niton above being an array of
pairs. Here we have a somewhat signi cant derivation from the XML encoding. This introduced
an extra element OMATP to represent the pairs { this is not necessary for our case.</p>
        </sec>
      </sec>
      <sec id="sec-1-18">
        <title>As an example, to attribute a variable x as having real type:</title>
        <p>"kind": "OMATTR",
"attributes": [
[
{ "kind": "OMS", "cd": "ecc", "name": "type" },
{ "kind": "OMS", "cd": "ecc", "name": "real" }
Here, the variables property is de ned as a non-empty array of
a variable OMV, or
an attributed variable (the type attvar), that is an OMATTR with the object being
attributed being a variable.
{
}
{
}</p>
        <p>For example to encode x: sin(x):
"kind": "OMBIND",
"binder":</p>
        <p>{ "kind": "OMS", "cd": "fns1", "name": "lambda" },
"variables": [</p>
        <p>{ "kind": "OMV", "name": "x" }
],
"object": {
"kind": "OMA",
"applicant":</p>
        <p>{ "kind": "OMS", "cd": "transc1", "name": "sin" },
"arguments": [</p>
        <p>{ "kind": "OMV", "name": "x" }
}
3.11</p>
        <sec id="sec-1-18-1">
          <title>Errors { OME</title>
        </sec>
      </sec>
      <sec id="sec-1-19">
        <title>An OpenMath Error is encoded as follows:</title>
        <p>"kind": "OME",
/** the error that has occured */
"error": OMS,
/** arguments to the error, optional */
"arguments"?: (omel|OMFOREIGN)[]</p>
        <p>For example, to annotate a division by zero error in x=0:
3.12</p>
        <sec id="sec-1-19-1">
          <title>Foreign Objects { OMFOREIGN</title>
          <p>An OpenMath Foreign Object is an object that is not part of OpenMath. In JSON, we can
encode one such object as follows:
"kind": "OME",
"error":
{ "kind": "OMS", "cd": "aritherror",</p>
          <p>"name": "DivisionByZero" },
"arguments": [{
"kind": "OMA",
"applicant": { "kind": "OMS", "cd": "arith1",</p>
          <p>"name": "divide" },
"arguments": [
{ "kind": "OMV", "name": "x" },
{ "kind": "OMI", "integer": 0}
"kind": "OMFOREIGN",
/** encoding of the foreign object, optional */
"encoding"?: string,
/** the foreign object */
"foreign": any
"kind": "OMFOREIGN",
"encoding": "text/x-latex",
"foreign": "$\sin(x)$"
3.13</p>
        </sec>
        <sec id="sec-1-19-2">
          <title>References { OMR</title>
        </sec>
      </sec>
      <sec id="sec-1-20">
        <title>Finally, OpenMath References are represented as:</title>
        <p>"kind": "OMR"
/** element that is being referenced */
"href": uri</p>
        <p>By nature of being JSON, foreign objects inside the JSON encoding are obviously limited of
being representable as JSON.</p>
        <p>As a very simple example a LATEXmath term could be represented as:</p>
        <p>These can be used for structure sharing. Concretely, one can take any OpenMath object with
an id attribute and refer to it in another place using the OMR object with an appropriate href
"kind": "OMOBJ",
"object": {
"kind": "OMA",
"applicant": { "kind": "OMV", "name": "f" },
"arguments": [{
"kind": "OMA", "id": "x",
"applicant": { "kind": "OMV", "name": "f" },
"arguments": [{
"kind": "OMA", "id": "y",
"applicant": { "kind": "OMV", "name": "f" },
"arguments":
[{ "kind": "OMV", "name": "a" },
{ "kind": "OMV", "name": "a" }]
}, { "kind": "OMR", "href": "#y" }]
}, {</p>
        <p>"kind": "OMR", "href": "#x"
}
. In our encoding, this corresponds to</p>
        <p>A JSON Validation and XML/JSON Translation Web Service
To demonstrate our OpenMath-JSON encoding, we have created a web site which can be found
at [openmathjson:web]. This site is implemented in TypeScript and encapsulated using a
docker [docker:webpage] container. It serves three purposes:</p>
        <p>Primarily, it serves as a presentation of the encoding, providing examples and documenting
it's usage.</p>
        <p>Secondly, it enables validation of OpenMath JSON objects. This can be seen in Figure 1. The
user can enter some JSON, press the Validate JSON button, and receive immediate feedback if
their JSON is a valid OpenMath object or not. In particular, the user can also see a detailed
error message if their object is not valid OpenMath JSON.</p>
        <p>This makes use of the OpenMath JSON schema, and validates the users' JSON using a generic
JSON Schema Validator. Furthermore, this is also exposed using a REST API, enabling easy
validation of OpenMath JSON in other applications.</p>
        <p>Finally, it translates between XML and JSON encoded OpenMath objects. As for validation,
the site enables the user to enter some JSON and be presented with some XML and vice-versa;
see Figures 2 and 3.</p>
        <p>As we designed our encoding with this translatability goal in mind, the implementation of
it was straight-forward. For programmatic access, translation and validation are also exposed
using a REST API.
5</p>
      </sec>
    </sec>
    <sec id="sec-2">
      <title>Conclusion</title>
      <p>We have proposed a new OpenMath JSON encoding that facilitates the content-oriented
communication of mathematical objects and formulae in the web applications and web services
area. Our encoding combines the advantages of existing approaches, alleviates their problems,
and enables validation via a JSON schema we provide. To support development with the new
encoding, we supply a JSON validation service and a JSON/XML encoding translation service.</p>
      <p>In the future we hope that the OpenMath Society will canonicalize a JSON encoding for</p>
      <sec id="sec-2-1">
        <title>OpenMath using our proposal as a basis.</title>
      </sec>
      <sec id="sec-2-2">
        <title>Acknowledgements</title>
      </sec>
    </sec>
  </body>
  <back>
    <ref-list />
  </back>
</article>