File: output-formats.html

package info (click to toggle)
jsonnet 0.20.0%2Bds-3.1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 16,776 kB
  • sloc: cpp: 23,318; python: 1,788; javascript: 1,003; ansic: 885; sh: 745; makefile: 194; java: 140
file content (334 lines) | stat: -rw-r--r-- 9,921 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
---
layout: default
title: Output Formats
---

<div class="hgroup">
  <div class="hgroup-inline">
    <div class="panel">
      <h1 id="top">Output Formats</h1>
    </div>
    <div style="clear: both"></div>
  </div>
</div>

<div class="hgroup">
  <div class="hgroup-inline">
    <div class="panel">
      <p>
        A Jsonnet evaluation typically outputs a JSON document. For ways to output multiple JSON
        documents, see <a href="/learning/getting_started.html">Getting Started</a>.  Whether this
        integrates cleanly depends on your application.  If you're writing a custom application,
        then you can simply consume this JSON.  Another option is to write your config as a protocol
        buffer and deserialize Jsonnet's JSON output using the proto3 canonical JSON representation.
        Interoperation with YAML is also easy, see <a
        href="/articles/kubernetes.html">Kubernetes</a> for an example.  To support consumers of
        syntactically incompatible formats such as INI or XML, custom serialization is needed.
      </p>
    </div>
    <div style="clear: both"></div>
  </div>
</div>

<div class="hgroup">
  <div class="hgroup-inline">
    <div class="panel">
      <h2 id="top">Custom Output Formats</h2>
    </div>
    <div style="clear: both"></div>
  </div>
</div>

<div class="hgroup">
  <div class="hgroup-inline">
    <div class="panel">
      <p>
        The INI format provides a simple example.
      </p>
      <ul>
        <li>
          The content of the INI file has been represented within the JSON object model, i.e. using
          objects to represent the nesting of the sections.
        </li>
        <li>
          The special <code>main</code> section holds the top-level keys (ones not in any section).
        </li>
        <li>
          The function <code>std.manifestIni</code> (written in Jsonnet) serializes the structure to
          a string.
        </li>
        <li>
          Jsonnet is run in string output mode <tt>-S</tt> to print the string verbatim rather than
          encoded as JSON.  
        </li>
      </ul>
      <p>
        The code below could be executed with the command:
      </p>
      <pre>$ jsonnet -S ini.jsonnet</pre>
      <p>
        Try replacing <code>manifestIni</code>. with <code>manifestJson</code> or
        <code>manifestPython</code>.  There are many such functions in the standard library, and you
        can write custom ones too.  Finally, to see the effect of <tt>-S</tt> directly, try
        replacing the whole buffer with just a string literal.
      </p>
    </div>
    <div style="clear: both"></div>
  </div>

</div>

<div class="inverse hgroup">
  <div class=hgroup-inline>
    <div class="tab-window-input" id="ini-input">
      <div class="tab-header">
      </div>
      <textarea id=ini-jsonnet>
        std.manifestIni({
          main: {
            a: 1,
          },
          sections: {
            foo: {
              a: true,
              b: 2,
            },
            bar: {
              x: 'text',
            },
          },
        })
      </textarea>
    </div>
    <div class="bigarrow">➡</div>
    <div class="tab-window-output" id="ini-output">
      <div class="tab-header">
        <div class=selected onclick="tab_output_click(this, 'output-ini')">
          output.ini
        </div>
      </div>
      <textarea readonly class="selected code-json" id="output-ini">
        a = 1
        [bar]
        x = text
        [foo]
        a = 1
        b = 2
      </textarea>
    </div>
    <script>
      demo(
        'ini-input',
        {
          'ini-jsonnet': 'ini.jsonnet',
        },
        'ini.jsonnet',
        'ini-output',
        false,
        true
      );
    </script>
    <div style="clear: both"></div>
  </div>
</div>

<div class="hgroup">
  <div class="hgroup-inline">
    <div class="panel">
      <p>
        Thus, despite internally using the JSON data model, Jsonnet can provide config generation
        for applications that consume INI.
      </p>
      <p>
        Below is a more complex example where we construct an SVG file by emitting XML.  It shows
        how to write a custom manifestation function, and also a non-trivial example of representing
        something in Jsonnet.
      </p>
    </div>
    <div style="clear: both"></div>
  </div>
</div>
<div class="inverse hgroup">
  <div class=hgroup-inline>
    <div class="tab-window-input" id="svg-input">
      <div class="tab-header">
      </div>
      <textarea id=svg-jsonnet>
        local xml = import 'xml.libsonnet';

        local Svg = xml.Element('svg') {
          height:: 100,
          width:: 100,
        };

        local Polygon = xml.Element('polygon') {
          points: std.join(
            ' ',
            [
              '%s,%s' % coords
              for coords in self.pointCoords
            ]
          ),
        };

        local Path = xml.Element('path') {
          cmds:: [],
          d: std.join('', self.cmds),
        };

        local ref(element) = 'url(#%s)' % element.id;

        local logo = Svg {
          version: '1.1',
          xmlns: 'http://www.w3.org/2000/svg',
          x: 0,
          y: 0,
          width: 90,
          height: 90,
          viewBox: '0 0 180 180',
          bg:: xml.Element('linearGradient') {
            id: 'bg',
            gradientUnits: 'userSpaceOnUse',
            x1: 53,
            y1: 19,
            x2: 126,
            y2: 162,
            colour1:: '#0091AD',
            colour2:: '#00728F',
            local grad = self,
            has: [
              xml.Element('stop') {
                offset: 0,
                'stop-color': grad.colour1,
              },
              xml.Element('stop') {
                offset: 1,
                'stop-color': grad.colour2,
              },
            ],
          },
          line:: Polygon {
            fill: 'white',
            pointCoords:: [
              [0, 38],
              [90, -14],
              [180, 38],
              [180, 142],
              [90, 194],
              [0, 142]
            ],
          },
          fill:: Path {
            fill: ref($.bg),
            cmds: [
              'M168,49 v86 L129,82 L168,49 z',
              'M90,98 l67-59 L90,0 V98 z',
              'M73,10 L12,45 v90 l61,35 V10 z',
              'M117,94 L90,116 v63 l63-36 L117,94 z',
            ],
          },
          has: [
            $.bg,
            $.line,
            $.fill,
          ],
        };

        xml.manifestXmlObj(logo)
      </textarea>
      <textarea id=xml-libsonnet>
        // Some utility functions for generating XML.
        {
          // Serialize a XML document represented as a
          // Jsonnet value.  Each node of the XML tree
          // has a field 'tag', and optionally 'attrs'
          // (an string mapping), and 'has', an array
          // of children.
          manifestXmlObj(value)::
            local aux(v, cindent) =
              if !std.isObject(v) then
                error 'Expected a object, got %s'
                      % std.type(value)
              else
                local attrs = [
                  ' %s="%s"' % [k, v.attrs[k]]
                  for k in std.objectFields(v.attrs)
                ];
                if std.length(v.has) &gt; 0 then
                  std.deepJoin([
                    cindent, '&lt;', v.tag, attrs, '&gt;\n',
                    [
                      aux(x, cindent + '  ')
                      for x in v.has
                    ],
                    cindent, '&lt;/', v.tag, '&gt;\n'
                  ])
                else
                  std.deepJoin([
                    cindent, '&lt;', v.tag, attrs, '&gt;',
                    '&lt;/', v.tag, '&gt;\n']);
            aux(value, ''),

          // A convenience object whose attributes are
          // taken from the top-level non-hidden fields
          // of the object.  This works except for
          // attributes called 'tag' or 'has'.
          Element(tag):: {
            local element = self,
            tag:: tag,
            attrs:: {
              [k]: element[k]
              for k in std.objectFields(element)
            },
            has:: [],
          },
        }
      </textarea>
    </div>
    <div class="bigarrow">➡</div>
    <div class="tab-window-output" id="svg-output">
      <div class="tab-header">
        <div class=selected onclick="tab_output_click(this, 'output-svg')">
          output.svg
        </div>
      </div>
      <textarea readonly class="selected code-json" id="output-svg">
<svg version="1.1" viewBox="0 0 180 180" x="0" xmlns="http://www.w3.org/2000/svg" y="0">
  <linearGradient gradientUnits="userSpaceOnUse" id="bg" x1="53" x2="126" y1="19" y2="162">
    <stop offset="0" stop-color="#0091AD"></stop>
    <stop offset="1" stop-color="#00728F"></stop>
  </linearGradient>
  <polygon fill="white" points="0,38 90,-14 180,38 180,142 90,194 0,142"></polygon>
  <path d="M168,49 v86 L129,82 L168,49 zM90,98 l67-59 L90,0 V98 zM73,10 L12,45 v90 l61,35 V10 zM117,94 L90,116 v63 l63-36 L117,94 z" fill="url(#bg)"></path>
</svg>
      </textarea>
    </div>
    <script>
      demo(
        'svg-input',
        {
          'svg-jsonnet': 'svg.jsonnet',
          'xml-libsonnet': 'xml.libsonnet',
        },
        'svg.jsonnet',
        'svg-output',
        false,
        true
      );
    </script>
    <div style="clear: both"></div>
  </div>
</div>

<div class="hgroup">
  <div class="hgroup-inline">
    <div class="panel">
      <p>
        This approach generalizes widely because JSON is very versatile.  Indeed, its success as an
        interchange format can be attributed to that versatility.  Using the technique described
        above, Jsonnet can output any format that can be represented in JSON.
      </p>
    </div>
    <div style="clear: both"></div>
  </div>
</div>