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 < > & &apos " 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