307 lines
29 KiB
Markdown
307 lines
29 KiB
Markdown
# Zero-copy JSON views
|
||
|
||
`#!cpp <nlohmann/json_view.hpp>` adds a read-only, non-owning way to look at a parsed JSON text, as an alternative to
|
||
building a [`basic_json`](../../api/basic_json/index.md) tree with [`parse()`](../../api/basic_json/parse.md).
|
||
|
||
## The problem
|
||
|
||
[`basic_json::parse()`](../../api/basic_json/parse.md) builds a tree of `basic_json` values: one allocation for every
|
||
array and object, and every string copied into its own `std::string`. That is the right trade-off when the program
|
||
goes on to read and write the value freely, but it does more work than necessary when only a small part of a large
|
||
JSON text is actually needed, or when the same text is parsed over and over (many small messages, for instance) and
|
||
most of the resulting tree is thrown away almost immediately.
|
||
|
||
## The idea
|
||
|
||
[`basic_json_document::parse()`](../../api/basic_json_document/parse.md) parses the same JSON grammar, with the same
|
||
options, but instead of a tree it builds a flat index of the values it found: one
|
||
[16-byte entry](../../home/architecture.md#node-index-of-json-views) per value (and one per object key), in document
|
||
order. Integers are converted while parsing and stored in their entry. Floating-point numbers and strings are
|
||
referenced in place in the source text: a float is converted when it is read, and only strings that contain escape
|
||
sequences are decoded, into one shared buffer owned by the document.
|
||
|
||
[`basic_json_view`](../../api/basic_json_view/index.md) is a small, trivially copyable handle (two pointers) into that
|
||
index. It gives you the read-only, type-inspection part of the `basic_json` interface —
|
||
[`type()`](../../api/basic_json_view/type.md) and the `is_*()` predicates,
|
||
[`size()`](../../api/basic_json_view/size.md)/[`empty()`](../../api/basic_json_view/empty.md) — as well as element
|
||
access ([`operator[]`](../../api/basic_json_view/operator%5B%5D.md), [`at`](../../api/basic_json_view/at.md),
|
||
[`front`](../../api/basic_json_view/front.md)/[`back`](../../api/basic_json_view/back.md)), lookup
|
||
([`find`](../../api/basic_json_view/find.md), [`contains`](../../api/basic_json_view/contains.md),
|
||
[`count`](../../api/basic_json_view/count.md)), and iteration
|
||
([`begin`](../../api/basic_json_view/begin.md)/[`end`](../../api/basic_json_view/end.md),
|
||
[`items`](../../api/basic_json_view/items.md)) — without ever allocating a `basic_json` value. When you do need an
|
||
actual `basic_json` value for a subtree, [`materialize()`](../../api/basic_json_view/materialize.md) builds exactly the
|
||
one [`parse()`](../../api/basic_json/parse.md) would have produced for it.
|
||
|
||
The same small text, parsed both ways:
|
||
|
||
<div class="nj-fig-wrap" markdown>
|
||
<svg class="nj-fig nj-jsonview " viewBox="0 0 840 692" role="img" aria-labelledby="fig-jvl-title fig-jvl-title-d" xmlns="http://www.w3.org/2000/svg">
|
||
<title id="fig-jvl-title">The same J​SON text parsed by basic_json::parse() and by json_document::parse()</title>
|
||
<desc id="fig-jvl-title-d">The text {"port": 6379, "price": 19.90, "tags": ["eu", "a\"b"]}. Top: basic_json::parse() builds a tree: the root json value points to a std::map whose three nodes are separate heap allocations; the price is stored as the double 19.9; the tags array is a std::vector of two json values, each pointing to its own std::string. Bottom: json_document::parse() keeps the 54 bytes of source text and builds a flat index of nine 16-byte nodes in document order: object, key port, unsigned integer 6379 (the converted value is in the node), key price, float, key tags, array, string eu, and an escaped string. Keys, the float, and the plain string point back into the source text; the escaped string points into the document's buffer of decoded strings. A json_view is two pointers: one to the document and one to a node, here the array.</desc>
|
||
<defs>
|
||
<marker id="jvl-line" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-line nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
|
||
<marker id="jvl-str" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-str nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
|
||
<marker id="jvl-key" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-key nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
|
||
<marker id="jvl-num" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-num nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
|
||
<marker id="jvl-dec" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-dec nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
|
||
<marker id="jvl-own" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-own nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
|
||
<marker id="jvl-struct" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-struct nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
|
||
<marker id="jvl-bad" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-bad nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
|
||
</defs>
|
||
<text class="nj-jsonview-h" x="16" y="26" xml:space="preserve">basic_json::parse(): a tree, every array, object, and string in its own heap allocation</text>
|
||
<rect class="nj-jsonview-box" x="16" y="98" width="60" height="34" rx="5"/>
|
||
<text class="nj-jsonview-mono" x="46" y="120" text-anchor="middle" xml:space="preserve">json</text>
|
||
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M76 115 L106 115" marker-end="url(#jvl-line)"/>
|
||
<rect class="nj-jsonview-heap" x="108" y="98" width="84" height="34" rx="5"/>
|
||
<text class="nj-jsonview-mono" x="150" y="120" text-anchor="middle" xml:space="preserve">std::map</text>
|
||
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M192 115 L226 67" marker-end="url(#jvl-line)"/>
|
||
<rect class="nj-jsonview-heap" x="228" y="50" width="180" height="34" rx="5"/>
|
||
<text class="nj-jsonview-mono nj-jsonview-c-key" x="240" y="72" xml:space="preserve">"port"</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-c-num" x="396" y="72" text-anchor="end" xml:space="preserve">6379</text>
|
||
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M192 115 L226 115" marker-end="url(#jvl-line)"/>
|
||
<rect class="nj-jsonview-heap" x="228" y="98" width="180" height="34" rx="5"/>
|
||
<text class="nj-jsonview-mono nj-jsonview-c-key" x="240" y="120" xml:space="preserve">"price"</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-c-num" x="396" y="120" text-anchor="end" xml:space="preserve">19.9</text>
|
||
<text class="nj-jsonview-note" x="418" y="120" xml:space="preserve">double: 19.90 is gone</text>
|
||
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M192 115 L226 163" marker-end="url(#jvl-line)"/>
|
||
<rect class="nj-jsonview-heap" x="228" y="146" width="180" height="34" rx="5"/>
|
||
<text class="nj-jsonview-mono nj-jsonview-c-key" x="240" y="168" xml:space="preserve">"tags"</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-c-line" x="396" y="168" text-anchor="end" xml:space="preserve">•</text>
|
||
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M408 163 L442 163" marker-end="url(#jvl-line)"/>
|
||
<rect class="nj-jsonview-heap" x="444" y="146" width="104" height="34" rx="5"/>
|
||
<text class="nj-jsonview-mono" x="496" y="168" text-anchor="middle" xml:space="preserve">std::vector</text>
|
||
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M548 163 L576 163" marker-end="url(#jvl-line)"/>
|
||
<rect class="nj-jsonview-heap" x="578" y="146" width="92" height="34" rx="5"/>
|
||
<path class="nj-jsonview-sep" d="M624 146 V180"/>
|
||
<text class="nj-jsonview-mono" x="601" y="168" text-anchor="middle" xml:space="preserve">json</text>
|
||
<text class="nj-jsonview-mono" x="647" y="168" text-anchor="middle" xml:space="preserve">json</text>
|
||
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M601 146 C601 130 641 130 706 130" marker-end="url(#jvl-line)"/>
|
||
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M647 180 C647 196 687 196 706 196" marker-end="url(#jvl-line)"/>
|
||
<rect class="nj-jsonview-heap" x="708" y="113" width="126" height="34" rx="5"/>
|
||
<text class="nj-jsonview-mono nj-jsonview-sm nj-jsonview-c-str" x="771" y="135" text-anchor="middle" xml:space="preserve">std::string eu</text>
|
||
<rect class="nj-jsonview-heap" x="708" y="179" width="126" height="34" rx="5"/>
|
||
<text class="nj-jsonview-mono nj-jsonview-sm nj-jsonview-c-str" x="771" y="201" text-anchor="middle" xml:space="preserve">std::string a"b</text>
|
||
<rect class="nj-jsonview-heap" x="16" y="186" width="18" height="14" rx="3"/>
|
||
<text class="nj-jsonview-note" x="42" y="198" xml:space="preserve">a separate heap allocation</text>
|
||
<path class="nj-jsonview-sep" d="M16 234 H824"/>
|
||
<text class="nj-jsonview-h" x="16" y="262" xml:space="preserve">json_document::parse(): the source text stays where it is; one flat index of 16-byte nodes</text>
|
||
<text class="nj-jsonview-note" x="16" y="290" xml:space="preserve">source text, 54 bytes (borrowed, or owned by the document)</text>
|
||
<rect class="nj-jsonview-ribbon" x="42" y="300" width="756" height="26" rx="4"/>
|
||
<rect class="nj-jsonview-span nj-jsonview-c-key" x="71" y="302" width="54" height="22" rx="3"/>
|
||
<rect class="nj-jsonview-span nj-jsonview-c-num" x="169" y="302" width="54" height="22" rx="3"/>
|
||
<rect class="nj-jsonview-span nj-jsonview-c-key" x="267" y="302" width="68" height="22" rx="3"/>
|
||
<rect class="nj-jsonview-span nj-jsonview-c-num" x="379" y="302" width="68" height="22" rx="3"/>
|
||
<rect class="nj-jsonview-span nj-jsonview-c-key" x="491" y="302" width="54" height="22" rx="3"/>
|
||
<rect class="nj-jsonview-span nj-jsonview-c-str" x="617" y="302" width="26" height="22" rx="3"/>
|
||
<rect class="nj-jsonview-span nj-jsonview-c-dec" x="701" y="302" width="54" height="22" rx="3"/>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="49" y="317.5" text-anchor="middle" xml:space="preserve">{</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="63" y="317.5" text-anchor="middle" xml:space="preserve">"</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="77" y="317.5" text-anchor="middle" xml:space="preserve">p</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="91" y="317.5" text-anchor="middle" xml:space="preserve">o</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="105" y="317.5" text-anchor="middle" xml:space="preserve">r</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="119" y="317.5" text-anchor="middle" xml:space="preserve">t</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="133" y="317.5" text-anchor="middle" xml:space="preserve">"</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="147" y="317.5" text-anchor="middle" xml:space="preserve">:</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="175" y="317.5" text-anchor="middle" xml:space="preserve">6</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="189" y="317.5" text-anchor="middle" xml:space="preserve">3</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="203" y="317.5" text-anchor="middle" xml:space="preserve">7</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="217" y="317.5" text-anchor="middle" xml:space="preserve">9</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="231" y="317.5" text-anchor="middle" xml:space="preserve">,</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="259" y="317.5" text-anchor="middle" xml:space="preserve">"</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="273" y="317.5" text-anchor="middle" xml:space="preserve">p</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="287" y="317.5" text-anchor="middle" xml:space="preserve">r</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="301" y="317.5" text-anchor="middle" xml:space="preserve">i</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="315" y="317.5" text-anchor="middle" xml:space="preserve">c</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="329" y="317.5" text-anchor="middle" xml:space="preserve">e</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="343" y="317.5" text-anchor="middle" xml:space="preserve">"</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="357" y="317.5" text-anchor="middle" xml:space="preserve">:</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="385" y="317.5" text-anchor="middle" xml:space="preserve">1</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="399" y="317.5" text-anchor="middle" xml:space="preserve">9</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="413" y="317.5" text-anchor="middle" xml:space="preserve">.</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="427" y="317.5" text-anchor="middle" xml:space="preserve">9</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="441" y="317.5" text-anchor="middle" xml:space="preserve">0</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="455" y="317.5" text-anchor="middle" xml:space="preserve">,</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="483" y="317.5" text-anchor="middle" xml:space="preserve">"</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="497" y="317.5" text-anchor="middle" xml:space="preserve">t</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="511" y="317.5" text-anchor="middle" xml:space="preserve">a</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="525" y="317.5" text-anchor="middle" xml:space="preserve">g</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="539" y="317.5" text-anchor="middle" xml:space="preserve">s</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="553" y="317.5" text-anchor="middle" xml:space="preserve">"</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="567" y="317.5" text-anchor="middle" xml:space="preserve">:</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="595" y="317.5" text-anchor="middle" xml:space="preserve">[</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="609" y="317.5" text-anchor="middle" xml:space="preserve">"</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="623" y="317.5" text-anchor="middle" xml:space="preserve">e</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="637" y="317.5" text-anchor="middle" xml:space="preserve">u</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="651" y="317.5" text-anchor="middle" xml:space="preserve">"</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="665" y="317.5" text-anchor="middle" xml:space="preserve">,</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="693" y="317.5" text-anchor="middle" xml:space="preserve">"</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="707" y="317.5" text-anchor="middle" xml:space="preserve">a</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="721" y="317.5" text-anchor="middle" xml:space="preserve">\</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="735" y="317.5" text-anchor="middle" xml:space="preserve">"</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="749" y="317.5" text-anchor="middle" xml:space="preserve">b</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="763" y="317.5" text-anchor="middle" xml:space="preserve">"</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="777" y="317.5" text-anchor="middle" xml:space="preserve">]</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-byte" x="791" y="317.5" text-anchor="middle" xml:space="preserve">}</text>
|
||
<text class="nj-jsonview-tiny" x="49" y="340" text-anchor="middle" xml:space="preserve">0</text>
|
||
<text class="nj-jsonview-tiny" x="189" y="340" text-anchor="middle" xml:space="preserve">10</text>
|
||
<text class="nj-jsonview-tiny" x="329" y="340" text-anchor="middle" xml:space="preserve">20</text>
|
||
<text class="nj-jsonview-tiny" x="469" y="340" text-anchor="middle" xml:space="preserve">30</text>
|
||
<text class="nj-jsonview-tiny" x="609" y="340" text-anchor="middle" xml:space="preserve">40</text>
|
||
<text class="nj-jsonview-tiny" x="749" y="340" text-anchor="middle" xml:space="preserve">50</text>
|
||
<rect class="nj-jsonview-frame" x="16" y="366" width="808" height="254" rx="10"/>
|
||
<text class="nj-jsonview-note nj-jsonview-strong" x="30" y="602" xml:space="preserve">json_document: owns the node index and the buffer of decoded strings</text>
|
||
<text class="nj-jsonview-note" x="30" y="500" xml:space="preserve">node index: 9 nodes × 16 bytes = 144 bytes, in document order</text>
|
||
<rect class="nj-jsonview-node nj-jsonview-c-struct" x="36" y="406" width="84" height="68" rx="5"/>
|
||
<text class="nj-jsonview-tiny" x="42" y="420" xml:space="preserve">0</text>
|
||
<text class="nj-jsonview-kind nj-jsonview-c-struct" x="78" y="434" text-anchor="middle" xml:space="preserve">object</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-xs" x="78" y="451" text-anchor="middle" xml:space="preserve">len 3</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-xs" x="78" y="465" text-anchor="middle" xml:space="preserve">next 9</text>
|
||
<rect class="nj-jsonview-node nj-jsonview-c-key" x="124" y="406" width="84" height="68" rx="5"/>
|
||
<text class="nj-jsonview-tiny" x="130" y="420" xml:space="preserve">1</text>
|
||
<text class="nj-jsonview-kind nj-jsonview-c-key" x="166" y="434" text-anchor="middle" xml:space="preserve">key</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-xs" x="166" y="451" text-anchor="middle" xml:space="preserve">off 2</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-xs" x="166" y="465" text-anchor="middle" xml:space="preserve">len 4</text>
|
||
<path class="nj-jsonview-arr nj-jsonview-c-key" d="M166 406 C166 367 98 367 98 328" marker-end="url(#jvl-key)"/>
|
||
<rect class="nj-jsonview-node nj-jsonview-c-num" x="212" y="406" width="84" height="68" rx="5"/>
|
||
<text class="nj-jsonview-tiny" x="218" y="420" xml:space="preserve">2</text>
|
||
<text class="nj-jsonview-kind nj-jsonview-c-num" x="254" y="434" text-anchor="middle" xml:space="preserve">uint</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-xs" x="254" y="451" text-anchor="middle" xml:space="preserve">6379</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-xs" x="254" y="465" text-anchor="middle" xml:space="preserve">(converted)</text>
|
||
<rect class="nj-jsonview-node nj-jsonview-c-key" x="300" y="406" width="84" height="68" rx="5"/>
|
||
<text class="nj-jsonview-tiny" x="306" y="420" xml:space="preserve">3</text>
|
||
<text class="nj-jsonview-kind nj-jsonview-c-key" x="342" y="434" text-anchor="middle" xml:space="preserve">key</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-xs" x="342" y="451" text-anchor="middle" xml:space="preserve">off 16</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-xs" x="342" y="465" text-anchor="middle" xml:space="preserve">len 5</text>
|
||
<path class="nj-jsonview-arr nj-jsonview-c-key" d="M342 406 C342 367 301 367 301 328" marker-end="url(#jvl-key)"/>
|
||
<rect class="nj-jsonview-node nj-jsonview-c-num" x="388" y="406" width="84" height="68" rx="5"/>
|
||
<text class="nj-jsonview-tiny" x="394" y="420" xml:space="preserve">4</text>
|
||
<text class="nj-jsonview-kind nj-jsonview-c-num" x="430" y="434" text-anchor="middle" xml:space="preserve">float</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-xs" x="430" y="451" text-anchor="middle" xml:space="preserve">off 24</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-xs" x="430" y="465" text-anchor="middle" xml:space="preserve">len 5</text>
|
||
<path class="nj-jsonview-arr nj-jsonview-c-num" d="M430 406 C430 367 413 367 413 328" marker-end="url(#jvl-num)"/>
|
||
<rect class="nj-jsonview-node nj-jsonview-c-key" x="476" y="406" width="84" height="68" rx="5"/>
|
||
<text class="nj-jsonview-tiny" x="482" y="420" xml:space="preserve">5</text>
|
||
<text class="nj-jsonview-kind nj-jsonview-c-key" x="518" y="434" text-anchor="middle" xml:space="preserve">key</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-xs" x="518" y="451" text-anchor="middle" xml:space="preserve">off 32</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-xs" x="518" y="465" text-anchor="middle" xml:space="preserve">len 4</text>
|
||
<path class="nj-jsonview-arr nj-jsonview-c-key" d="M518 406 C518 367 518 367 518 328" marker-end="url(#jvl-key)"/>
|
||
<rect class="nj-jsonview-node nj-jsonview-c-struct" x="564" y="406" width="84" height="68" rx="5"/>
|
||
<text class="nj-jsonview-tiny" x="570" y="420" xml:space="preserve">6</text>
|
||
<text class="nj-jsonview-kind nj-jsonview-c-struct" x="606" y="434" text-anchor="middle" xml:space="preserve">array</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-xs" x="606" y="451" text-anchor="middle" xml:space="preserve">len 2</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-xs" x="606" y="465" text-anchor="middle" xml:space="preserve">next 3</text>
|
||
<rect class="nj-jsonview-node nj-jsonview-c-str" x="652" y="406" width="84" height="68" rx="5"/>
|
||
<text class="nj-jsonview-tiny" x="658" y="420" xml:space="preserve">7</text>
|
||
<text class="nj-jsonview-kind nj-jsonview-c-str" x="694" y="434" text-anchor="middle" xml:space="preserve">string</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-xs" x="694" y="451" text-anchor="middle" xml:space="preserve">off 41</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-xs" x="694" y="465" text-anchor="middle" xml:space="preserve">len 2</text>
|
||
<path class="nj-jsonview-arr nj-jsonview-c-str" d="M694 406 C694 367 630 367 630 328" marker-end="url(#jvl-str)"/>
|
||
<rect class="nj-jsonview-node nj-jsonview-c-dec" x="740" y="406" width="84" height="68" rx="5"/>
|
||
<text class="nj-jsonview-tiny" x="746" y="420" xml:space="preserve">8</text>
|
||
<text class="nj-jsonview-kind nj-jsonview-c-dec" x="782" y="434" text-anchor="middle" xml:space="preserve">string</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-xs" x="782" y="451" text-anchor="middle" xml:space="preserve">escaped</text>
|
||
<text class="nj-jsonview-mono nj-jsonview-xs" x="782" y="465" text-anchor="middle" xml:space="preserve">len 3</text>
|
||
<text class="nj-jsonview-note" x="773" y="568" text-anchor="middle" xml:space="preserve">decoded strings</text>
|
||
<rect class="nj-jsonview-node nj-jsonview-c-dec" x="740" y="518" width="66" height="30" rx="4"/>
|
||
<text class="nj-jsonview-mono" x="751" y="538" text-anchor="middle" xml:space="preserve">a</text>
|
||
<text class="nj-jsonview-mono" x="773" y="538" text-anchor="middle" xml:space="preserve">"</text>
|
||
<text class="nj-jsonview-mono" x="795" y="538" text-anchor="middle" xml:space="preserve">b</text>
|
||
<path class="nj-jsonview-arr nj-jsonview-c-dec" d="M782 474 C782 496 773 496 773 518" marker-end="url(#jvl-dec)"/>
|
||
<text class="nj-jsonview-mono nj-jsonview-sm" x="470" y="670" text-anchor="end" xml:space="preserve">json_view v = doc.root()["tags"]</text>
|
||
<rect class="nj-jsonview-node nj-jsonview-c-struct" x="480" y="648" width="140" height="34" rx="6"/>
|
||
<path class="nj-jsonview-sep" d="M550 648 V682"/>
|
||
<text class="nj-jsonview-mono" x="515" y="670" text-anchor="middle" xml:space="preserve">doc*</text>
|
||
<text class="nj-jsonview-mono" x="585" y="670" text-anchor="middle" xml:space="preserve">node*</text>
|
||
<path class="nj-jsonview-arr nj-jsonview-c-struct" d="M515 648 L515 622" marker-end="url(#jvl-struct)"/>
|
||
<path class="nj-jsonview-arr nj-jsonview-c-struct" d="M585 648 C585 561 606 561 606 474" marker-end="url(#jvl-struct)"/>
|
||
<text class="nj-jsonview-note" x="30" y="524" xml:space="preserve">integers are converted while parsing and kept in their node;</text>
|
||
<text class="nj-jsonview-note" x="30" y="542" xml:space="preserve">floats and strings point back into the text</text>
|
||
</svg>
|
||
|
||
</div>
|
||
|
||
<p class="nj-caption" markdown>Top: the tree of separate heap allocations that `basic_json::parse()` builds. Bottom: `json_document::parse()` keeps the source text and builds one flat index of 16-byte nodes that point back into it, plus a buffer of decoded strings.</p>
|
||
|
||
## How to use it
|
||
|
||
Include `<nlohmann/json_view.hpp>` in addition to (or instead of) `<nlohmann/json.hpp>`. Parse into a
|
||
[`json_document`](../../api/json_document.md), inspect its [`root()`](../../api/basic_json_document/root.md), and
|
||
`materialize()` when you need a real value. `materialize()` works on any view, not just the root, so you can turn just
|
||
the subtree you need into a value:
|
||
|
||
??? example "Example: parse a document, inspect its root, and materialize it"
|
||
|
||
```cpp
|
||
#include <iostream>
|
||
#include <nlohmann/json_view.hpp>
|
||
|
||
using nlohmann::json_document;
|
||
|
||
int main()
|
||
{
|
||
std::cout << std::boolalpha;
|
||
|
||
// json_document is basic_json_document<nlohmann::json>: same value types
|
||
// and containers as the ordinary json specialization
|
||
json_document doc = json_document::parse(R"({"pi": 3.14, "numbers": [1, 2, 3]})");
|
||
|
||
std::cout << doc.root().is_object() << '\n';
|
||
std::cout << doc.root().materialize().dump() << '\n';
|
||
}
|
||
|
||
```
|
||
|
||
Output:
|
||
|
||
```json
|
||
true
|
||
{"numbers":[1,2,3],"pi":3.14}
|
||
|
||
```
|
||
|
||
[`ordered_json_document`](../../api/ordered_json_document.md) is the equivalent for
|
||
[`ordered_json`](../../api/ordered_json.md), just as [`ordered_json`](../../api/ordered_json.md) is to
|
||
[`json`](../../api/json.md).
|
||
|
||
A view behaves like a `basic_json` value in most respects, but not in all: lookups of a repeated key, the order in
|
||
which an object's members are visited, and what a missing key does to chained `operator[]` are the most visible
|
||
differences. [Differences from `basic_json`](differences.md) lists all of them.
|
||
|
||
## Where to go next
|
||
|
||
- [Ownership and lifetime](lifetime.md) - when a document borrows its source text, and how long a view stays valid
|
||
- [Differences from `basic_json`](differences.md) - everything a view does differently from a parsed `basic_json` value
|
||
- [Reading values](reading.md) - converting with `get<T>()`, reading strings and numbers without copying, and writing a
|
||
view back with `dump()`
|
||
- [Writing generic code](generic_code.md) - functions and `from_json()` overloads that accept views
|
||
- [Editing a document](editing.md) - patching a document in place, keeping its member order and number spellings
|
||
- [Images](images.md) - saving a parsed document and loading it back without parsing
|
||
|
||
## Choosing between `json`, `ordered_json`, the SAX interface, and `json_view`
|
||
|
||
| | [`json`](../../api/json.md) / [`ordered_json`](../../api/ordered_json.md) | [SAX interface](../parsing/sax_interface.md) | [`json_document`](../../api/json_document.md) / [`json_view`](../../api/json_view.md) | [`json_editable_document`](../../api/json_editable_document.md) / [`json_editable_view`](../../api/json_editable_view.md) |
|
||
|---|---|---|---|---|
|
||
| **Ownership** | owns every value | owns nothing; you decide what to keep, in your handler | borrows or owns the *text*; the index is always owned by the document | same as `json_document`; edits go to storage the document owns |
|
||
| **Mutability** | freely mutable | not applicable (a one-shot event stream) | read-only | [`set`](../../api/basic_json_document/set.md)/[`push_back`](../../api/basic_json_document/push_back.md)/[`insert`](../../api/basic_json_document/insert.md)/[`erase`](../../api/basic_json_document/erase.md) edit in place; the source text is never rewritten |
|
||
| **What you get** | a full tree you can read, write, and keep as long as you like | a sequence of callbacks; whatever your handler builds from them | a flat index plus, on demand, [`materialize()`](../../api/basic_json_view/materialize.md)d `json`/`ordered_json` values for the parts you actually use | the same, plus [`dump()`](../../api/basic_json_view/dump.md) of an edited document that keeps the member order and, with [`number_format::source`](../../api/basic_json_view/number_format.md), the spelling of every untouched number |
|
||
| **Typical use** | general-purpose JSON handling: config, request/response bodies you build or modify, anything you hold onto | validating or projecting a text into your own data structure without ever holding the whole thing as JSON | large or high-volume input where you only need part of it, or need it repeatedly, and can keep the source text (or a copy) alive for as long as the document lives | a document you read, patch a few fields of, and write back — a configuration file, for instance — where the rest of it should come back exactly as it was |
|
||
| **Caching/reload** | not applicable — re-parse, or roll your own serialization | not applicable | [`save()`](../../api/basic_json_document/save.md)/[`load()`](../../api/basic_json_document/load.md): cache the parsed index as an [image](images.md) and reload it without parsing | same, saving the document's current — possibly edited — state |
|
||
|
||
<p class="nj-table-caption" markdown>Each column is one way to work with JSON in this library, and each row compares one property of them.</p>
|
||
|
||
## See also
|
||
|
||
- [`basic_json_document`](../../api/basic_json_document/index.md) - the document that owns the parsed index (parse, access, images, edits)
|
||
- [`basic_json_view`](../../api/basic_json_view/index.md) - the non-owning handle to a value in a document
|
||
- [`json_document`](../../api/json_document.md) - and [`ordered_json_document`](../../api/ordered_json_document.md) - the read-only documents
|
||
- [`json_editable_document`](../../api/json_editable_document.md) - and [`ordered_json_editable_document`](../../api/ordered_json_editable_document.md) - the documents that can be edited in place
|
||
- [Architecture](../../home/architecture.md#node-index-of-json-views) - the layout of the node index
|
||
- [SAX interface](../parsing/sax_interface.md) - event-based parsing without building a tree
|
||
- [Performance](../performance.md) - benchmarks and tuning of parsing and serialization
|
||
- [Large, Streamed, and Partial Input](../parsing/large_and_partial_input.md) - reading only the part of a text you need
|
||
|
||
## Version history
|
||
|
||
- Added in version 3.13.0.
|