Archiwum dla kategorii Ajax

JSON (JavaScript Object Notation) jest drugim, po XML, najpopularniejszym formatem przesyłania danych stosowanym w technologi AJAX. Niewątpliwą przewagą JSON’a nad XML’em jest jego natywne parsowanie po stronie klienta (funkcja JavaScriptu eval()). JSON pozwala również na proste serializowanie obiektów JavaScript.

Przykład składni JSON (przykład z Wikipedii na licencji GPL FDL):

{"menu": {
  "id": "file",
  "value": "File",
  "popup": {
    "menuitem": [
      {"value": "New", "onclick": "CreateNewDoc()"},
      {"value": "Open", "onclick": "OpenDoc()"},
      {"value": "Close", "onclick": "CloseDoc()"}
    ]
  }
}}
 

Analogiczny zapis w XML:

<menu id="file" value="File">
  <popup>
    <menuitem value="New" onclick="CreateNewDoc()" />
    <menuitem value="Open" onclick="OpenDoc()" />
    <menuitem value="Close" onclick="CloseDoc()" />
  </popup>
</menu>
 

Parsowanie JSON po stronie JavaScript sprowadza się do pojedynczej instrukcji:

var obiekt = eval(‘(’ + JSON + ‘)’);
 

Następnie do zmiennej obiekt można się odwoływać jak do zwykłego obiektu:

alert(obiekt.menu.id);  //zwróci "file"
alert(obiekt.menu.popup.menuitem[1].onclick); //zwróci "OpenDoc()"
 

Warto zaznaczyć, że JSON nie wymaga obecności znacznika głównego, tak więc zapis można jeszcze bardzie skrócić.

Pomimo iż według standardu JSON można przesyłać tylko dane (proste typy obsługiwane w JavaScript oraz obiekty JS), to jednak nie ma problemu z przesłaniem funkcji (w tym wypadku należy to rozumieć jako metodę obiektu):

{
  nazwa: "Funkcja",
  func: function(arg) { alert(arg); }
}
 

Przykład 1

Następnie funkcje wywołujemy:

var obiekt = eval(‘(’ + JSON + ‘)’);
obiekt.func(‘hello’);
 

Oczywiście możliwe jest traktowanie funkcji jako części obiektu (choć nie wchodzi to w skład standardu JSON!):

{
  nazwa: "Funkcja",
  func: function(arg) { alert(arg); },
  func2: function() { alert(this.nazwa); }
}
 

Wówczas:

obiekt.func2();
 

wyświetli napis “Funkcja”.

Przykład 2

Prezentacja wideo:

Zobacz prezentacje wideo

W przeciągu ostatniego roku można zauważyć zwiększenie zainteresowania formatem JSON. Do najbliższej specyfikacji języka Javascript zgłoszono dwie nowe metody klasy Object (klasy superbazowej) służące do serializacji i deserializacji obiektów. Wiele popularnych bibliotek i frameworków AJAX’owych korzysta z JSON jako podstawowego sposobu komunikacji.

PHP począwszy od wersji 5.2 posiada wsparcie do generowania i parsowania zapisu JSON (http://pl.php.net/json).

Przykład (zaczerpnięty z dokumentacji PHP):

< ?php
$arr = array (‘a’=>1,‘b’=>2,‘c’=>3,‘d’=>4,‘e’=>5);

echo json_encode($arr);
?>
 

wypisze:

{"a":1,"b":2,"c":3,"d":4,"e":5}
 

Natomiast:

< ?php
$json = ‘{"a":1,"b":2,"c":3,"d":4,"e":5}’;

var_dump(json_decode($json, true));
?>
 

zwróci tablicę:

array(5) {
    ["a"] => int(1)
    ["b"] => int(2)
    ["c"] => int(3)
    ["d"] => int(4)
    ["e"] => int(5)
}
 

Niezależnie od tych rozwiązań powstały zewnętrzne biblioteki, często o dużo większych możliwościach. Linki do tych rozwiązań można znaleźć na stronie: www.json.org.

Nie brakuje przy tym bibliotek dedykowanych językowi Java.

Dwie oficjalne można znaleźć na stronach: http://www.json.org/java/index.html oraz http://www.json.org/java/simple.txt (obydwie na otwartych i darmowych licencjach).

JSON.simple

W przypadku JSON.simple należy ściągnąć archiwum http://www.JSON.org/java/json_simple.zip
Wewnątrz znajduje się plik json_simple.jar, który należy dodać do projektu (umieszczając go w podkatalogu WEB-INF/lib/ projektu).

Od tej chwili możemy skorzystać z gotowych klas znajdujących się w pakiecie: org.json.simple.*. W szczególności wykorzystuje się dwie:

JSONArray
JSONObject
 

Zacznijmy od drugie. Można zrobić porównanie, że generuje ono jednopoziomową tablicę asocjacyjną:

import org.json.simple.JSONObject;

JSONObject obj=new JSONObject();
obj.put("name","foo");
obj.put("num",new Integer(100));
obj.put("balance",new Double(1000.21));
obj.put("is_vip",new Boolean(true));
obj.put("nickname",null);
System.out.print(obj);
 

Powyższy kod wygeneruje odpowiednio zakodowany i sformatowany ciąg JSON:

{"nickname":null,"num":100,"balance":1000.21,"is_vip":true,"name":"foo"}
 

JSONArray zachowuje się trochę inaczej. Tworzy, jak sama nazwa wskazuje, tablicę elementów (mogą być różnego typu!):

import org.json.simple.JSONArray;

JSONArray tab = new JSONArray();
tab.add("111");
tab.add(new Integer(222));
tab.add(new Double(333.33));
System.out.print(tab);
 

wypisze:

{["111",222,333.33]}
 

Obiekty te można wzajemnie łączyć, tworząc wielopoziomowe struktury:

JSONObject json = new JSONObject();
json.put("napis", "to jest napis");
json.put("liczba", new Integer(999));

JSONArray tab = new JSONArray();
tab.add("111");
tab.add(new Integer(222));
tab.add(new Double(333.33));

json.put("tablica", tab);
out.print(json);
 

Rezultat:

{"napis":"to jest napis","liczba":999,"tablica":["111",222,333.33]}
 

Przykład 3

Prezentacja wideo:

Zobacz prezentacje wideo

JSON in Java

JSON.simple jest prostą, aczkolwiek w kompletną biblioteką.

Jeżeli jednak potrzebujemy więcej, należy sięgnąć do innych. Pełniejszą odmianą JSON.simple jest „JSON in Java? (http://www.json.org/java/index.html). Instalacja oraz wykorzystanie jest bardzo zbliżone do JSON.simple. Biblioteka oprócz prostego tworzenia danych JSON, umożliwia też łatwiejsze jego odczytywanie, wspiera konwersje z/do XML oraz zawiera kilka mniej ważnych elementów, których pozbawiona jest uproszczona wersja.

JSON-lib

Obydwie wyżej opisane biblioteki są zgodne ze standardem JSON. Wprowadza to pewne ograniczenia, na przykład w kwestii przesyłania funkcji.
Dużo bardziej liberalna i rozbudowana jest biblioteka json-lib (json-lib.sourceforge.net) rozprowadzana na licencji Apache 2.0.

Instalacja nie jest w tym wypadku tak prosta, bowiem json-lib posiada listę zależność zawierającą:
xom (http://www.xom.nu/)
commons-lang (http://jakarta.apache.org/commons/lang/)
commons-beanutils (http://jakarta.apache.org/commons/beanutils/)
ezmorph (http://ezmorph.sourceforge.net/)

Należy zainstalować wymagane zależności, a na końcu pobrać plik jar odnoszący się do json-lib (json-lib-1.0b1-jdk13.jar lub json-lib-1.0b1-jdk15.jar). Wszystkie pliki jar umieszczamy w podkatalogu WEB-INF/lib na serwerze. Po odświeżeniu danych serwera zostanie udostępniona przestrzeń nazw net.sf.json.*

Podstawowe użycie jest analogiczne jak wyżej (przykłady pochodzą w części ze strony http://json-lib.sourceforge.net):

int[] array = new int[]{1,2,3};
JSONArray jsonArray = JSONArray.fromObject( array );
out.print(jsonArray);
 

wypisze:

[1,2,3]
 

Natomiast:

List list = new ArrayList();
list.add( "A" );
list.add( "B" );
JSONArray jsonArray = JSONArray.fromObject( list );
out.print( jsonArray );
 

wypisze:

["A","B"]
 

W kolejnym przykładzie widać utworzenie prostej funkcji:

Map map = new HashMap();
map.put( "name", "json" );
map.put( "bool", Boolean.TRUE );
map.put( "int", new Integer(1) );
map.put( "arr", new String[]{"a","b"} );
map.put( "func", "function(i){ return this.arr[i]; }" );
JSONObject json = JSONObject.fromObject( map );
out.print( json );
 

zwróci:

{"func":function(i){ return this.arr[i]; },"arr":["a","b"],"int":1,"name":"json","bool":true}
 

Wielką przewagą json-lib nad podobnymi bibliotekami jest możliwość serializacji klas języka Java do postaci JSON:

class MyBean{
    private String name = "json";
    private int pojoId = 1;
    private char[] options = new char[]{‘a’,‘f’};
    private String func1 = "function(i){ return this.options[i]; }";
    private JSONFunction func2 = new JSONFunction(new String[]{"i"},"return this.options[i];");

    // getters & setters
    …
}

JSONObject jsonObject = JSONObject.fromObject( new MyBean() );
System.out.println( jsonObject );
 

kod zwróci:

{"name":"json","pojoId":1,"options":["a","f"],
"func1":function(i){ return this.options[i];},
"func2":function(i){ return this.options[i];}}
 

W czasie konwersji obiekty klasy JSONFunction są zamieniane na funkcje języka JavaScript.
Możliwa jest także konwersja w drugą stronę.

Dodatkowo json-lib pozwala na konwersje formatu JSON na XML i odwrotnie.

Bardziej szczegółowy opis JSON można znaleźć w dokumencie: http://www.ietf.org/rfc/rfc4627.txt

Ajax Kurs cz. 1:
http://www.tpython.com/index.php/2007/08/23/kurs-ajax-cz1/

Około pół roku temu realizowałem referat akademicki o technologii Ajax. Dzisiaj przedstawiam pierwszą część tego opracowania.

Stworzenie bazowego projektu:

Zobacz prezentacje

XMLHttpRequest jest podstawowym obiektem języka JavaScript służącym do asynchronicznej komunikacji klienta z serwerem.

Pierwotnie obiekt pojawił się w przeglądarce Internet Explorer, a precyzyjniej w dołączanej do niej bibliotece MSXML. Z czasem został zaimportowany do innych przeglądarek, aż wreszcie został zatwierdzony przez organizację W3 w ramy standardowego elementu JavaScript (http://www.w3.org/TR/XMLHttpRequest/).

Tworzenie obiektu:

Internet Explorer 6.0 i wcześniejsze:

var http_request = new ActiveXObject("Msxml2.XMLHTTP");

pozostałe przeglądarki oraz IE 7.0:

var http_request = new XMLHttpRequest();

Dla zapewnienia działania w każdej przeglądarce można skorzystać z kodu:

var http_request = false;if (window.XMLHttpRequest) { // Mozilla, Safari, …
    http_request = new XMLHttpRequest();
    if (http_request.overrideMimeType) {
        http_request.overrideMimeType(’text/xml’);
    }
} else if (window.ActiveXObject) { // IE
    try {
        http_request = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {
        try {
            http_request = new ActiveXObject("Microsoft.XMLHTTP");
        } catch (e) {}
    }
}

Zapytanie do serwera (typu “get”):

http_request.onreadystatechange = function() { /* */ };
http_request.open(’GET’, url, true);

http_request.send(null);

W pierwszej linii ustawiamy funkcję, która będzie wykonana za każdym razem gdy obiekt http_request zmieni stan (tzw. callback). Stan przechowywany jest w zmiennej http_request.readyState

    Może on przyjmować następujące wartości:

  1. 0 = niezainicjalizowany
  2. 1 = połączenie otwarte (http_request.open)
  3. 2 = żądanie zostało wysłane (http_request.send)
  4. 3 = trwa odbieranie danych
  5. 4 = odbieranie zakończone

Stany te następuje po sobie w kolejności. W praktyce sprawdza się tylko kiedy wystąpił stan 4.

Tak więc funkcję można zaimplementować następująco:

http_request.onreadystatechange = function() {
 if( http_request.readyState == 4) {
  // rób coś ciekawego
 }

};

Pełną implementacją funkcji zajmę się w dalszej części.

Polecenie

http_request.open(’GET’, url, true);

otwiera połączenie z serwerem podanym jako adres “url”. Warto nadmienić, że musi być to połączenie wykorzystujące protokół HTTP, połączenia lokalne (file://) nie działają poprawnie.

Funkcja open może przyjmować pięć parametrów (dwa pierwsze są niezbędne)

open(in DOMString method, in DOMString url, in boolean async, in DOMString user, in DOMString password)
  • method - najczęściej “GET” lub “POST”
  • url - adres docelowy
  • async - true jeżeli połączenie ma być asynchroniczne (domyślnie)
  • user, password - dane autentyfikacyjne (domyślnie null)

Polecenie

http_request.send(null);

wysyła żądanie do serwera.

Jako parametr podaje się najczęściej null gdy żądanie jest typu “GET” lub ciąg parametrów (na przykład “action=remove&id=10&time=1000000″) dla „POST’.

W celu zapewnienia poprawności przesyłanych danych powinny być one sformatowanie przy pomocy funkcji “encodeURIComponent”:

var dane = encodeURIComponent(’action’) + ‘=’ + encodeURIComponent(’test=?&;test’);

Taka postać danych powinna zostać odzwierciedlona w zmianie nagłówka “Content-Type”:

http_request.setRequestHeader(’Content-Type’, ‘application/x-www-form-urlenpred’);

Jest to wymagane w przypadku gdy method jest “POST”.

Ostatecznie, przykład wykorzystania obiektu XMLHttpRequest może wyglądać następująco:

var dane = encodeURIComponent(’action’) + ‘=’ + encodeURIComponent(’test=?&;test’);
http_request.onreadystatechange = function() {
  if( http_request.readyState == 4) {
    alert(http_request.responseText);
  }
};

http_request.open(’POST’, ’serwer’, true);
http_request.setRequestHeader(’Content-Type’, ‘application/x-www-form-urlenpred’);
http_request.send(dane);

Jeżeli teraz na serwerze utworzymy plik tekstowy o nazwie “serwer”, to po wywołaniu żądania pojawi się okienko z zawartością pliku.

Co się jednak stanie gdy plik “serwer” nie istnieje?
Zostanie zwrócony błąd o numerze 404.
W przypadku powodzenia zwrócona zostanie wartość 200.

http_request.onreadystatechange = function() {
  if( http_request.readyState == 4) {
    if( http_request.status == 200 ) {
      alert(http_request.responseText);
  } else if ( http_request.status == 404 ) alert(’Plik nie istnieje’);
    else alert(’inny błąd’);
  }

};

Zobacz prezentacje

Obok właściwości http_request.responseText występuje druga http_request.responseXML, użyteczna wówczas, gdy do komunikacji używany jest język XML.
Przykładowo jeżeli plik “serwer” będzie miał zawartość:

<?xml version="1.0"?>
<root>
    hello world
</root>

Można zawartość <root/> odczytać:

http_request.onreadystatechange = function() {
  if( http_request.readyState == 4) {
    if( http_request.status == 200 ) {
      var xml = http_request.responseXML;
      alert(xml.firstChild.firstChild.data);
  } else alert(’błąd’);
  }
};

Aby zakończyć opis obiektu XMLHttpRequest należy wspomnieć o jeszcze jednej instrukcji:

http_request.abort();

Przerywa ona połączenie na danym obiekcie i przywraca jego wartości początkowe.

Zobacz prezentacje

Pozostałe metody i właściwości klasy nie są często używane. Ich opis znajduje się w (http://www.w3.org/TR/XMLHttpRequest/).

XMLHttpRequest domyślnie używa kodowania znaków UTF-8.

Ciężko nie zauważyć wielkiej popularności języka JavaScript wzrastającej nieustannie od kilku lat. Inspiracją do napisania tego posta był kolejny znakomity toolkit (właściwie to nawet pełna biblioteka) javascriptowa do wizualizacji graficznego interfejsu użytkownika. Mam tutaj na myśli OAT Framework.

Obecna wersja 2.6 wspiera kilkanaście atrakcyjnie wyglądających widgetów (między innymi bardzo efektowne Dock lub zintegrowany widget do obsługi RSS) oraz sporo innych przydatnych narzędzi (funkcje kryptograficzne, bazodanowe).

Ale niewątpliwie największe wrażenie pozostawił przykład aplikacji do modelowania baz danych napisany w OAT Framework:

http://demo.openlinksw.com/DAV/home/demo/Public/Design/employee_sales_customer_diagram2.xml

Wróćmy jednak jeszcze do kwestii popularności JavaScript. Niedawno przeczytałem, iż obecne badanie w Stanach Zjednoczonych sugerują, iż najwięcej programistów tworzy obecnie programy w JS.

Potwierdzenia postanowiłem poszukać w danych serwisu Freshmeat. Wprawdzie nie ograniczyłem się do czasu obecnego, ale sprawdziłem ile projektów wykorzystuje ten język. JavaScript znalazł się na szczytnym 7. miejscu (licząc wszystkie projekty; należy pamiętać, iż JS rzadko występuje jako jedyna technologia w projekcie).

Poniżej przedstawiam obecny ranking:

  1. C (8737)
  2. Java (5657)
  3. C++ (4746)
  4. PHP (4203)
  5. Perl (3758)
  6. Python (2826)
  7. JavaScript (1019)
  8. Unix Shell (986)
  9. SQL (538)
  10. TCL (493)

W najbliższym czasie należy się spodziewać wkroczenia na listę języka Ruby, zapewne kosztem tracącego znaczenie TCL.

Nowości w jTemplates 0.2:

- MultiTemplates

Pozwalają na umieszczeniu wielu szablonów w jednym pliku, przykład:

{#template MAIN}
 <div id="header">{$T.name}</div>
 <table>
 {#foreach $T.table as r}
  {#include row root=$T.r}
 {#/for}
 </table>
{#/template MAIN}

{#template row}
 <tr bgcolor="{#cycle values=[‘#AAAAEE’,'#CCCCFF’]}">
  <td>{$T.name.bold()}</td>
  <td>{$T.age}</td>
  <td>{$T.mail.link(‘mailto:’+$T.mail)}</td>
 </tr>
{#/template row}

- korekta kilku błędów (na przykład obsługa #literal) i zmniejszenie obciążenia pamięciowego

Więcej na stronie: http://jtemplates.tpython.com

Wczoraj (a właściwie dzisiaj, bo przez ostatnie 24 godziny strona nie wytrzymała obciążenie i była sporadycznie dostępna) ukazała się kolejna (1.1.3) wersja biblioteki JavaScript pod nazwą jQuery.

Wśród nowości na szczególną uwagę zwraca deklarowane przyspieszenie działania nawet kilkukrotne (średnio 867%)!

Więcej informacji w blogu autora.

Na stronie http://jtemplates.tpython.com/ publikuję system szablonów stron w JavaScript o nazwie jTemplates.

jTemplates wcześniej był rozwijany pod nazwą tParser. Obecnie stał się pluginem do biblioteki jQuery. jTemplates dostępny jest na licencjach MIT i GPL.

Najnowsza wersja nosi numer 0.1.9 i zawiera szereg udoskonaleń w stosunku do wersji 0.1.

Więcej informacji na stronie projektu.

Ajax jako młoda i dynamicznie rozwijająca się dziedzina programowania webowego nie narodziła wciąż szablonowych zasad debugowania. Do niedawna programiści byli zmuszeni do stosowania kilku programów: debuggera JavaScriptu, loggera wywołań, inspektora DOM. “Do niedawna” - gdyż historia programu o nazwie FireBug nie jest długa.

Firebug nie jest osobnym programem, ale darmowym pluginem do Firefoxa. Słowo “tylko” jest wyjątkowo niefortunne, gdyż pod względem możliwości Firebug przewyższa większość podobnym komercyjnych programów.

Do dyspozycji mamy zintegrowany debugger JavaScript (z obsługą pułapek warunkowych i edycji zmiennych w czasie wykonania!), rozbudowany inspektor DOM, umożliwiający na pełną edycję strony, logger wywołań ajaxowych, profiler i wiele więcej.

Wywołania ajaxowe są bardzo dobrze przestawione: parametry żądania, nagłówki, pełna odpowiedź. Wbudowany interpreter pozwala na manualne wprowadzenia i wykonania kodu JavaScript.

Prawdę klikając muszę stwierdzić iż jestem pod wielkim wrażeniem Dzieła autora. Aby tak dalej. Polecam.