Получение данных в формате XML

С одной стороны, обмен данными в текстовом формате является простым, но с другой стороны, это влечет за собой жесткую зависимость между клиентским и серверным кодами. Если разработкой проекта занимаются разные люди, а обычно так и бывает, то такой способ обмена данными не является эффективным. При обмене данными в формате XML разработчики могут заранее договориться о формате XML-документа, и в дальнейшем каждый будет выполнять свою часть работы, опираясь на согласованный формат.

Прежде чем рассматривать обработку данных в формате XML с помощью JavaScript, напомним некоторые правила создания простейших XML-документов. XML-документ состоит из двух разделов — пролога и тела документа. В прологе указывается объявление XML:

<?xml version="1.0" encoding="utf-8" ?>

В параметре encoding указывается кодировка XML-документа. Если она не указана, то по умолчанию используется кодировка UTF-8.

Тело XML-документа должно находиться внутри корневого тега. Обычно имя тега совпадает с именем документа:

<?xml version="1.0" encoding="utf-8" ?>
<ajax>
<!-- Тело XML-документа -->
</ajax>

При указании имени тега необходимо помнить, что регистр символов имеет значение. Имена должны начинаться с буквы и содержать буквы, цифры или символ подчеркивания. В отличие от HTML-тегов, в XML пространство имен выбирает сам разработчик.

Следует учитывать, что каждому открывающему тегу должен соответствовать закрывающий тег:

<item></item>

Кроме того, должна соблюдаться вложенность тегов. Если элемент является пустым, то он может быть записан следующим образом:

<item/>

XML-теги могут иметь параметры. Параметр указывается в формате:

<Имя параметра>="<Значение>"

Значение параметра обязательно должно быть указано в кавычках, а сам параметр указывается в открывающем теге:

<item id="5">Данные</item>

Все специальные символы внутри тегов и в значениях параметров должны быть заменены мнемоническими именами:

  • &lt; — знак меньше (<);
  • &gt; — знак больше (>);
  • &amp; — амперсанд (&);
  • &quot; — кавычка (");
  • &apos; — апостроф (').

Внутри тегов можно использовать комментарии, которые имеют синтаксис, похожий на синтаксис HTML-комментариев:

<!-- Это комментарий -->

Следование этим несложным правилам избавит от множества проблем при работе с XML-документами.

Теперь рассмотрим получение данных в формате XML на примере. Создадим документ с формой (листинг 3.7), который будет обмениваться данными с файлом ajax.php (листинг 3.8).

Листинг 3.7. Получение данных в формате XML

<!doctype html>
<html lang="ru">
<head>
   <meta charset="utf-8">
   <meta name="viewport"
      content="width=device-width, initial-scale=1, shrink-to-fit=no">
   <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">
   <title>Получение данных в формате XML</title>
</head>
<body>
<div class="container my-3">
  <form action="ajax.php" method="GET" onsubmit="return false;">
    <div class="form-group">
      <input type="text" class="form-control" id="txt1">
    </div>
    <div class="form-group">
      <input type="text" class="form-control" id="txt2">
    </div>
    <button type="button" class="btn btn-primary"
            id="btnSend">Отправить методом GET</button>
  </form>
</div>
<div class="container my-3">
   <div id="div_ajax"></div>
</div>

<script>
function processReqChange(req) {
   // Обрабатываем асинхронный запрос
   try {
      if (req.readyState == 4) {
         if (req.status == 200) { // Запрос успешно обработан
            var xml = req.responseXML;
            var serverData = xml.getElementsByTagName('serverData');
            var txt1 = serverData.item(0)
                            .getElementsByTagName('txt1').item(0);
            var txt2 = serverData.item(0)
                            .getElementsByTagName('txt2').item(0);
            var msg = txt1.firstChild.data + '<br>' + 
                      txt2.firstChild.data;
            document.getElementById('txt1').value = '';
            document.getElementById('txt2').value = '';
            document.getElementById('div_ajax').innerHTML = msg;
         }
         else {
            document.getElementById('div_ajax').innerHTML = 'Ошибка';
         }
      }
   }
   catch(e) {
      document.getElementById('div_ajax').innerHTML = 'Ошибка';
   }
}

function sendReqGET() {
   // Отправка запроса методом GET
   if ( !window.XMLHttpRequest ) {
      window.alert('Ваш Web-браузер не поддерживает XMLHttpRequest');
      return;
   }
   var txt1 = document.getElementById('txt1').value;
   var txt2 = document.getElementById('txt2').value;
   if (txt1 === '' || txt2 === '') {
      window.alert('Не заполнено поле');
      return;
   }
   var url = '/ajax.php?txt1=' + encodeURIComponent(txt1);
   url += '&txt2=' + encodeURIComponent(txt2);
   // Создание объекта XMLHttpRequest
   var req = new XMLHttpRequest();
   // Подготовка асинхронного запроса методом GET
   req.open('GET', url, true);
   req.onreadystatechange = function() {
      processReqChange(req);
   };
   req.onloadstart = function() {
      document.getElementById('div_ajax').innerHTML = 'Загрузка...';
   };
   // Отправляем запрос
   req.send(null);
}
document.getElementById('btnSend').onclick = sendReqGET;
</script>
</body>
</html>

Листинг 3.8. Исходный код файла ajax.php

<?php
// Запрещаем кеширование
header('Expires: Tue, 12 May 2020 01:00:00 GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Pragma: no-cache');
// Указываем MIME-тип и кодировку
header('Content-Type: text/xml; charset=utf-8');
echo '<?xml version="1.0" encoding="utf-8" ?>', "\n";
echo "<ajax>\n";
echo "   <serverData>\n";
if ( isset($_GET['txt1']) && isset($_GET['txt2']) ) {
   echo '      <txt1>';
   echo 'Поле 1 – ';
   echo htmlspecialchars($_GET['txt1'], ENT_COMPAT, 'UTF-8');
   echo "</txt1>\n";
   echo '      <txt2>';
   echo 'Поле 2 – ';
   echo htmlspecialchars($_GET['txt2'], ENT_COMPAT, 'UTF-8');
   echo "</txt2>\n";
}
echo "   </serverData>\n";
echo "</ajax>\n";

После заполнения двух полей и щелчка на кнопке Отправить методом GET внутри функции sendReqGET() получаем значение текстовых полей и сохраняем их в переменных txt1 и txt2. Далее проверяем, заполнены ли поля ввода, и, если они не заполнены, выводим сообщение и завершаем выполнение функции.

Затем формируем строку запроса, которую будем передавать методом GET. Все данные, введенные пользователем в поля ввода, перекодируем с помощью функции encodeURIComponent(). Сформированную строку сохраняем в переменной url:

var url = '/ajax.php?txt1=' + encodeURIComponent(txt1);
url += '&txt2=' + encodeURIComponent(txt2);

На следующем этапе создаем объект XMLHttpRequest. Далее с помощью метода open() подготавливаем объект к отправке асинхронного запроса методом GET:

req.open('GET', url, true);

В свойстве onreadystatechange указываем функцию-обработчик и с помощью метода send() отправляем запрос на сервер:

req.send(null);

Теперь рассмотрим, что происходит при получении запроса сервером. Получив запрос, сервер создаст две переменные окружения: $_GET['txt1'] и $_GET['txt2']. Для корректного отображения отправленной информации указываем MIME-тип и кодировку с помощью функции header():

header('Content-Type: text/xml; charset=utf-8');

Если MIME-тип не указан, то получить данные с помощью свойства responseXML не получится. Однако можно после создания объекта XMLHttpRequest до вызова метода send() явным образом указать MIME-тип с помощью метода overrideMimeType(), не полагаясь на заголовки ответа сервера:

if (req.overrideMimeType) {
   req.overrideMimeType('text/xml');
}

Далее формируем XML-документ, который отправим в ответ на запрос. В результате Web-браузер получит следующий XML-документ:

<?xml version="1.0" encoding="utf-8" ?>
<ajax>
   <serverData>
      <txt1>Поле 1 – Строка 1</txt1>
      <txt2>Поле 2 – Строка 2</txt2>
   </serverData>
</ajax>

После получения ответа XML-документ будет доступен через свойство responseXML внутри функции processReqChange():

var xml = req.responseXML;

С помощью метода getElementsByTagName() получаем массив всех элементов serverData и сохраняем его в переменной serverData:

var serverData = xml.getElementsByTagName('serverData');

Получить доступ к отдельному элементу массива позволяет метод item(). Нумерация элементов начинается с нуля. Общее количество элементов можно получить с помощью свойства length:

var count = serverData.length;
console.log(count);

С помощью цикла for мы можем получить доступ к каждому элементу serverData:

for (var i = 0; i < count; i++) {
   // ...
}

Доступ к элементам txt1 и txt2 внутри элемента serverData также происходит с помощью метода getElementsByTagName():

var txt1 = serverData.item(0).getElementsByTagName('txt1').item(0);
var txt2 = serverData.item(0).getElementsByTagName('txt2').item(0);

Получить доступ к элементу можно по индексу, указанному в квадратных скобках:

var txt1 = serverData[0].getElementsByTagName('txt1')[0];
var txt2 = serverData[0].getElementsByTagName('txt2')[0];

Чтобы получить данные внутри элементов txt1 и txt2, следует воспользоваться свойством firstChild. Свойство firstChild содержит информацию о длине строки (свойство length) и текстовых данных элемента (свойство data). Именно свойство data позволяет нам получить переданные данные и сформировать строку для вывода результата:

var msg = txt1.firstChild.data + '<br>' + txt2.firstChild.data;
document.getElementById('div_ajax').innerHTML = msg;

В нашем примере всего один элемент serverData, поэтому достаточно сразу найти элементы txt1 и txt2. Давайте рассмотрим это на примере (листинг 3.9), а заодно укажем тип документа в свойстве responseType и получим ответ сервера с помощью свойства response.

Листинг 3.9. Свойства responseType и response

<!doctype html>
<html lang="ru">
<head>
   <meta charset="utf-8">
   <meta name="viewport"
      content="width=device-width, initial-scale=1, shrink-to-fit=no">
   <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">
   <title>Свойства responseType и response</title>
</head>
<body>
<div class="container my-3">
  <form action="ajax.php" method="GET" onsubmit="return false;">
    <div class="form-group">
      <input type="text" class="form-control" id="txt1">
    </div>
    <div class="form-group">
      <input type="text" class="form-control" id="txt2">
    </div>
    <button type="button" class="btn btn-primary"
            id="btnSend">Отправить методом GET</button>
  </form>
</div>
<div class="container my-3">
   <div id="div_ajax"></div>
</div>

<script>
function onloadXML(req) {
   try {
      if (req.status == 200) { // Запрос успешно обработан
         var xml = req.response;
         var txt1 = xml.getElementsByTagName('txt1').item(0);
         var txt2 = xml.getElementsByTagName('txt2').item(0);
         var msg = txt1.firstChild.data + '<br>' + 
                   txt2.firstChild.data;
         document.getElementById('txt1').value = '';
         document.getElementById('txt2').value = '';
         document.getElementById('div_ajax').innerHTML = msg;
      }
      else {
         document.getElementById('div_ajax').innerHTML = 'Ошибка';
      }
   }
   catch(e) {
      document.getElementById('div_ajax').innerHTML = 'Ошибка';
   }
}

function sendReqGET() {
   // Отправка запроса методом GET
   if ( !window.XMLHttpRequest ) {
      window.alert('Ваш Web-браузер не поддерживает XMLHttpRequest');
      return;
   }
   var txt1 = document.getElementById('txt1').value;
   var txt2 = document.getElementById('txt2').value;
   if (txt1 === '' || txt2 === '') {
      window.alert('Не заполнено поле');
      return;
   }
   var url = '/ajax.php?txt1=' + encodeURIComponent(txt1);
   url += '&txt2=' + encodeURIComponent(txt2);
   // Создание объекта XMLHttpRequest
   var req = new XMLHttpRequest();
   // Подготовка асинхронного запроса методом GET
   req.open('GET', url, true);
   req.responseType = 'document';
   req.onerror = function() {
      document.getElementById('div_ajax').innerHTML = 'Ошибка';
   };
   req.onload = function() {
      onloadXML(req);
   };
   req.onloadstart = function() {
      document.getElementById('div_ajax').innerHTML = 'Загрузка...';
   };
   // Отправляем запрос
   req.send(null);
}
document.getElementById('btnSend').onclick = sendReqGET;
</script>
</body>
</html>

В этом примере мы указали тип документа в свойстве responseType:

req.responseType = 'document';

Даже если сервер не отправит заголовок с MIME-типом, ответ все равно будет правильно обработан и доступен через свойство response:

var xml = req.response;

Учебник по jQuery и AJAX
Учебник по jQuery и AJAX в формате PDF

Помощь сайту

ЮMoney (Yandex-деньги): 410011140483022

ПАО Сбербанк:
Счет: 40817810855006152256
Реквизиты банка:
Наименование: СЕВЕРО-ЗАПАДНЫЙ БАНК ПАО СБЕРБАНК
Корреспондентский счет: 30101810500000000653
БИК: 044030653
КПП: 784243001
ОКПО: 09171401
ОКОНХ: 96130
Скриншот реквизитов