XML i Java 1. XML

Transkrypt

XML i Java 1. XML
Projektowanie systemów informatycznych
XML i Java
1. XML
1.1. Budowa dokumentu XML
XML (ang. Extensible Markup Language) – rozszerzalny język znaczników. Jest to standard
mający bardzo szeroki zakres zastosowań. Dokument XML składa się z następujących części:
• prologu –zawiera wersje dokumentu, komentarze, metadane o treści dokumentu
• ciała dokumentu – zawiera element pierwotny (korzeń) i elementy podrzędne
• epilogu – zawiera on komentarze i instrukcje dotyczące obsługi
Prolog
Prolog znajduje się na samym początku dokumentu. Rekomendacja W3C zaleca umieszczenie
w nim wersji języka XML oraz standardu kodowania znaków. Do ich zadeklarowania służą
instrukcje przetwarzania. Są one otoczone parą znaczników <? ... ?>. Po pierwszym znaku
zapytania występuje słowo kluczowe, które interpretuje aplikacja przetwarzająca dokument. Treść
instrukcji przetwarzania znajduję się pomiędzy tym słowem a znacznikiem ?>.
Przykład.
<?xml version=”1.0” encoding=”windows-1250”?>
Parametr version powyższej instrukcji przetwarzania informuje aplikację przetwarzającą o
wersji języka XML, z którą zgodny jest dany dokument. Parametr encoding jest opcjonalny
i określa standard kodowania znaków. Jego wartością domyślną jest UTF-8.
Komentarze
Komentarze muszą występować na zewnątrz wszystkich znaczników. Można je umieszczać
w dowolnym miejscu dokumentu poniżej jego deklaracji XML. Zawierają zwykle objaśnienia i są
ignorowane przez parser. Komentarze rozpoczynamy od <--! i kończymy -->, na przykład <!-Tu wpisujemy treść komentarza -->.
Elementy
Element składa się ze znacznika początkowego, końcowego oraz treści między nimi zwanej
jego zawartością. Nazwy elementów możemy tworzyć ze znaków postaci 0...9, a...z, A...Z, _, -, : .
Muszą one jednak zaczynać się od litery, podkreślenia lub dwukropka. Elementy mogą zawierać :
• inne elementy (typ elementowy)
• inne elementy i tekst (typ mieszany)
Zawartością elementu może być również wartość pusta. Możemy wtedy zapisać taki element
w krótszej postaci, to znaczy piszemy
<element_pusty/> zamiast <element_pusty><element_pusty/>
Michał Bleja
Uniwersytet Łódzki
Projektowanie systemów informatycznych
Element główny
Prawidłowo sformułowany dokument XML musi posiadać jeden element, który zawiera
wszystkie inne elementy. Jest to tak zwany element główny, jego zawartość łącznie z nim stanowi
ciało dokumentu XML.
Atrybuty
Atrybut to para złożona z nazwy i wartości. Najpierw podajemy jego nazwę (zakres
dopuszczalnych znaków jest taki jak w przypadku elementów), następnie znak równości i ujętą
w cudzysłowie jego wartość. Atrybuty umieszczamy w znacznikach początkowych, na przykład:
<zamówienie id=”1” data_wysłania=”20.01.2005”> ... </zamówienie>.
Element zamówienie ma dwa atrybuty o nazwach id, data_wysłania oraz wartościach
odpowiednia 1, 20.01.2005. Znacznik początkowy może mieć oczywiście zero lub więcej
atrybutów.
Encje
Encja to część dokumentu XML, która może zawierać tekst lub dane binarne. Istnieją dwie
kategorie encji :
•
parsowane (dane tekstowe)
•
nieparsowane ( dane tekstowe nie zawierające kodu XML, dane binarne)
Encja może włączać do dokumentu XML inne encje, poprzez zastosowanie odwołań do
nich. Jeżeli encja odwołuje się do encji parsowanej w celu umieszczenia jej danych w dokumencie,
to muszą one być poprawnie sformatowane. Każdy procesor XML powinien rozpoznawać encje
predefiniowane, które odpowiadają znakom. Do zbioru tego należą:
Znak
<
>
&
‘
„
Sekwencja
&lt
&gt
&amp
&apos
&quot
Po stworzeniu dokumentu XML (encji), należy dokonać deklaracji encji w innym dokumencie,
aby wykorzystać wcześniej zdefiniowane dane. W celu odwołania się do encji należy poprzedzić
znakiem & jej zdefiniowaną wcześniej nazwę. Przykład przedstawia definicje encji o nazwie
encja_1 i odwołanie do niej:
<?xml version = „1.0”?>
<!ENTITY encja_1 SYSTEM "dane/dane.xml">
......
......
&encja_1
......
Michał Bleja
Uniwersytet Łódzki
Projektowanie systemów informatycznych
......
Sekcje CDATA
Użycie takiej sekcji informuje procesor XML, że zawarty w niej tekst ma przekazać bez zmian
aplikacji przetwarzającej dane z dokumentu XML. Są one zatem silnym mechanizmem, gdyż
umożliwiają wstawianie do dokumentów XML danych nie podlegających interpretacji. Sekcje
CDATA rozpoczynamy pisząc <![CDATA a kończymy ]]>.
1.2. Przestrzenie nazw XML
Umożliwiają one uniknięcia konfliktów między poszczególnymi zbiorami znaczników,
powstałych przez połączenie kilku dokumentów XML w jedną całość. Mechanizm ten polega na
poprzedzeniu nazwy elementu, identyfikatorem odpowiedniej przestrzeni nazw z dwukropkiem.
Powstała w ten sposób nazwa jest określana mianem nazwy kwalifikowanej. Specyfikacja
przestrzeni nazw zaleca używanie adresów URI jako identyfikatorów. Adresy URI mogą zawierać
znaki niedopuszczalne w nazwach elementów XML i być dość długie. W związku z tym
identyfikator jest wiązany z prefiksem (nazwą zawierającą tylko znaki dopuszczalne oprócz
dwukropka w elementach XML), nazwy kwalifikowane powstają zaś przez złożenie prefiksu,
dwukropka i lokalnej nazwy elementu.
W celu zdefiniowania przestrzeni nazw używa się atrybutu xmlns:prefiks, gdzie prefiks
zostanie wykorzystany do identyfikacji naszej przestrzeni. Wartością atrybutu xmlns:prefiks
będzie zaś jakiś adres URI.
Przykład dokumentu XML (kursy.xml) z domyślną i jawną przestrzenią nazw:
<?xml version="1.0" encoding="ISO-8859-2"?>
<tabela_kursow xmlns=”http://www.moja_przestrzen_nazw.pl”
xmlns:kursy=”http://www.kursy.pl”>
<data_notowania>2005-03-11</data_notowania>
<kursy:pozycja>
<kursy:nazwa_waluty>euro</kursy:nazwa_waluty>
<kursy:przelicznik>1</kursy:przelicznik>
<kursy:kod_waluty>EUR</kursy:kod_waluty>
<kursy:kurs_kupna>3,9072</kursy:kurs_kupna>
<kursy:kurs_sprzedazy>3,9862</kursy:kurs_sprzedazy>
</kursy:pozycja>
<kursy:pozycja>
<kursy:nazwa_waluty>jen japoński</kursy:nazwa_waluty>
<kursy:przelicznik>100</kursy:przelicznik>
<kursy:kod_waluty>JPY</kursy:kod_waluty>
<kursy:kurs_kupna>2,7996</kursy:kurs_kupna>
<kursy:kurs_sprzedazy>2,8562</kursy:kurs_sprzedazy>
</kursy:pozycja>
......
......
......
</tabela_kursow>
Michał Bleja
Uniwersytet Łódzki
Projektowanie systemów informatycznych
W przykładzie tym elementy, których nazwa rozpoczyna się od prefiksu kursy pochodzą
z przestrzeni nazw o identyfikatorze http://www.kursy.pl. Dodanie prefiksu do każdego elementu
zwiększa rozmiar i obniża czytelność dokumentu. Specyfikacja przestrzeni nazw umożliwia jednak
zastosowanie domyślnej przestrzeni. Elementy do niej należące nie wymagają prefiksu.
W powyższym
dokumencie
identyfikatorem
domyślnej
przestrzeni
nazw
jest
http://www.moja_przestrzen_nazw.pl. Należą do niej elementy o nazwach tabela_kursow
i data_notowania.
1.3. Definicja typu dokumentu
Definicja typu dokumentu (ang. DTD, Document Type Definition) określa reguły składniowe, za
pomocą których są tworzone dokumenty XML. Reguły te określają między innymi:
• nazwę elementu głównego dokumentu
• elementy, które mogą wchodzić w skład innych elementów
• porządek (kolejność elementów)
• krotność występowania elementów
• atrybuty mogące pojawić się w elemencie
• typy danych stanowiące zawartość elementu
Przykład pliku DTD dla powyższego dokumentu XML o nazwie kursy.xml
<!ELEMENT tabela_kursow (data_notowania,pozycja*)>
<ATTLIST tabela_kursow xmlns CDATA>
<ATTLIST tabela_kursow xmlns:kursy CDATA>
<!ELEMENT data_notowania (#PCDATA)>
<!ELEMENT pozycja (nazwa_waluty,przelicznik,kod_waluty,
kurs_kupna, kurs_sprzedazy)>
<!ELEMENT nazwa_waluty (#PCDATA)>
<!ELEMENT przelicznik (#PCDATA)>
<!ELEMENT kod_waluty (#PCDATA)>
<!ELEMENT kurs_kupna(#PCDATA)>
<!ELEMENT kurs_sprzedazy (#PCDATA)>
Pierwszy wiersz definiuje element główny tabela_kursow. Definicja elementu w DTD
rozpoczyna się prefiksem <!ELEMENT. Nawiasy występujące w definicji, zawierają listę
oddzielonych przecinkami elementów podrzędnych danego elementu. Znak gwiazdki po elemencie
pozycja oznacza, że liczba jego wystąpień może być równa zero lub więcej (znak plusa oznacza, co
najmniej jedno wystąpienie). Element data_notowania musi występować jeden raz,
opcjonalność oznaczamy symbolem ?. Następne dwa wiersze definiują atrybuty elementu
głównego i określają ich typ jako CDATA. Czwarty wiersz definiuje element data_notowania.
Jego typ zostaje określony jako PCDATA. Typy CDATA (ang. character data) i PCDATA (ang.
parsed character data) dotyczą danych znakowych lub tekstu. Pozostała część pliku definiuje
element pozycja, który zawiera kolejno elementy: nazwa_waluty, przelicznik, kod_waluty,
kurs_kupna, kurs_sprzedazy. Krotność występowania każdego z nich jest równa jeden i są one
Michał Bleja
Uniwersytet Łódzki
Projektowanie systemów informatycznych
wszystkie typu tekstowego (PCDATA).
1.4. XML Schema
Metajęzyk XML Schema bazuje na składni XML i jest o wiele bogatszy od DTD. Służy do
definiowania struktury dokumentów XML i pozwala na definiowanie typów danych. XML Schema
zaprojektowano pod kątem współpracy z mechanizmem przestrzeni nazw. W schemacie
(dokumencie XML Schema) wszystkie elementy definiujące strukturę dokumentu noszą nazwy o
prefiksie xsd (ang. XML Schema Definition). Prefiks jest odwzorowywany na identyfikator
przestrzeni nazw postaci : http://www.w3.org/2001/XMLSchema. Adres ten wskazuje lokalizację
specyfikacji XML Schema rekomendowaną przez organizację W3C.
Elementem głównym schematu jest xsd:schema. Wewnątrz niego mogą występować inne
elementy, atrybuty i typy danych. Jeżeli dokument XML posiada zdefiniowane przestrzenie nazw,
to należy je określić w schemacie za pomocą atrybutów elementu głównego. Dzięki temu możemy
odróżnić elementy XML wchodzące w skład dokumentu XML, od elementów zawartych
w specyfikacji schematu. Atrybut targetNamespace definiuje przestrzeń nazw dla dokumentów
zgodnych z regułami danego schematu.
Specyfikacja XML Schema w przeciwieństwie do DTD zawiera duży zbiór predefiniowanych
typów podstawowych (np. daty, dodatnie liczby całkowite). Istnieje również mechanizm
definiowania własnych typów, które można wykorzystać do określenia typu wartości danego
elementu lub atrybutu. Nowy typ musi wywodzić się z bazowego (predefiniowanego lub innego
wcześniej utworzonego typu prostego), który jest ograniczony przez pewne kryteria. Nie możemy
oczywiście zastosować do wszystkich typów każdego kryterium. Pojęcie liczby cyfr dziesiętnych
po przecinku nie ma sensu na przykład dla dat, napisów. Kryteria charakteryzują typy danych
i posiadają następujące cechy:
• minLength, maxLength, length – minimalna, maksymalna i dokładna liczba znaków
w zapisie wartości
• enumeration – lista wszystkich możliwych wartości
• pattern – wzorzec wyrażenia regularnego dla wartości
• minExclusive, minInclusive, maxInclusive, maxExclusive – dopuszczalny zakres wartości
liczbowych
• totalDigits – ilość cyfr dziesiętnych w zapisie wartości liczbowych
• fractionDigits – ilość cyfr dziesiętnych po przecinku
• whiteSpace – sposób interpretacji białych znaków w zapisie wartości
Przykłady definicji typów prostych:
<xsd:simpleType name=”typ_kod_pocztowy”>
<xsd:restriction base=”xsd:string”>
<xsd:pattern value=”\d{2} – \d{3}”/>
</ xsd:restriction>
<xsd:simpleType>
Fragment powyższego schematu definiuje typ prosty dla elementu kod_pocztowy. Nazwą
typu jest typ_kod_pocztowy. Bazuje on na typie napisowym (string) i jest ograniczony
przez wzorzec dwóch cyfr, myślnika i trzech cyfr.
Michał Bleja
Uniwersytet Łódzki
Projektowanie systemów informatycznych
<xsd:simpleType name=”typ_plec”>
<xsd:restriction base=”xsd:string”>
<xsd:enumeration value=”K” />
<xsd:enumeration value=”M” />
</ xsd:restriction>
<xsd:simpleType>
Powyższy typ prosty o nazwie typ_plec bazuje również na typie napisowym. Lista jego
wszystkich możliwych wartości składa się z dwóch elementów (K lub M).
Typy złożone w standardzie XML Schema definiują w przeciwieństwie do prostych złożone
modele zawartości (np. dla elementów, które zawierają elementy potomne, atrybuty). Typy złożone
obejmują liczność i sekwencjonowanie elementów potomnych, nazwy atrybutów oraz to, czy ich
występowanie jest wymagane. Składnia definiowania typów podstawowych jest postaci:
<xsd:complexType name=”nazwa_typu>
<xsd:model_zawartości>
<!--ograniczenia na liczność i sekwencjonowanie
elementów potomnych określane za pomocą xsd:element-->
</xsd:model_zawartości>
<!--deklaracje atrybutów określane za pomocą
xsd:attribute-->
</xsd:complexType>
Element xsd:complexType zawiera definicję typu złożonego. Najczęściej
wykorzystywanymi modelami zawartości są elementy :
•
•
•
xsd:sequence – sekwencja elementów
xsd:choice – wybór jednego spośród kilku elementów
xsd:all – pozwala dokonać wyboru pewnego zbioru elementów i umieścić je w dowolnej
kolejności
• xsd:group – odwołuje się do modelu zawartości umieszczonego w innym miejscu
Wewnątrz modelu zawartości elementy potomne są definiowane za pomocą
xsd:element. Po wypełnieniu jego specyfikacji występują definicje atrybutów, określone za
pomocą xsd:attribute.
Wiązanie dokumentu XML ze schematem jest dokonywane za pomocą atrybutu
xsi:schemaLocation jego elementu głównego. Atrybut ten zawiera parę wartości. Pierwszą
z nich jest identyfikator przestrzeni nazw związanej z dokumentem XML, na którego lokalizacje
wskazuje druga wartość atrybutu. W przypadku występowania w dokumencie XML kilku
przestrzeni nazw, należy atrybutowi xsi:schemaLocation przypisać wiele par wartości.
Używanie prefiksu xsi (ang. XML Schema Instance) w nazwie atrybutu jest ogólnie przyjętą
konwencją.
Michał Bleja
Uniwersytet Łódzki
Projektowanie systemów informatycznych
Przykład dokumentu XML (waluty.xml) i jego schematu (waluty.xsd).
waluty.xml.
<?xml version="1.0" encoding="ISO-8859-2"?>
<waluty xmlns=http://www.waluty.pl
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.waluty.pl
C:\praca_magisterska\waluty\waluty.xsd"
data_notowania="23.03.2005">
<pozycja>
<kraj>Australia</kraj>
<przelicznik>1</przelicznik>
<kod_waluty>AUD</kod_waluty>
<sym_waluty>781</sym_waluty>
<kurs_sredni>2.4439</kurs_sredni>
<zmiana>+0.5</zmiana>
</pozycja>
<pozycja>
<kraj>Cypr</kraj>
<przelicznik>1</przelicznik>
<kod_waluty>CYP</kod_waluty>
<sym_waluty>615</sym_waluty>
<kurs_sredni>7.0060</kurs_sredni>
<zmiana>+0.08</zmiana>
</pozycja>
......
......
......
</waluty>
waluty.xsd
<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.waluty.pl"
xmlns="http://www.waluty.pl">
<xsd:element name="waluty" type="typ_waluty"/>
<xsd:complexType name="typ_waluty">
<xsd:sequence>
<xsd:element name="pozycja" type="typ_pozycja"/>
</xsd:sequence>
<xsd:attribute name="data_notowania" type="xsd:date"
use="required"/>
</xsd:complexType>
<xsd:simpleType name="typ_symb_waluty">
<xsd:restriction base="xsd:string">
<xsd:pattern value"\d{3}"/>
Michał Bleja
Uniwersytet Łódzki
Projektowanie systemów informatycznych
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="typ_pozycja">
<xsd:sequence>
<xsd:element name="kraj" type="xsd:string"/>
<xsd:element name="przelicznik"
type="xsd:positiveInteger"/>
<xsd:element name="kod_waluty" type="xsd:string"/>
<xsd:element name="symb_waluty"
type="typ_symb_waluty"/>
<xsd:element name="kurs_sredni" type="xsd:decimal"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
2. JAXP (Java API for XML Processing)
2.1. Wprowadzenie
JAXP jest API (Application Programming Interface) Javy do przetwarzania danych XML.
Umożliwia wybór sposobu przetwarzanych dokumentów XML, gdyż zawiera standardowe parsery
SAX i DOM. Kontrolę nad sposobem prezentacji danych, JAXP pozwala sprawować za pomocą
XSLT. Obsługa dokumentów definiujących strukturę danych XML (DTD, XML Schema) jest
również wspierana przez standard JAXP. SAX, DOM i XSLT zostały zdefiniowane przez
organizacje XML-DEV i W3C. Głównymi pakietami są :
• javax.xml.parsers – definiuje klasy pozwalające przetwarzać dokumenty XML
• org.xml.sax – dostarcza klas i interfejsów dla SAX
• org.w3c.dom – dostarcza interfejsów dla DOM
• javax.xml.transform – definiuje klasy, interfejsy do przetwarzania instrukcji
transformacji i wykonywania transformacji ze źródła do celu
Komunikacja między aplikacjami klienckimi odbywa się zwykle za pomocą dokumentów
XML. JAXP umożliwia przetwarzanie właśnie takich dokumentów.
2.2. SAX (Simple API for XML)
Analizator składniowy SAX jest oparty na modelu zdarzeń. Parser SAX przebiega kolejno
elementy dokumentu XML od początku do końca. W momencie napotkania danego elementu
generuje odpowiednie powiadomienie, które przechwytuje program obsługi (ang. handler).
Rodzajem najprostszej akcji podejmowanej przez program obsługi, jest na przykład wypisanie
tekstu między znacznikiem początkowym a końcowym danego elementu. Oczywiście po
napotkaniu pewnych elementów przez parser i zgłoszeniu ich wystąpienia nie musi zostać podjęta
żadna akcja.
Michał Bleja
Uniwersytet Łódzki
Projektowanie systemów informatycznych
Rysunek 2. Model SAX
Kiedy SAX rozpoczyna parsowanie (wywołuje metodę parse) urządzenie czytające (ang.
reader) wywołuje jedną lub kilka metod zdefiniowanych w interfejsach ContentHandler,
ErrorHandler, DTDHandler, EntityResolver.
Obiekt
SAXParserFactory
otrzymujemy
wywołując
statyczną
metodę
newInstance() tejże klasy. Możemy go skonfigurować za pomocą następujących metod :
• setFeature – ustawia poszczególne cechy przez podanie ich nazwy i wartości
• setNamespaceAware – wyszczególnia, że parser dostarczy wsparcia dla mechanizmu
przestrzeni nazw
• setValidating – wyszczególnia, że parsowane dokumenty zostaną poddane walidacji
Argumentem wszystkich powyższych metod z wyjątkiem setFeature jest tylko typ logiczny.
Obiekt SAXParser otrzymujemy przez wywołanie metody newSAXParser() na rzecz
SAXParserFactory. Instancja klasy SAXParser definiuje kilka różnych metod parse.
Przetwarzane dane XML mogą pochodzić z wielu źródeł wejściowych. Przykładami takich
obiektów są InputStream, File, URL. Zawartość XML jest parsowana za pomocą metod
zdefiniowanych w HandlerBase lub DefaultHandler.
Obiekt ContentHandler jest głównym interfejsem, którego implementuje większość
aplikacji korzystających z SAX, gdyż dostarcza informacji o podstawowych zdarzeniach. Metody
takie jak startDocument, endDocument, startElement, endElement są
wywoływane kiedy rozpoznawany jest znacznik XML (odpowiednio rozpoczynający, kończący
dokument, rozpoczynający, kończący element). Interfejs definiuje również metody characters
i processingInstruction, które są wywoływane gdy parser napotka odpowiednio element
XML zawierający tekst, włączone do dokumentu instrukcje przetwarzania.
Interfejs ErrorHandler jest przeznaczony do obsługi błędów parsera. Jego metody error,
fatalError, warning są wywoływane w odpowiedzi na różne błędy parsowania. Domyślny
obiekt obsługujący błędy zwraca wyjątki tylko dla błędów krytycznych, a wszystkie inne ignoruje.
Jeżeli zachodzi konieczność obsługi wszystkich błędów, to należy dostarczyć parserowi
Michał Bleja
Uniwersytet Łódzki
Projektowanie systemów informatycznych
implementacje interfejsu ErrorHandler.
Interfejs DTDHandler jest implementowany gdy aplikacja SAX potrzebuje informacji o
notacjach i nieparsowanych encjach. Wystąpienie deklaracji tych elementów zgłaszają metody
instancji DTDHandler – notationDecl, unparsedEntityDecl.
EntityResolver to prosty interfejs do analizowania encji. Posiada tylko jedną metodę
resolveEntity, która jest wywoływana gdy parser musi zidentyfikować dane, identyfikowane
za pomocą URI. W większości przypadków URI jest prostym adresem URL, który określa
położenie dokumentu.
Solidne aplikacje implementują metody interfejsu ContentHandler i ErrorHandler.
Interfejsy ContentHandler, ErrorHandler, DTDHandler, EntityResolver
implementuje klasa DefaultHandler z pakietu org.xml.sax.helpers.
Przykład. Program dokonuje analizy dokumentu XML (komunikatu SOAP), który zawiera treść
zamówienia.
Szkielet programu order_sax.java:
1. Import pakietów Javy
• java.io.*, java.util.* - podstawowe pakiety
• java.awt.*, javax.swing.*, javax.swing.table* - pakiety pozwalające
stworzyć graficzny interfejs użytkownika
• javax.xml.parsers.*, org.xml.sax.helpers.*, org.xml.sax.* pakiety umożliwiające parsowanie dokumentu za pomocą parsera SAX
2. Główne fragmenty programu
klasa reprezentująca pojedynczy element zamówienia, posiada metody get, set dla odpowiednich
pól
class element
{
int id;
String nazwa;
int ilosc;
......
......
}
klasa reprezentująca zamówienie, którego elementy przechowuje obiekt typu ArrayList
class elements
{
ArrayList elements_list = new ArrayList();
konstruktor
public elements()
{
}
f-cja dodaje element
public void add_element(element e)
{
elements_list.add(e);
}
f-cja zwraca element o odpowiednim indeksie
Michał Bleja
Uniwersytet Łódzki
Projektowanie systemów informatycznych
public element get_element(int index)
{
if(index>=elements_list.size())
return null;
return (element)elements_list.get(index);
}
f-cja zwraca ostatni element
public element get_last_element()
{
return get_element(elements_list.size()-1);
}
f-cja zwraca liczbę elementów zamówienia
public int get_size()
{
return elements_list.size();
}
}
klasa rozszerzająca DefaultHandler
class elements_sax_d_h extends DefaultHandler
{
elements elementy;
metody startDocument(), endDocument() zostaną wywołane odpowiednio
w momencie rozpoczęcia i zakończenia procesu parsowania
public void startDocument() throws SAXException
{
System.out.println("START.....");
}
public void endDocument() throws SAXException
{
System.out.println("STOP");
}
metody startElement, endElement zostaną wywołane w momencie napotkania
przez parser znacznika początkowego, końcowego elementu (odpowiednio),
namespaceURI – URI przestrzeni nazw, sName – nazwa prosta elementu,
qName – nazwa kwalifikowna elementu, attrs – obiekt zawierający atrybuty
danego elementu
public void startElement(String namespaceURI,
String sName, String qName, Attributes attrs) throws
SAXException
{
......
......
}
public void startElement(String namespaceURI,
String sName, String qName, Attributes attrs) throws
SAXException
{
Michał Bleja
Uniwersytet Łódzki
Projektowanie systemów informatycznych
......
......
}
metoda characters jest wywoływana w momencie napotkania zawartości
tekstowej elementu, buf[] – tablica zawierająca treść dokumentu XML,
offset – numer pozycji początkowej (wyrazu stanowiącego zawartość elementu)
w tablicy buf, len – długość wyrazu
public void characters(char buf[], int offset, int len) throws
SAXException
{
......
}
klasa tworzy tabelę zawierającą elementy zamówienia, dokonuje również procesu
parsowania
class table_elements extends AbstractTableModel
{
……
elements_handler jest klasą dziedziczącą z DefaultHandler
elements_handler = new elements_sax_d_h();
SAXParserFactory factory = SAXParserFactory.newInstance();
ustawienie walidacji
factory.setValidating(true);
try
{
SAXParser saxParser = factory.newSAXParser();
argumentami metody parse są nazwa pliku (plik) i obiekt rozszerzający
DefaultHandler (elements_handler)
saxParser.parse(plik,elements_handler);
}
……
}
2.3. DOM (Document Object Model)
Obiektowy model dokumentu DOM tworzy reprezentację dokumentu XML w postaci drzewa.
DOM dostarcza interfejsy umożliwiające dostęp do danych i manipulowanie nimi. Zawiera nawet
funkcje raportujące i przeszukujące.
Michał Bleja
Uniwersytet Łódzki
Projektowanie systemów informatycznych
Rysunek 3. Model DOM
Obiekt DocumentBuilderFactory uzyskujemy przez wywołanie statycznej metody
newInstance(). Instancja tej klasy podobnie jak SAXParserFactory zawiera metody
służące
do
konfiguracji.
Obiekt
DocumentBuilderFactory
oprócz
funkcji
setNamespaceAware, setValidating posiada dodatkowo metody:
• setAttribute – pozwala ustawić konkretne atrybuty przez podanie ich nazwy i wartości
• setCoalescing – specyfikuje, że parser dokona przekształcenia węzłów CDATA na
węzły tekstowe
• setExpandEntityReference – specyfikuje, że parser weźmie pod uwagę odwołania
do encji
• setIgnoringComments – komentarze w trakcie parsowania zostaną zignorowane
• setIgnoringElementContentWhitespace – parser usunie białe znaki występujące
w zawartości elementu
Argumentem wszystkich powyższych metod z wyjątkiem setAttribute jest tylko typ
logiczny.
Obiekt
DocumentBuilder
otrzymujemy
przez
wywołanie
metody
newDocumentBuilder()
na
rzecz
DocumentBuilderFactory.
Klasa
DocumentBuilder pozwala uzyskać z danych XML instancje obiektu Document,
reprezentującą dokument XML w postaci drzewa. Podobnie jak klasa SAXParser tak
i DocumentBuilder zawiera kilka metod parse.
Interfejs Document przedstawia całkowity dokument XML. Zawiera szereg metod
umożliwiających dostęp do danych XML, umieszczonych w hierarchicznej strukturze drzewa.
Można tworzyć również puste obiekty Document i wypełniać ich zawartość. Interfejs Document
posiada metody pozwalające konstruować nowe elementy, atrybuty, tekstowe węzły, encje,
instrukcje przetwarzania, komentarze.
Michał Bleja
Uniwersytet Łódzki
Projektowanie systemów informatycznych
Przykład. Program pozwala wyświetlić zawartość dowolnego pliku w formacie XML w postaci
drzewa.
Szkielet programu dom_tree.java:
1. Import pakietów Javy
• java.io.*, java.util.* - podstawowe pakiety
• java.awt.*,java.awt.event.*,
javax.swing.*,
javax.swing.event.*, javax.swing.tree.* - pakiety pozwalające stworzyć
graficzny interfejs użytkownika
• javax.xml.parsers.*,
org.xml.sax.*,
org.w3c.dom.* - pakiety
umożliwiające parsowanie dokumentu za pomocą parsera DOM
2. Główne fragmenty programu
......
......
utworzenie instancji DocumentBuilderFactory
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
białe znaki (spacje, tabulatory) zostaną zignorowane przez parser
factory.setIgnoringElementContentWhitespace(true);
utworzenie obiektu DocumentBuilder
builder = factory.newDocumentBuilder();
w przypadku wystąpienia błędów zostaną one obsłużone przez metody klasy dom_error
(implementuje ona interfejs ErrorHandler)
builder.setErrorHandler(new dom_error());
metoda parse zwraca reprezentację dokumentu XML w postaci drzewa, które jest reprezentowane
przez obiekt Document
Document doc=builder.parse(f);
……
klasa dom_tree_model implementuje interfejs TreeModel, którego metody po odpowiednim ich
nadpisaniu pozwolą utworzyć drzewo
class dom_tree_model implements TreeModel
{
Document document;
konstruktor
public dom_tree_model(Document doc)
{
document=doc;
}
metoda zwraca korzeń drzewa
public Object getRoot()
{
return document.getDocumentElement();
}
metoda zwraca liczbę dzieci danego rodzica
public int getChildCount(Object parent)
{
Michał Bleja
Uniwersytet Łódzki
Projektowanie systemów informatycznych
Node node_parent=(Node)parent;
NodeList list=node_parent.getChildNodes();
return list.getLength();
}
metoda zwraca wezeł podrzędny (dziecko) o danym numerze
public Object getChild(Object parent,int i)
{
Node node_parent=(Node)parent;
NodeList list=node_parent.getChildNodes();
return list.item(i);
}
metoda zwraca numer węzła podrzędnego danego węzła
public int getIndexOfChild(Object parent,Object child)
{
Node node_parent=(Node)parent;
NodeList list=node_parent.getChildNodes();
for(int i=0;i<list.getLength();i++)
if(getChild(node_parent,i)==child)
return i;
return -1;
}
metoda zwraca true gdy badany węzeł jest liściem
public boolean isLeaf(Object node)
{
return getChildCount(node)==0;
}
……
}
klasa odpowiedzialna za obsługę błędów, błędów fatalnych i ostrzeżeń
class dom_error implements ErrorHandler
{
public void error(SAXParseException exception)
{
System.out.println("\n** Parsing error"
+ ", line " + exception.getLineNumber()
+ ", uri " + exception.getSystemId());
System.out.println("
" + exception.getMessage());
}
public void fatalError(SAXParseException exception)
{
System.out.println("\n** Parsing error"
+ ", line " + exception.getLineNumber()
+ ", uri " + exception.getSystemId());
System.out.println("
" + exception.getMessage());
}
public void warning(SAXParseException exception)
Michał Bleja
Uniwersytet Łódzki
Projektowanie systemów informatycznych
{
System.out.println("\n** Parsing error"
+ ", line " + exception.getLineNumber()
+ ", uri " + exception.getSystemId());
System.out.println("
" + exception.getMessage());
}
}
......
2.4. XSLT (XML Style Sheet Language for Transformations)
XSLT to język arkuszy stylów do transformacji XML. Służy do przekształcania dokumentów
XML do dowolnej innej postaci. Najczęściej XSLT jest stosowany do transformacji XML-a na
HTML-a. Oczywiście można otrzymać dokumenty w innym formacie (np. xml, pdf) z danych XML
za pomocą XSLT. Obsługa w JAXP standardu XSLT odbywa się za pomocą pakietu
javax.xml.transform. Kod Javy umożliwiający zastosowanie szablonu stylów do dokumentu
XML (w celu transformacji) nie jest zbyt skomplikowany. Dużo więcej pracy zajmuje stworzenie
samego szablonu.
Rysunek 4. Model XSLT
Obiekt TransformerFactory otrzymujemy przez wywołanie metody newInstance()
na rzecz instancji tej klasy. Zawiera on następujące metody konfiguracyjne:
• setAttribute – pozwala ustawić konkretne atrybuty przez podanie ich nazwy i wartości
• setErrorListener – umożliwia raportowanie błędów i ostrzeżeń, jej argumentem jest
ErrorListener, który nasłuchuje i przechwytuje błędy
• setURIResolver – ustawia obiekt URIResolver, który jest domyślnie używany
podczas transformacji do analizowania adresów URI występujących w xsl:include lub
Michał Bleja
Uniwersytet Łódzki
Projektowanie systemów informatycznych
xsl:import.
Instancje klasy Transformer można uzyskać za pomocą metody newTransformer()
obiektu TransformerFactory. Transformacji dokonuje metoda transform klasy
Transformer. Jej argumentami są oczywiście Source i Result. Klasami implementującymi
interfejs Source są DOMSource, SAXSource, StreamSource. Interfejs Result
implementują zaś klasy DOMResult, SAXResult, StreamResult.
Obiekt Transformer możemy utworzyć z kilkoma instrukcjami transformacji. W tym
przypadku wyszczególnione transformacje zostaną oczywiście wykonane. Jeśli Transformer nie
posiada instrukcji, to zwyczajnie kopiuje źródło do wyniku.
Przykład. Program dokonuje przekształcenia zamówienia (komunikatu SOAP) do postaci pliku
html.
Szkielet programu order_xslt:
1. Import pakietów Javy
• java.io.* - podstawowy pakiet
• javax.xml.parsers.*,org.xml.sax.*,org.w3c.dom.*,
javax.xml.transform.*, javax.xml.transform.stream.*,
javax.xml.transform.dom.* - pakiety umożliwiające przetwarzanie dokumentu
XML na postać HTML
2. Główne fragmenty programu
public class order_xslt
{
static Document document;
f-cja main
public static void main (String argv [])
{
if (argv.length != 2)
{
System.err.println ("Files not found");
System.exit (1);
}
utworzenie obiektu DocumentBuilderFactory i skonfigurowanie go tak,
aby wspierał mechanizm przestrzeni nazw
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance()
;
factory.setNamespaceAware(true);
try
{
utworzenie obiektu reprezentującego arkusz stylów
File stylesheet = new File(argv[0]);
obiekt datafile reprezentuje plik xml
File datafile
= new File(argv[1]);
DocumentBuilder builder = factory.newDocumentBuilder();
Michał Bleja
Uniwersytet Łódzki
Projektowanie systemów informatycznych
obiekt document zawiera drzewo reprezentujące dane XML
document = builder.parse(datafile);
utworzenie egzemplarza TransformerFactory
TransformerFactory tFactory = TransformerFactory.newInstance();
obiekt stylesource implementuje interfejs Source
StreamSource stylesource = new StreamSource(stylesheet);
utworzenie obiektu Transformer z instrukcjami
transformacji zawartymi w obiekcie stylesource
Transformer transformer = tFactory.newTransformer(stylesource);
DOMSource source = new DOMSource(document);
obiekt result implementuje interfejs Result i reprezentuje
wynik transformacji obiektu typu DOMSource
StreamResult result = new StreamResult(new
File("order_result.html"));
metoda transform przekształca obiekt source na obiekt result,
zgodnie z instrukcjami transformacji zawartymi w obiekcie stylesource
transformer.transform(source, result);
}
Michał Bleja
Uniwersytet Łódzki