# DOM API

Parse a whole document into an immutable, random-access tree of JsonValues.


The DOM API parses an entire document into an immutable in-memory tree. Every
node is a [`JsonValue`](#the-jsonvalue-tree) you can navigate and re-read
freely: random access, multiple passes, no ordering constraints.

## Parsing

`SimdJsonParser.parse` accepts either a `String` or a UTF-8 `ByteArray` and
returns the root `JsonValue`:

```kotlin
val json: ByteArray = loadTwitterJson()

SimdJsonParser().use { parser ->
    val root = parser.parse(json) as JsonObject
    val statuses = root["statuses"] as JsonArray
    for (tweet in statuses) {
        val user = (tweet as JsonObject)["user"] as JsonObject
        if ((user["default_profile"] as JsonBoolean).value) {
            println((user["screen_name"] as JsonString).value)
        }
    }
}
```

<aside class="kt-callout kt-callout--tip">
  <svg class="kt-callout__icon" viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 18h6"/><path d="M10 22h4"/><path d="M12 2a7 7 0 0 1 7 7c0 3-2 5-3 6.5V18H8v-2.5C7 14 5 12 5 9a7 7 0 0 1 7-7z"/></svg>
  <div class="kt-callout__body"><strong class="kt-callout__title">Bytes beat strings</strong><div class="kt-callout__content">Parsing a UTF-8 <code>ByteArray</code> directly skips a <code>String</code> decode step. <code>parse</code> takes
an optional <code>length</code>, so you can reuse an oversized buffer:
<code>parser.parse(buffer, length = bytesRead)</code>.</div>
  </div>
</aside>


## The JsonValue tree

`JsonValue` is a `sealed` type with one subtype per JSON kind:

<table class="kt-params">
  <thead>
    <tr><th>Parameter</th><th>Description</th></tr>
  </thead>
  <tbody><tr>
          <td>
            <code class="kt-params__name">JsonObject</code><span class="kt-params__type">Iterable&lt;Pair&lt;String, JsonValue&gt;&gt;</span></td>
          <td>Keyed map: <code>get(key): JsonValue?</code>, <code>size</code>, <code>keys(): Set&lt;String&gt;</code>, <code>key in obj</code>, and iteration over <code>(key, value)</code> pairs.</td>
        </tr><tr>
          <td>
            <code class="kt-params__name">JsonArray</code><span class="kt-params__type">Iterable&lt;JsonValue&gt;</span></td>
          <td>Ordered list: <code>get(index): JsonValue</code>, <code>size</code>, and iteration over elements.</td>
        </tr><tr>
          <td>
            <code class="kt-params__name">JsonString</code><span class="kt-params__type">value class</span></td>
          <td>Wraps <code>value: String</code>.</td>
        </tr><tr>
          <td>
            <code class="kt-params__name">JsonNumber</code><span class="kt-params__type">—</span></td>
          <td>A number that remembers its representation (see <a href="/simdjson-kotlin/#numbers">Numbers</a>).</td>
        </tr><tr>
          <td>
            <code class="kt-params__name">JsonBoolean</code><span class="kt-params__type">value class</span></td>
          <td>Wraps <code>value: Boolean</code>.</td>
        </tr><tr>
          <td>
            <code class="kt-params__name">JsonNull</code><span class="kt-params__type">object</span></td>
          <td>The <code>null</code> literal (a singleton).</td>
        </tr></tbody>
</table>


Because the hierarchy is sealed, a `when` over it is exhaustive:

```kotlin
val text: String? = when (val v = parser.parse(json)) {
    is JsonObject -> "object with ${v.size} entries"
    is JsonArray -> "array of ${v.size}"
    is JsonString -> v.value
    is JsonNumber -> v.toDouble().toString()
    is JsonBoolean -> v.value.toString()
    JsonNull -> null
}
```

`get` on a `JsonObject` returns `JsonValue?` (`null` when the key is absent).
Indexing a `JsonArray` returns a non-null `JsonValue`. Casting to the wrong
subtype throws a `ClassCastException`, so guard with `as?` or an `is` check when
the shape is uncertain.

## Numbers

`JsonNumber` preserves the parsed number's representation so you can read it
back without loss:

<table class="kt-params">
  <thead>
    <tr><th>Parameter</th><th>Description</th></tr>
  </thead>
  <tbody><tr>
          <td>
            <code class="kt-params__name">isInteger</code><span class="kt-params__type">Boolean</span></td>
          <td><code>true</code> for integers, signed or unsigned.</td>
        </tr><tr>
          <td>
            <code class="kt-params__name">isLong</code><span class="kt-params__type">Boolean</span></td>
          <td><code>true</code> for signed 64-bit integers.</td>
        </tr><tr>
          <td>
            <code class="kt-params__name">isUnsigned</code><span class="kt-params__type">Boolean</span></td>
          <td><code>true</code> for values that only fit in an unsigned 64-bit integer.</td>
        </tr><tr>
          <td>
            <code class="kt-params__name">toLong() · toULong() · toInt()</code><span class="kt-params__type">—</span></td>
          <td>Integer views of the value.</td>
        </tr><tr>
          <td>
            <code class="kt-params__name">toDouble()</code><span class="kt-params__type">—</span></td>
          <td>Floating-point view of the value.</td>
        </tr></tbody>
</table>


## Lifetime

The DOM tree is fully materialized and **independent of the parser**. It stays
valid after later `parse`/`iterate` calls and even after the parser is closed.
The *parser* itself still needs closing, since it owns reusable buffers and,
on Native, native memory. `use { }` does that for you.

<aside class="kt-callout kt-callout--note">
  <svg class="kt-callout__icon" viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 5h18"/><path d="M3 12h18"/><path d="M3 19h12"/></svg>
  <div class="kt-callout__body"><strong class="kt-callout__title">Reuse the parser</strong><div class="kt-callout__content"><code>SimdJsonParser</code> is <strong>not thread-safe</strong>. Reuse one instance per thread to
amortize its internal buffer allocations, rather than constructing a parser per
document.</div>
  </div>
</aside>


## Errors

Parsing failures are subtypes of `SimdJsonException`:

<table class="kt-params">
  <thead>
    <tr><th>Parameter</th><th>Description</th></tr>
  </thead>
  <tbody><tr>
          <td>
            <code class="kt-params__name">JsonParsingException</code><span class="kt-params__type">SimdJsonException</span></td>
          <td>Input is not valid JSON. Carries the byte <code>offset</code> of the failure.</td>
        </tr><tr>
          <td>
            <code class="kt-params__name">JsonEncodingException</code><span class="kt-params__type">SimdJsonException</span></td>
          <td>Input is not valid UTF-8.</td>
        </tr></tbody>
</table>

