Ajax Russia : Аякс по-русски

Свежие новости из мира IT

AJAX и собственно XML

ajax
Что такое AJAX, думаю, все уже знают и имеют небольшое представление о том, как он работает. Но всё же много людей до сих пор представления не имеют о том, каким боком собственно XML, так как большинство ресурсов расписывают работу только со свойством responseText, не говоря уже о сторонних библиотеках (prototype, sAjax и прочее).

Почему XML?

Некоторые люди говорят, что AJAX прозвали именно AJAX’ом потому что это «прикольно». Цитата: «У американцев есть манечка, придумывать красивые аббривиатуры, они ведь не назовут технологию AJAT(response text), AJAX звучит на порядок лучше». Но это не так. Технология AJAX действительно придумана и разработана для работы с XML данными.

XML (EXtensible Markup Language) - разработан для хранения и передачи данных. Очень простой в изучении и использовании язык разметки. В настоящее время нашел широкое применение в прикладном программировании, особенно после выпуска Microsoft Visual Studio 8 и 9 (xml manifest, config, и т.д.). Есть несколько ресурсов, которые вообще отказались от HTML, CSS и полностью перешли на XML. Сразу возникает вопрос? А как же визуальная разметка? Здесь, на помощь приходит XSLT – EXtensible Stylesheet Language. Но в нашем случае вещь бесполезная, так как мы будем внедрять XML данные в уже оформленный HTML документ.

С чего начать?

Надеюсь все уже догадываются о том, что суть AJAX в использовании нестандартного объекта – XMLHttpRequest, для общения со сторонними ресурсами. Итак, начнем с универсальной функции для создания xmlHttp объекта в различных браузерах. Выглядит она примерно так:

JavaScript:
  1. function getXmlHttp(){
  2.     var xmlhttp;
  3.     try {
  4.         xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
  5.     } catch (e) {
  6.         try {
  7.             xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
  8.         } catch (E) {
  9.             xmlhttp = false;
  10.         }
  11.     }
  12.  
  13.     if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
  14.         xmlhttp = new XMLHttpRequest();
  15.     }
  16.     return xmlhttp;
  17. }

Сам объект XMLHttpRequest понимают только Firefox, Opera 8+ и Safari, так что для вредного ослика мы будем использовать его ActiveX объект, который имеет те же методы что и XMLHttpRequest. Кстати, компания Microsoft – первый, кто представил такой объект, а Firefox, Opera, Safari и другие браузеры последовали.

Краткое введение в AJAX

В рамках данной статьи мы будем использовать запрос с методом GET. Делается это в две строки, не считая инициализацию объекта xmlHttp:

JavaScript:
  1. var xmlHttp;
  2. xmlHttp = getXmlHttp();
  3. xmlHttp.open('GET', 'http://www.example.ru/data.xml', true);
  4. xmlHttp.send(null)

Где http://www.example.ru/data.xml сторонний ресурс содержащий XML данные. НО, прежде чем отсылать куда-то запрос, советую сразу установить «слушатель» для данного объекта. «Слушатель» устанавливается таким образом:

JavaScript:
  1. xmlHttp.onreadystatechange = nameOfFunction;

Где nameOfFunction – имя функции которую следует вызвать при смены состояния объекта xmlHttp. Список всевозможных состояний:

  • 0 – не инициализирован
  • 1 – загрузка
  • 2 – загрузка завершена
  • 3 – обработка
  • 4 – готово

Следовательно, откликаться мы будем только по состоянию 4 – готово.

JavaScript:
  1. function nameOfFunction() {
  2.     if (xmlHttp.readyState == 4)
  3.     {
  4.         // что нибудь делаем
  5.     }
  6. }

То же самое можно написать и в одном блоке:

JavaScript:
  1. xmlHttp.onreadystatechange = function() {
  2.     if (xmlHttp.readyState == 4)
  3.     {
  4.         // что нибудь делаем
  5.     }
  6. }

Далее следует проверить полученный код статуса HTTP сервера, но это не в рамках нашего сюжета. Сконцентрируемся на XML.

Прием и обработка данных

К полученным данным вы можете получить доступ двумя способами:

  • xmlHttp.responseText
  • xmlHttp.responseXML

Нас, в данном случае, интересует только второй способ. Делается это вот таким образом:

JavaScript:
  1. var xmlDoc = xmlHttp.responseXML.documentElement;

xmlHttp.responseXML.documentElement – это объект содержащий весь, полученный XML документ. Теперь нам следует его обработать, то есть «выдернуть» из негу нужную нам информацию, в нужном нам порядке. Для этого мы будем использовать методы DOM (Data Object Model), а именно getElementsByTagName(). В цикле по главному (не путать с корневым) элементу XML документа мы можем пройти через все интересующие нас записи. Для примера рассмотрим простой XML документ:

XML:
  1. <?xml version="1.0" encoding="windows-1251"?>
  2. <newsarchive>
  3.     <entry>
  4.         <id>73</id>
  5.         <title>заголовок первой статьи</title>
  6.         <content>содержание первой статьи</content>
  7.         <date>2008-03-04 05:03:24</date>
  8.     </entry>
  9.     <entry>
  10.         <id>74</id>
  11.         <title>заголовок второй статьи</title>
  12.         <content>содержание второй статьи</content>
  13.         <date>2008-03-10 15:21:39</date>
  14.     </entry>
  15. </newsarchive>

Пускай это будет простой новостной архив из 2х записей. Таким образом, главным нашим элементом будет являться элемент entry, так как он и содержит несущую смысл информацию. На самом деле всё зависит от структуры документа, его элементной вложенности. XML позволяет писать какие угодно тэги, какой угодно вложенности, так что структура остаётся на усмотрение самого автора.

Вернемся к нашему XML документу. Мы будем просматривать каждый элемент entry в цикле, а данные элемента (id, title, content, date) будем добавлять (appendChild) в определенном порядке к какому-либо объекту, например data_div (document.getElementById). Примерно так:

JavaScript:
  1. var xmlDoc = xmlHttp.responseXML.documentElement;
  2. var dataArray = xmlDoc.getElementsByTagName("entry");
  3. obj = document.getElementById("data_div");
  4. for (var i = 0; i <dataArray.length; i++)
  5. {
  6.     var new_el = document.createElement("div");
  7.     new_el.innerHTML = '<b>' + xmlDoc.getElementsByTagName("title")[i].childNodes[0].nodeValue + '</b><br>' + xmlDoc.getElementsByTagName("date")[i].childNodes[0].nodeValue + '<br>' + xmlDoc.getElementsByTagName("content")[i].childNodes[0].nodeValue + '<br><br>';
  8.     obj.appendChild(new_el);
  9. }

Сводим все в одно

Итак, какой-нибудь HTML документ, который будет обращаться к XML файлу за данными. В нём div куда будут добавляться данные, и ссылка для посылки запроса:

HTML:
  1. <div id="data_div">
  2.     <a href="#" onclick="getSomeData(); return false;">получить данные</a><br>
  3. </div>

Javascript функция getSomeData():

JavaScript:
  1. function getSomeData() {
  2.     var xmlHttp;
  3.     xmlHttp = getXmlHttp();
  4.  
  5.     xmlHttp.onreadystatechange = function() {
  6.         if (xmlHttp.readyState == 4)
  7.         {
  8.             var xmlDoc = xmlHttp.responseXML.documentElement;
  9.             var dataArray = xmlDoc.getElementsByTagName("entry");
  10.             obj = document.getElementById("data_div");
  11.             for (var i = 0; i <dataArray.length; i++)
  12.             {
  13.                 var new_el = document.createElement("div");
  14.                 new_el.innerHTML = '<b>' + xmlDoc.getElementsByTagName("title")[i].childNodes[0].nodeValue + '</b><br>' + xmlDoc.getElementsByTagName("date")[i].childNodes[0].nodeValue + '<br>' + xmlDoc.getElementsByTagName("content")[i].childNodes[0].nodeValue + '<br><br>';
  15.                 obj.appendChild(new_el);
  16.             }
  17.         }
  18.     }
  19.  
  20.     xmlHttp.open('GET', 'data.xml', true);
  21.     xmlHttp.send(null);
  22. }

XML документ data.xml (повторно):

XML:
  1. <?xml version="1.0" encoding="windows-1251"?>
  2. <newsarchive>
  3.     <entry>
  4.         <id>73</id>
  5.         <title>заголовок первой статьи</title>
  6.         <content>содержание первой статьи</content>
  7.         <date>2008-03-04 05:03:24</date>
  8.     </entry>
  9.     <entry>
  10.         <id>74</id>
  11.         <title>заголовок второй статьи</title>
  12.         <content>содержание второй статьи</content>
  13.         <date>2008-03-10 15:21:39</date>
  14.     </entry>
  15. </newsarchive>

Заключение

AJAX, чаще всего, работает с динамическими данными. Возможно ли динамически подавать XML документ? Конечно, любой серверный язык может выдать документ в виде XML, а в функцию xmlHttp.open() спокойно можно подставить data.php вместо data.xml. Главное помнить об одном – некоторые браузеры (в частности Internet Explorer) воспринимают XML файл только тогда, когда он действительно XML файл. То есть в вашем серверном скрипте нужно обязательно выслать заголовок браузеру, о том что вывод – XML. Конкретнее на примере PHP:

PHP:
  1. header('Content-type: application/xml');

Вы так же можете воспользоваться javascript функцией:

JavaScript:
  1. xmlHttp.overrideMimeType('application/xml');

Полезные ссылки

del.icio.us Забобрить!

22 Comments so far

  1. andead March 14th, 2008 08:15

    нигде не видел такого подробного описания работы с AJAX + XML, спасибо огромное!))

  2. anton March 14th, 2008 08:44

    За статью спасибо, хотя я это уже всё знаю, буду тыкать в неё новичков.
    Правда я всёже предпочитаю json, мне кажется он полегче (а в этом какраз и смысл - сократить передаваемый трафик), да и сформировать для отдачи его проще.

  3. Константин March 14th, 2008 14:11

    Andead, Anton - не за что, рад что вам понравилось. Anton, я не буду с вами спорить по этому поводу. Я ничего не имею против JSON, и совершенно согласен, что он чуток быстрее чем XML, но всё же думаю это разные вещи. “XML против JSON” неверное выражение. На самом деле оно должно звучать так - “Где XML, а где JSON?”. Я постараюсь написать об этом в другой статье ;)

  4. aJIeks March 14th, 2008 15:22

    интересно :) было бы не плохо если бы еще были примеры с использованием распространенных фреймворков к примеру prototype :)

  5. Zelman March 14th, 2008 15:57

    ВО! отличная статья… начинаю потихоньку врубаться!
    Спасибо!

  6. Константин March 14th, 2008 16:04

    Алекс, in my humble opinion, prototype создан для ленивых ;) да и вот перегружает он малость оперативку когда что-то комплексное “играет”.. А вот если понимать саму суть, как всё работает, то можно писать отличный, а главное чистый код, что может быть и займет больше времени, зато нет необходимости передавать ненужные данные бедным дайлапщикам ;)) я всегда сравниваю prototype с .net framework, 3.5 блин полтора часа только ставится, зато возможности его поражают. Но .NET заходит глубоко под систему, а вот неуверен насколько prototype или jQuery могут зайти глубже самого javascript ;) только если ради каких-либо удобств, например $(main) вместо document.getElementById(main) - потому и для ленивых ;)))

  7. Aleksandr March 14th, 2008 17:17

    Тут я не соглашусь.

    Во первых если над сайтом работают несколько человек - прототайп упрощает работу. Всё таки он предполагает некоторые стандарты программирования и мне не придётся вникать в “супер” аякс функцию Васи Пупкина. Потом каждый релиз прототайпа и других библиотек протестированы со всеми браузерами, что со своей библиотекой ты не будешь делать. Потом в ptototype кроме аякса - ещё куча полезностей. Один Enumerable чего стоит. А тем кто работает с фреймворками типа Rails, Symphony и тд что делать? Отказаться от яваскрипт библиотек, только потому что всё можно написать самому?

    Я думаю что в реальных рабочих условиях прототайп и подобные подходят больше.

  8. Константин March 14th, 2008 17:57

    Тоже верно, но работа в одинокого и работа в команде очень сильно отличаются. Ну.. Если Вася Пупкин в коментах написал, что его супер функция выполняет такие-то такие-то пупер действия, то вряд ли у кого возникнут вопросы к Васи Пупкину ;)

    Я не говорю, что prototype бесполезная вещь. Я уверен, что в ней есть свой изюм. Но если мы воспользовались библиотекой на 5-10%, то зачем подгружать остальные 90? В крупномасштабных проектах, где prototype изъят до 99% естественно бредовая идея изобретать колесо, здесь, не согласиться я просто не могу ;)

  9. Sergey March 14th, 2008 19:15

    Меня мучало дежавю… Где-то на http://www.ibm.com/developerworks я такое уже читал. (К сожалению найти не смог.)

    Но хочу отметить, что статья написана на понятном языке (как и обещалось)).

  10. Денис Радченко March 14th, 2008 20:46

    JS фреймворки еще и способ забыть про особенности Javascript для каждого браузера. Если вы профи и можете написать что-то вроде LightBox’а бысто и хорошо - это замечательно. Мне проще взять готовое решение и не мучиться с поддержкой этого кода.

  11. Константин March 15th, 2008 11:23

    Денис, я с вами полностью согласен, взять готовое решение всегда проще и надежнее, но если вдруг понадобилось что то добавить, то тут уже сложнее, нежели если бы всё было написано вами.

    Сергей, ibm.com редко читаю, но об этом много информации на http://www.w3schools.com и http://developer.mozilla.org

  12. Алексей March 26th, 2008 00:26

    вопрос чисто практический и может оффтоповый: а не удобно ли переводить XML в JSON и потом проводить работу по “разбору” получившегося массива средствами тех же всеми любимых библиотек?
    и еще - какие могут быть адекватные причины использовать самописный объект для XMLHTTP, когда можно использовать все те же библиотеки?

    Если статья имела чисто познавательный характер - преклоняюсь как и многие перед подробностью!

  13. Константин March 26th, 2008 12:48

    Алексей, да, может быть вам и удобнее работать с JSON, но схватка XML vs JSON похожа на JPG vs PNG. Всё зависит от того где, как и зачем.

  14. Алексей March 26th, 2008 20:09

    ну не скажите))) PNG имеет явное преимущество - наличием альфаканала!

  15. Константин March 27th, 2008 16:42

    Нет, я вовсе не об альфаканале )) я же сказал - “где, как и зачем”.. Вы же не будете хранить фотографии в PNG, а вот графику с альфа прозрачностью будете. Если вам нужна анимация то вы используете GIF, ну и так далее.. Та же история с ajaxом, преимущества есть как у json так и у xml, ну плюс еще личные нравы и привычки…

  16. Dmitriy April 14th, 2008 20:07

    Спасибо большое за статьи. Много искал… Редко где попадаются настолько чёткие и ясные. Спасибо!

  17. Samolisov Pavel April 23rd, 2008 09:06

    >> Алексей, да, может быть вам и удобнее работать с JSON, но схватка XML vs JSON похожа на JPG vs PNG. Всё зависит от того где, как и зачем.

    Совершенно согласен с вами - все зависит от того где как и зачем. Сейчас мы говорим об асинхронном взаимодействии сервера и клиента (браузера). Браузер умеет выполнять JavaScript - все на этом его интерактивность заканчивается. JSON - это нативная ява-скриптовая нотация, поэтому ИМХО в данном конкретном случае (асинхронное взаимодействие сервера и клиента) JSON будет предпочтительнее. Можно конечно говорить о веб-сервисах, RSS и прочем - но это уже будет несколько офтоп.

    А вообще очень плотно сталкивался с порочной практикой когда на клиента передавали уже целиком сформированый html (xhtml). Это вообще ахтунг.

  18. Константин April 23rd, 2008 10:17

    Дмитрий, пожалуйста.

    Павел, вы совершенно правильно говорите, правда в данном уроке у нас вопрос не технологический, а более “педагогический”. Ведь прежде чем работать с JSON, Prototype, Scriptaculous и прочее, необходимы хотя бы базовые знания как работает js вместе с xml (первоначальная задумка AJAX). Ну по крайней мере я так считаю.

    Да, и огромным плюсом будет эти знания при столкновении с RSS лентами ;)

    И по поводу передачи html целиком. Может быть это и не совсем правильно, но не такой уж это и ахтунг. Тут тоже всё зависит от ситуации, ну в качестве примера возьмем мультитаб (я писал про это в уроке о prototype). Допустим нам нужно подгрузить комплексную таблицу, с картинками, flash/silverlight и еще куча тэгов. Что если посетитель не нажмёт на этот конкретный таб? Зачем хранить кучу лишнего парсинга если клиент этим, вероятно, не воспользуется? В таком случае очень даже не помешало бы подгружать html целиком.

  19. Samolisov Pavel April 23rd, 2008 11:10

    Насчет html-целиком - я согласен возможно это и имеет смысл но все в меру. Единственное применение такого метода я вижу только если формируется очень сложная разметка с использованием серверных шаблонов или компонентов (Tapestry например). Тогда и правда нет смысла писать тонну ява-скрипта, когда все написано до тебя разработчиками того же Tapestry, JSF или еще чего-то. Хотя уже появляются и чисто клиентские либы для сложных компонентов, которым как раз надо лишь получить с севера JSON, а там они нарисуют все что надо. Тут все ооочень индивидуально. Ахтунг же относилось именно к той реализации, которую пришлось рефакторить.

    Про педагогичность - согласен. Конечно “X” в слове “AJAX” это “XML”, из песни слов не выкинешь и про это конечно надо рассказывать ))) А потом про JSON )

  20. Константин April 23rd, 2008 13:39

    Уважаю ;)

  21. [...] AJAX и собственно XML [...]

  22. постер July 17th, 2008 09:25

    Прелестно)

Leave a reply