This repository has been archived by the owner on May 26, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 16
/
ajax.xml
675 lines (540 loc) · 25.2 KB
/
ajax.xml
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
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
<?xml version="1.0" encoding="UTF-8"?>
<chapter version="5.0" xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:m="http://www.w3.org/1998/Math/MathML"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns:db="http://docbook.org/ns/docbook">
<title>Ajax</title>
<section>
<title>Introdução</title>
<para>O método XMLHttpRequest permite que navegadores se comuniquem com o
servidor sem precisar recarregar a página. Este método, também conhecido
como Ajax (Asynchronous JavaScript and XML - JavaScript Assíncrono e XML),
permite ter experiências ricas e interativas nas páginas web.</para>
<para>Requisições Ajax são disparadas por código JavaScript; seu código
envia uma requisição a uma URL, e quando recebe uma resposta, uma função de
callback pode ser acionada para tratá-la. Pelo motivo da requisição
ser assíncrona, o resto do seu código continurá executando enquanto a
requisição é processada, sendo assim, é imperativo que um callback seja usado
para lidar com a resposta.</para>
<para>O jQuery provê suporte Ajax que abstrai as dolorosas diferenças entre
navegadores. Ele oferece métodos completos como o <code>$.ajax()</code>,
e alguns métodos de conveniência como <code>$.get()</code>,
<code>$.getScript()</code>, <code>$.getJSON()</code>,
<code>$.post()</code> e <code>$().load()</code>.</para>
<para>A maior parte das aplicações jQuery não usam XML apesar do nome
"Ajax"; ao invés disso, elas transportam HTML puro ou JSON (JavaScript
Object Notation - Notação de Objeto do JavaScript).</para>
<para>Em geral, Ajax não funciona através de domínios diferentes.
As exceções são serviços que fornecem suporte ao JSONP (JSON com
padding), que permite uma limitada funcionalidade entre domínios.</para>
</section>
<section>
<title>Conceitos Chave</title>
<para>O uso apropriado de métodos relacionados ao Ajax requer o
conhecimento de alguns conceitos-chave.</para>
<section>
<title>GET vs. POST</title>
<para>Os métodos mais comuns para enviar uma requisição ao servidor são
o GET e o POST. É importante entender a aplicação apropriada para cada um.
</para>
<para>O método GET deve ser usado para operações não-destrutivas -
ou seja, operações que você apenas esteja "pegando" dados do servidor,
sem modificar nenhum dado no servidor. Por exemplo, uma consulta para
fazer uma busca pode ser uma requisição GET. Requisições GET podem ser
cacheadas pelo navegador, que pode levar a comportamentos imprevisíveis
se você não tomar cuidado. Requisições GET geralmente enviam todos os
seus dados na string de requisição.</para>
<para>O método POST deve ser usado para operações destrutivas - ou seja,
operações onde você muda dados no servidor. Por exemplo, um usuário salvando
o post de um blog deve ser uma requisição POST. Requisições POST geralmente
não são cacheadas pelo navegador; uma string de requisição pode fazer parte da
URL, mas os dados tendem a ser enviados separadamente como uma requisição
POST.</para>
</section>
<section>
<title>Tipos de dados</title>
<para>O jQuery geralmente requer alguma instrução a respeito do tipo de
dados que você espera obter com uma requisição Ajax; em alguns casos, o
tipo de dado é especificado no nome do método e em outros casos é
fornecido como parte do objeto de configuração. Há várias opções:</para>
<variablelist>
<varlistentry>
<term>texto</term>
<listitem>
<para>Para transportar strings simples</para>
</listitem>
</varlistentry>
<varlistentry>
<term>html</term>
<listitem>
<para>Para transportar blocos de HTML para serem colocados
na página</para>
</listitem>
</varlistentry>
<varlistentry>
<term>script</term>
<listitem>
<para>Para adicionar um novo script à página</para>
</listitem>
</varlistentry>
<varlistentry>
<term>json</term>
<listitem>
<para>Para transportar dados formatados no estilo JSON, que pode
incluir strings, arrays e objetos<note>
<para>No jQuery 1.4, se os dados JSON enviados pelo seu
servidor não estiverem propriamente formatados, a requisição
pode falhar silenciosamente. Dê uma olhada em
<link xlink:href="http://json.org">http://json.org</link> para
detalhes sobre formatação correta do JSON, mas como regra geral,
use métodos já prontos da linguagem usada no servidor para gerar
JSON sem erros de sintaxe.</para>
</note></para>
</listitem>
</varlistentry>
<varlistentry>
<term>jsonp</term>
<listitem>
<para>Para transportar dados JSON de outro domínio.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>xml</term>
<listitem>
<para>Para transporte de dados em um XML</para>
</listitem>
</varlistentry>
</variablelist>
<remark>Eu sou um forte proponente no uso de JSON na maioria dos casos,
de forma que ele provê a maior flexibilidade. É especialmente útil para
enviar HTML e dados ao mesmo tempo.</remark>
</section>
<section>
<title>A é de assíncrono</title>
<para>A assincronicidade do Ajax pega muitos novos usuários do jQuery
desprevinidos. Pelo fato das chamadas Ajax serem assíncronas por padrão,
a resposta não estará disponvível imediatamente. Respostas só podem ser
manipuladas por um callback. Então, por exemplo, o código seguinte não
irá funcionar:</para>
<programlisting>$.get('foo.php');
console.log(response);</programlisting>
<para>Ao invés disso, nós temos que passar um função callback para
nossa requisição; Este callback será executado quando a requisição
for realizada com sucesso, e é neste ponto que poderemos acessar os
dados que ela retornou, se houver algum. <programlisting>$.get('foo.php', function(response) { console.log(response); });</programlisting></para>
</section>
<section>
<title>Regra da mesma origem e JSONP</title>
<para>Em geral, as requisições Ajax são limitadas ao mesmo protocolo
(http ou https), a mesma porta, e ao mesmo domínio da página que
está fazendo a requisição. Estas limitações não se aplicam a scripts que
são carregados pelos métodos Ajax do jQuery.</para>
<para>As outras exceções são requisições direcionadas a um serviço JSONP
em outro domínio. No caso do JSONP, o provedor do serviço tem que concordar
em responder a sua requisição com um script que pode ser carregado dentro
da mesma página usando uma tag <code><script></code>, assim evitando
a limitação da mesma origem; este script terá os dados que você requisitou
encapsulado em uma função de callback que você especificou.</para>
</section>
<section>
<title>Ajax e o Firebug</title>
<para>O Firebug (ou o Webkit Inspector no Chrome ou Safari) é uma
ferramenta indispensável para trabalhar com requisições Ajax. Você
pode ver as requisições Ajax no mesmo instante que elas acontecem na
tab Console do Firebug (e no painel Resources > XHR do Webkit Inspector),
e você pode clicar numa requisição para expandí-la e ver os detalhes como
os headers de requisição, de resposta, conteúdo e mais. Se alguma coisa não
estiver acontecendo como esperado com uma requisição Ajax, este é o primeiro
lugar para ver o que está acontecendo de errado.</para>
</section>
</section>
<section>
<title>Métodos do jQuery relacionados ao Ajax</title>
<para>Enquanto o jQuery oferece muitos métodos convenientes relacionados
ao Ajax, o coração de todos eles é o método <code>$.ajax</code> e entendê-lo
é imperativo. Nós vamos revisá-lo primeiro e então dar uma olhada rápida
nos métodos de conveniência.</para>
<remark>Eu geralmente uso o método $.ajax e não uso os métodos de conveniência.
Como você poderá ver, ele fornece recursos que os métodos de conveniência não
oferecem e sua sintaxe é mais facilmente inteligível, na minha opinião.</remark>
<section>
<title>$.ajax</title>
<para>O método core <code>$.ajax</code> é uma forma simples e poderosa
de criar requisições Ajax. Ele utiliza um objeto de configuração que
contém todas as instruções que o jQuery precisa para completar a requisição.
O método <code>$.ajax</code> é particularmente útil porque ele oferece a
habilidade de especificar callbacks de sucesso e falha. Há também a
possibilidade de pegar um objeto de configuração definido separadamente,
fazendo que seja fácil escrever código reutilizável. Para documentação
completa das opções de configuração, visite <link
xlink:href="http://api.jquery.com/jQuery.ajax/">http://api.jquery.com/jQuery.ajax/</link>.</para>
<example>
<title>Usando o método core $.ajax</title>
<programlisting>$.ajax({
// a URL para requisição
url : 'post.php',
// Os dados a serem enviados
// (serão convertidos em uma string de requisição)
data : { id : 123 },
// se esta é uma requisição POST ou GET
method : 'GET',
// o tipo de dados que nós esperamos
dataType : 'json',
// código a ser executado se a requisição
// for executada com sucesso; a resposta
// é passada para a função
success : function(json) {
$('<h1/>').text(json.title).appendTo('body');
$('<div class="content"/>')
.html(json.html).appendTo('body');
},
// código a ser executado se a requisição
// falhar. A requisição bruta e os códigos
// de status são passados para função
error : function(xhr, status) {
alert('Desculpa, aconteceu um problema!');
},
// Código a ser executado independetemente
// do sucesso ou falha
complete : function(xhr, status) {
alert('A requisição está completa!');
}
});</programlisting>
</example>
<note>
<para>Uma nota a respeito da configuração <code>dataType</code>: se o
servidor enviar dados que estão num formato diferente que você especificou,
seu código poderá falhar, e a razão nem sempre será clara, por que o
código de resposta HTTP não irá mostrar um erro. Quando estiver trabalhando
com requisições Ajax, tenha certeza que o servidor está retornando
os dados com o formato que você especificou e verifique se o header
Content-type está de acordo com o tipo de dados. Por exemplo, para dados
JSON, o header Content-type deve ser <code>application/json</code>.</para>
</note>
<section>
<title>Opções do <code>$.ajax</code></title>
<para>Há várias, várias opções para o método $.ajax, que é parte do
seu poder. Para uma lista completa de opções, visite <link
xlink:href="http://api.jquery.com/jQuery.ajax/">http://api.jquery.com/jQuery.ajax/</link>;
aqui vão algumas opções que você irá usar frequentemente:</para>
<variablelist>
<varlistentry>
<term>async</term>
<listitem>
<para>Configure para <code>false</code> se a requisição deve ser
enviada de forma síncrona. O padrão é <code>true</code>. Perceba
que se você configurar esta opção para falso, sua requisição
bloqueará a execução de outro código até que a resposta seja
recebida.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>cache</term>
<listitem>
<para>Usado se a resposta disponível for cacheável. O padrão é
<code>true</code> para todos os tipos de dados, exceto "script"
e "jsonp". Quando setado para falso, a URL simplesmente terá um
parâmetro a mais anexado a ela para evitar o cache.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>complete</term>
<listitem>
<para>Uma função callback para executar quando a requisição
estiver completa, independetemente de sucesso ou falha. A função
recebe o objeto bruto da requisição e o texto de status da mesma.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>context</term>
<listitem>
<para>O escopo em que a função callback deve executar
(ou seja, o que <code>this</code> irá significar dentro da(s)
função(ões) callback). Por padrão, <code>this</code> dentro
das funções callback refere ao objeto originalmente passado
para <code>$.ajax</code>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>data</term>
<listitem>
<para>Os dados a serem enviados para o servidor. Isto pode ser tanto
um objeto quanto uma string de requisição, como
<code>foo=bar&baz=bim</code>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>dataType</term>
<listitem>
<para>O tipo de dado que você espera do servidor. Por padrão, o
jQuery irá olhar o MIME type da resposta se nenhum tipo de dados
for especificado.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>error</term>
<listitem>
<para>Uma função callback para ser executa se a requisição resultar
em um erro. A função recebe o objeto bruto de requisição e o texto
de status da requisição.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>jsonp</term>
<listitem>
<para>O nome da função de callback para enviar na string de requisição
quando estiver fazendo uma requisição JSONP. O padrão é "callback".</para>
</listitem>
</varlistentry>
<varlistentry>
<term>success</term>
<listitem>
<para>Uma função de callback para ser executada se a requisição
tiver êxito. A função recebe os dados de resposta (convertidos
para um objeto JavaScript se o tipo de dados for JSON), e o texto
de status da requisição e o objeto bruto da requisição.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>timeout</term>
<listitem>
<para>O tempo em milisegundos a se esperar antes de considerar
que a reqsuisição falhou.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>traditional</term>
<listitem>
<para>Configure para <code>true</code> para usar o tipo de serialização <code>param</code> em
versões anteriores ao jQuery 1.4. Para detalhes, veja: <link
xlink:href="http://api.jquery.com/jQuery.param/">http://api.jquery.com/jQuery.param/</link>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>type</term>
<listitem>
<para>O tipo da requisição, "POST" ou "GET". O padrão é "GET".
Outros tipos de requisições, como "PUT" e "DELETE" podem ser
utilizados, mas eles talvez não sejam suportados por todos os
navegadores.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>url</term>
<listitem>
<para>A URL para requisição.</para>
</listitem>
</varlistentry>
</variablelist>
<para>A opção <code>url</code> é a única propriedade obrigatória
do objeto de configuração do método <code>$.ajax</code>; todas as
outras propriedades são opcionais.</para>
</section>
</section>
<section>
<title>Métodos de conveniência</title>
<para>Se você não precisa da configuração extensiva do <code>$.ajax</code>,
e você não se preocupa sobre manipulação de erros, as funções
de conveniêcia providas pelo jQuery podem ser uma forma útil e lapidada
para executar requisições Ajax. Estes métodos são somente "encapsulamentos"
em torno do método <code>$.ajax</code>, e simplesmente pré setam algumas
das opções no método <code>$.ajax</code>.</para>
<para>Os métodos de conveniência providos pelo jQuery são:</para>
<variablelist>
<varlistentry>
<term>$.get</term>
<listitem>
<para>Executa uma requisição GET para a URL informada.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>$.post</term>
<listitem>
<para>Executa uma requisição POST para a URL informada.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>$.getScript</term>
<listitem>
<para>Adiciona um script à página.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>$.getJSON</term>
<listitem>
<para>Executa uma requisição GET com expectativa de retorno
de um JSON.</para>
</listitem>
</varlistentry>
</variablelist>
<para>Em cada caso, os métodos pegam os seguintes argumentos,
em ordem:</para>
<variablelist>
<varlistentry>
<term>url</term>
<listitem>
<para>A URL para requisição. Obrigatório.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>data</term>
<listitem>
<para>Os dados para serem enviados para o servidor.
Opcional. Pode ser tanto um objeto quanto uma string
de requisição, como
<code>foo=bar&baz=bim</code>.</para>
<note>
<para>Esta opção não é válida para
<code>$.getScript</code>.</para>
</note>
</listitem>
</varlistentry>
<varlistentry>
<term>callback de successo</term>
<listitem>
<para>Uma função de callback para executar se a requisição for
executada com sucesso. Opcional. A função recebe os dados de
resposta (convertidos para um objeto JavaScript se o tipo de
dados for JSON), assim como o texto de status e o objeto
bruto da requisição.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>tipo de dados</term>
<listitem>
<para>O tipo de dados que você espera de retorno do servidor.
Opcional.</para>
<note>
<para>Esta opção só é aplicável para métodos que ainda não
especificaram o tipo de dados no seu nome.</para>
</note>
</listitem>
</varlistentry>
</variablelist>
<example>
<title>Usando os métodos de conveniência do jQuery</title>
<para><programlisting>// pega um texto puro ou html
$.get('/users.php', { userId : 1234 }, function(resp) {
console.log(resp);
});
// adiciona um script na página, e então executa uma função
// definida nele
$.getScript('/static/js/myScript.js', function() {
functionFromMyScript();
});
// pega dados formatados em JSON do servidor
$.getJSON('/details.php', function(resp) {
$.each(resp, function(k, v) {
console.log(k + ' : ' + v);
});
});</programlisting></para>
</example>
</section>
<section>
<title><code>$.fn.load</code></title>
<para>O método <code>$.fn.load</code> é único dentre os métodos de
Ajax do jQuery que é chamado em uma seleção. O método <code>$.fn.load</code>
pega o HTML de uma URL, e usa o HTML retornado para popular o(s) elemento(s)
selecionados. Em adição à URL informada, você ainda pode informar um
seletor; o jQuery irá pegar somente o elemento correspondente do HTML
retornado.</para>
<example>
<title>Usando o <code>$.fn.load</code> para popular um elemento</title>
<programlisting>$('#newContent').load('/foo.html');</programlisting>
</example>
<example>
<title>Usando o <code>$.fn.load</code> para popular um elemento
baseado no seletor</title>
<programlisting>$('#newContent').load('/foo.html <emphasis role="bold">#myDiv h1:first</emphasis>', function(html) {
alert('Conteúdo atualizado!');
});</programlisting>
</example>
</section>
</section>
<section>
<title>Ajax e formulários</title>
<para>As funcionalidades de Ajax do jQuery podem ser especialmente úteis
ao lidar com formulários. O <link xlink:href="http://jquery.malsup.com/form/">jQuery
Form Plugin</link> é uma ferramenta bem testada para adicionar funcionalidades
de Ajax nos formulários e você deve usá-lo para manipular formulários com
Ajax ao invés de usar sua própria solução para alguma coisa mais complexa.
Mas ainda há dois métodos do jQuery relacionados à processamento de formulários
que você deve conhecer: <code>$.fn.serialize</code> e
<code>$.fn.serializeArray</code>.</para>
<example>
<title>Transformando os dados de um formulário em uma string de requisição</title>
<programlisting>
$('#myForm').serialize();
// cria uma estrutura como esta:
name=campo1&value=123
</programlisting>
</example>
<example>
<title>Criando um array de objetos contendo dados do formulário.</title>
<programlisting>$('#myForm').serializeArray();
// cria uma estrutura como esta:
[
{ name : 'campo1', value : 123 },
{ name : 'campo2', value : 'olá mundo!' }
]</programlisting>
</example>
</section>
<section>
<title>Trabalhando com JSONP</title>
<para>O advento do JSONP -- essencialmente um hack consensual para cross-site
scripting -- abriu a porta para mashups de conteúdo bem poderosos. Muitos
sites provêem serviços JSONP, permitindo que você acesse o conteúdo deles
através de uma API pré-definida. Uma boa fonte de dados formatados em
JSONP é o <link xlink:href="http://developer.yahoo.com/yql/console/">Yahoo! Query
Language</link>, que nós iremos usar no próximo exemplo para pegar notícias
a respeito de gatos.</para>
<example>
<title>Usando YQL e JSONP</title>
<programlisting>$.ajax({
url : 'http://query.yahooapis.com/v1/public/yql',
// o nome do parâmetro de callback,
// como é especificado pelo serviço do YQL
jsonp : 'callback',
// fala para o jQuery que estamos esperando JSONP
dataType : 'jsonp',
// fala para o YQL o que nós queremos e que queremos em JSON
data : {
q : 'select title,abstract,url from search.news where query="gato"',
format : 'json'
},
// trabalha com a resposta
success : function(response) {
console.log(response);
}
});</programlisting>
</example>
<para>O jQuery manipula todos os aspectos complexos por trás do JSONP --
tudo que nós temos que fazer é falar para o jQuery o nome do callback
JSONP especificado pelo YQL ("callback" neste caso), e todo o processo
se parece com uma requisição Ajax normal.</para>
</section>
<section>
<title>Eventos do Ajax</title>
<para>Frequentemente, você irá querer fazer algo depois que uma requisição
Ajax inicia ou termina, como exibir ou mostrar um indicador de carregamento.
Ao invés de definir este comportamento dentro de cada requisição Ajax, você
pode associar eventos do Ajax à elementos da mesma forma que você associa
outros eventos. Para uma lista completa de de eventos do Ajax, visite <link
xlink:href="http://docs.jquery.com/Ajax_Events">http://docs.jquery.com/Ajax_Events</link>.</para>
<example>
<title>Configurando um indicador de carregamento usando eventos do Ajax</title>
<programlisting>$('#loading_indicator')
.ajaxStart(function() { $(this).show(); })
.ajaxStop(function() { $(this).hide(); });</programlisting>
</example>
</section>
<section>
<title>Exercícios</title>
<xi:include href="exercises/load-external-content.xml"
xpointer="element(/1)" />
<xi:include href="exercises/load-json.xml" xpointer="element(/1)" />
</section>
</chapter>