XML – ćwiczenia 14: JAXB.

Wszystkie przykładowe programy:

Referencje

JAXB, a także StAX, powstały (JAXB wcześniej, StAX później) w związku z „webserwisami”. Początkowo były częścią Java Web Services Developer Pack i Java Enterprise Edition, a od wersji 6 wchodzą w skład Java Standard Edition. Ponadto StAX został dodany do wersji 1.4 standardu JAXP.

Wiązanie XML (w Javie)

Wiązanie XML w języku programowania (u nas w Javie) to pomysł, aby schematom dokumentów XML (DTD, XML Schema itp.) odpowiadały hierarchie klas, a instancjom dokumentów konkretne obiekty (z obiektami – podelementami itd., tworząc strukturę drzewiastą).

Dokument zgodny ze schematem można wczytać do pamięci (unmarshalling), a drzewo obiektów zapisać do dokumentu (marshalling).

Interfejs dostępu do drzewa jest zależny od schematu, ale dzięki temu jest wygodniejszy. Np. elementowi osoba, który może zawierać jeden podelement nazwisko i wiele podelementów imię (oba typu xs:string) będzie odpowiadała klasa z metodami List<String> getImię() i String getNazwisko(). Ponadto wartości od razu są tego typu Javy, który odpowiada zadeklarowanemu typowi XML Schema.

Nie ma potrzeby pamiętania nazw elementów i atrybutów (po prostu widać jakiego są typu), w wielu przypadkach można też uniknąć tworzenia list i słowników, dzięki temu wiązanie XML jest mniej pamięciochłonne i szybsze niż DOM.

JAXB

Standard Java API for XML Binding jest realizacją idei „wiązania XML” w Javie, został opracowany przez Suna, obecnie jest projektem open-source.

Niedawno JAXB został włączony do platformy Java Standard Edition (do wersji 6).

Od wersji JAXB 2.0 istnieje także możliwość generowania schematu na podstawie klas Javy (aby mieć większą kontrolę nad tym procesem, należy używać specjalnych anotacji w Javie).

Typowe kroki implementacji aplikacji używającej JAXB

  1. Przygotowanie schematu dokumentów.
  2. Kompilacja schematu narzędziem XJC, generuje klasy Javy odpowiadające typom zdefiniowanym w schemacie.

  3. Napisanie samej aplikacji korzystając z:

    • uniwersalnej części API JAXB,
    • klas wygenerowanych przez XJC.
  4. Uwaga! Zmiana schematu po napisaniu aplikacji może spowodować konieczność znacznych zmian w kodzie.

Przykład 1.

Pliki: LiczbyJAXB.java, klasy wygenerowane przez XJC.

Przykład o sumowaniu liczb w JAXB.

Zadanie 1.

Skompiluj narzędziem xjc schemat z zadania 3.

Przykłady w tutorialach Suna

Ciekawsze przykłady można znaleźć w tutorialach:

Wygodne uruchomienie przykładów poprzez Anta wymaga skonfigurowania Java Enterprise Edition. Same programy powinny działać w czystym Java SE 6.

Walidacja

Klasy i interfejsy związane z walidacją są umieszczone w pakiecie javax.xml.validation. Aby walidacja zgodnie z tym „nowym” interfejsem działała zwykle trzeba włączyć obsługę przestrzenia nazw w parserze.

Obiekty typu Schema to schematy, które definiują strukturę dokumentów XML. Do tworzenia obiektów typu Schema służą obiekty klasy SchemaFactory. Obiekty typu Schema mogą być utworzone na podstawie schematów XML Schema, ale także schematów Relax NG czy Schematron, o ile dana implementacja komponentu służącego do walidacji je obsługuje.

Obiekty typu Schema mogą być wykorzystane do sprawdzania poprawności dokumentów podczas parsowania: fabryce parserów (zarówno SAX jak i DOM) metodą setSchema można wskazać schemat, względem którego ma być walidowany dokument.

Aktywna walidacja – Validator

Z obiektu typu Schema metodą newValidator można uzyskać obiekt typu Validator, za pomocą którego można zwalidować dokument, nawet jeśli dokument nie jest dostępny jako plik, a na przykład drzewo DOM czy strumień zdarzeń SAX. Do obsługi błędów walidacji należy użyć obiektu typu ErrorHandler, jak dla parsera SAX.

Walidacja może mieć wpływ na zawartość dokumentu, poprzez wstawienie domyślnych wartości atrybutów i normalizację białych znaków. Dlatego do walidacji możemy użyć najbardziej ogólnej metody Validator.validate(Source, Result), która waliduje dokument podany w pierwszym argumencie a (potencjalnie zmieniony) wynik zwraca poprzez drugi argument.

Jak widać dozwolone są te same rodzaje źródeł i wyników, co dla transformerów, jednak tutaj wynik musi być tego samego rodzaju co źródło.

Przykład 2.

Przykłady walidacji drzewa DOM w pamięci.

Bierny walidator dla SAX – ValidatorHandler

W przypadku walidacji strumienia zdarzeń SAX czasami wygodniej jest użyć „biernego” obiektu typu ValidatorHandler (podobnie jak TransformerHandler).

Metoda setContentHandler pozwala do obiektu typu ValidatorHandler dołączyć ContentHandler, który będzie odbierał zdarzenia reprezentujące zwalidowany dokument.

Zadanie 2.

  1. Do programu z poprzednich zajęć (z filtrem blokującym nieważne grupy liczb) dodaj walidację wynikowego dokumentu względem schematu przed zapisaniem do pliku. Wybierz zestaw obiektów właściwych typów, aby tylko jeden z nich uruchamiał parsowanie, ale dało się je połączyć w „łańcuszek”.
  2. Jeśli Twój filtr dodaje podelementy suma, po przetestowaniu z oryginalnym schematem dodaj deklarację tego podelementu w schemacie i ponownie przetestuj. Spraw aby informacja o nie walidowaniu się była wypisywana lub miała wpływ na działanie. (Jeśli filtr tylko przesiewa grupy, inaczej spraw aby wynikowy dokument czasami nie przechodził walidacji).
  3. Do schematu dodaj deklarację atrybutu z wartością domyślną, sprawdź czy walidacja powoduje dopisanie domyślnych wartości atrybutów.

Ewaluacja XPath

JAXP 1.4 obejmuje wsparcie dla XPath 1.0. Klasy i interfejsy stanowiące wsparcie dla XPath zostały umieszczone w pakiecie javax.xml.xpath. Do obliczania wyrażeń służą obiekty implementujące interfejs XPath, można je uzyskać z obiektu klasy XPathFactory.

Wartość wyrażenia XPath może być obliczona dla dokumentu dostępnego jako plik (lub ogólnie ciąg znaków) lub jako drzewo DOM. W pierwszym przypadku w celu obliczenia jednego wyrażenia parsowany jest cały dokument, co zwykle nie jest efektywnym rozwiązaniem, drugi przypadek jest możliwy do osiągnięcia tylko dla dokumentów mieszczących się w pamięci. Wyrażenie może być także obliczone w kontekście konkretnego węzła – należy go podać jako węzeł DOM.

Wynik wyrażenia można odebrać jako obiekt Javy typu najbardziej odpowiedniego dla wskazanego typu XPath (metoda typu Object). Węzły zwracane są jako węzły DOM. Typy atomowe w XPath 1.0 to jedynie liczby, napisy i boolean – zwracane są odpowiednie obiekty Javy.

Wynik można też odebrać zrzutowany od razu na String (metoda typu String).

Przykład 3.

Plik: XPathExample.java.

Zadanie 3.

  1. Napisz program sumujący liczby z ważnych grup, który robi to poprzez wybranie ścieżką XPath wszystkich elementów l z ważnych grup (lub od razu ich węzłów tekstowych) i następnie zsumowanie wartości liczbowych.
  2. Spróbuj (nie było to testowane) napisać od razu ścieżkę, która liczy sumę (funkcja sum())

Valid XHTML 1.1Valid CSS