XML i Java Technologie zarządzania treścią dr inż. Robert Perliński rperlinski@icis.pcz.pl Politechnika Częstochowska Instytut Informatyki Teoretycznej i Stosowanej
XML i Java 2/57 SAX vs. DOM Dwa podstawowe typy API do przetwarzania dokumentów XML: Oparte na drzewach (ang. Tree-based API ) - mapują strukturę dokumentu do drzewa i pozwalają użytkownikowi nawigować po tym drzewie. Oparte na zdarzeniach (ang. Event based API ) - zgłaszają zdarzenia występujące podczas parsowania (np. początek/koniec elementu). Zdarzenia są zgłaszane do aplikacji za pomocą callback u. Aplikacja implementuje metody (handlery) przechwytujace te zdarzenia w sposób podobny do obsługi zdarzeń generowanych przez GUI.
XML i Java 3/57 SAX vs. DOM DOM - czesto użyteczne, ale wykorzystują dużo zasobów, szczególnie w przypadku dużych dokumentów. Jesli aplikacje wykorzystują swoje własne struktury danych niekorzystne jest budowanie drzewa tylko po to, żeby na jego podstawie zbudować obiekty wewnętrznych struktur danych. SAX pozwala na parsowanie dokumentów dużo większych niż dostępne zasoby pamięciowe. Własne struktury danych mogą być tworzone za pomocą metod wykorzystywanych do obsługi zdarzeń.
XML i Java 4/57 Kiedy używać SAX - przykład ZADANIE: W dokumencie XML wielkosci 20MB znaleźć element zawierający słowo Częstochowa. Wykorzystanie DOM - tworzenie drzewa dla tak dużego dokumentu tylko po to, żeby znaleźć jeden element w zbiorze danych byłoby bardzo niekorzystne. Wykorzystanie SAX - możliwe znalezienie elementu (w metodach obsługi zdarzeń) wykorzystując minimalną ilość pamięci.
XML i Java 5/57 SAX - jak to działa. <?xml version="1.0"?> <doc> <para>hello, world!</para> </doc> Podczas przetwarzania dokumentu zgłoszone zostaną zdarzenia: 1 start document 2 start element: doc 3 start element: para 4 characters: Hello, world! 5 end element: para 6 end element: doc 7 end document
XML i Java 6/57 SAX SAX nie wymaga cache owania całego dokumentu. Umożliwia przechwytywanie zdarzeń parsowania tak jakby były to zdarzenia interesu użytkownika. Za pomocą API bazujacego na zdarzeniach możliwe jest utworzenie struktury drzewa i zmapowanie dokumentu XML do tej struktury.
XML i Java 7/57 Biblioteki XML w języku Java http://docs.oracle.com/javase/7/docs/api/
XML i Java 8/57 Wykorzystanie modelu DOM Pakiet org.w3c.dom Interfejsy: Document - reprezentuje cały dokument XML (albo HTML), Node - podstawowy typ danych dla całego DOM, reprezentuje pojedynczy węzeł w drzewie dokumentu, NodeList - uporządkowana kolekcja węzłów (obiekty klasy Node), NamedNodeMap - kolekcja węzłów dostępnych po nazwie elementu, Element - reprezentuje element w dokumencie XML (albo HTML), może zawierać związane z nim atrybuty, dziedziczy po Node, Attr - reprezentuje atrybut w elemencie dokumentu XML.
XML i Java 9/57 Model DOM - Document Interfejs org.w3c.dom.document Najważniejsze metody: createelement(string nazwa) - tworzy element o określonej nazwie, createattribute(string nazwa) - tworzy atrybut o podanej nazwie, createtextnode(string data) - pozwala stworzyć węzeł tekstowy o zawartości data, createcomment(string data) - tworzy komentarz o treści data, createcdatasection(string data) - tworzy sekcje CDATA o zawartości data, createprocessinginstruction(string target, String data) - służy do tworzenia instrukcji przetwarzania o zawartości data, target oznacza cel czyli słowo określające aplikację przetwarzającą.
XML i Java 10/57 Model DOM - Document Interfejs org.w3c.dom.document Najważniejsze metody: getelementsbytagname(string tagname) - zwraca listę węzłów (NodeList) o nazwie znacznika tagname, getdocumentelement() - pozwala na dostęp do elementu głównego całego dokumentu, getxmlversion() - zwraca informację o wersji XML określonej w deklaracji XML dokumentu, getxmlencoding() - zwraca informację o kodowaniu określonym w deklaracji XML dokumentu, getxmlstandalone() - zwraca informację czy dokument XML jest samodzielny czy nie, setxmlstandalone(boolean xmlstandalone), setxmlversion(string xmlversion) - pozwala ustalić samodzielność i wersję dokumentu XML.
XML i Java 11/57 Model DOM - Node Interfejs org.w3c.dom.node, najważniejsze metody (wywoływane dla węzła): getchildnodes() - zwraca listę (NodeList) wszystkich dzieci węzła, getattributes() - zwraca listę atrybutów jako interfejs NamedNodeMap jeśli węzeł jest elementem, hasattributes() - zwraca prawdę jeśli węzeł ma jakiekolwiek atrybuty, haschildnodes() - zwraca prawdę jeśli węzeł ma jakiekolwiek dzieci, getnodename() - zwraca nazwę węzła, getnodevalue() - zwraca wartość węzła, zależnie od typu węzła, setnodevalue(string nodevalue) - pozwala ustalić wartość węzła, zależnie od jego typu, getnodetype() - zwraca typ węzła określny wartością stałej (short), normalize() - normalizauje zawartość tekstową tego węzła i wszyskich jego podwęzłów, normalizacja dotyczy również atrybutów,
XML i Java 12/57 Model DOM - Node Interfejs org.w3c.dom.node, najważniejsze metody (wywoływane dla węzła): appendchild(node newchild) - dodaje dziecko newchild do listy dzieci, replacechild(node newchild, Node oldchild) - zamienia węzeł dziecka oldchild węzłem newchild, removechild(node oldchild) - usuwa węzeł dziecka oldchild, insertbefore(node newchild, Node refchild) - wstawia węzeł newchild przed węzłem refchild, getparentnode() - zwraca rodzica daneg węzła, getfirstchild(), getlastchild() - zwraca pierwsze/ostatnie dziecko. getprevioussibling() - zwraca węzeł bezpośrednio poprzedzający dany węzeł, getnextsibling() - zwraca węzeł występujący zaraz po bierzącym węźle.
XML i Java 13/57 Model DOM - Node, typy węzła Wybrane stałe określające typ węzła (static short): ATTRIBUTE NODE (2) - Węzeł jest atrybutem. CDATA SECTION NODE (4) - Węzeł jest sekcją CDATA. COMMENT NODE (8) - Węzeł jest komentarzem. DOCUMENT NODE (9) - Węzeł jest całym dokumentem XML (klasa Document). ELEMENT NODE (1) - Wezeł jest elementem. ENTITY NODE (6) - Węzeł jest encją. NOTATION NODE (12) - Węzeł jest notacją. PROCESSING INSTRUCTION NODE (7) - Węzeł jest instrukcją przetwarzania. TEXT NODE (3) - Węzel tekstowy.
XML i Java 14/57 Model DOM - Element Interfejs org.w3c.dom.element dziedziczy po interfejsie Node. Najważniejsze unikalne metody: getattribute(string name) - zwraca wartość atrybutu o nazwie name, getattributenode(string name) - zwraca węzeł atrybutu o nazwie name, setattributenode(attr newattr) - dodaje węzeł atrybutu newattr, setattribute(string name, String value) - dodaje atrubyt o nazwie name i wartości value, removeattribute(string name) - usuwa atrybut o nazwie name, removeattributenode(attr oldattr) - usuwa atrybut oldattr, hasattribute(string name) - zwraca prawdę jeśli w elemencie występuje atrybut o nazwie name.
XML i Java 15/57 Model DOM - Attr Interfejs org.w3c.dom.attr, najważniejsze metody: getname() - zwraca nazwę atrybutu, getvalue() - zwraca wartość atrybutu, setvalue(string value) - ustala zawartość atrybutu na value, getownerelement() - zwraca element, do którego należy dany atrybut.
XML i Java 16/57 Model DOM - NodeList Interfejs org.w3c.dom.nodelist zawiera tylko dwie metody: getlength() - zwraca liczbę wezłów zawartych w liście, item(int index) - zwraca węzeł znajdujący się na pozycji index listy. Interfejs org.w3c.dom.namednodemap, najważniejsze metody: getlength() - liczba węzłow w danej kolekcji, item(int index) - zwraca węzeł znajdujący się na pozycji index, getnameditem(string name) - zwraca węzeł o nazwie name, removenameditem(string name) - usuwa węzeł o nazwie name,
XML i Java 17/57 Klasy i intefrejsy modelu DOM Pakiet javax.xml.parsers udostępnia klasy pozwalające na przetwarzanie dokumentów XML. Klasy: DocumentBuilder - pozwala na otrzymanie dokumentu DOM (klasa Document) na podstawie dokumentu XML, DocumentBuilderFactory - klasa pozwala otrzymać parser (klasa DocumentBuilder), który tworzy DOM z dokumentu XML.
XML i Java 18/57 Model DOM - tworzenie dokumentu XML Document doc = docbuilder.newdocument(); Element korzen = doc.createelement("korzen drzewa"); doc.appendchild(korzen); Element osoba = doc.createelement("osoba"); Attr attr = doc.createattribute("atrybut"); attr.setvalue("wartość"); osoba.setattributenode(attr); osoba.setattribute("wiek", "31"); korzen.appendchild(osoba); Element nazwisko = doc.createelement("nazwisko"); nazwisko.appendchild(doc.createtextnode("kowalski")); osoba.appendchild(nazwisko); Element imie = doc.createelement("imie"); imie.appendchild(doc.createtextnode("januszek")); osoba.appendchild(imie);
XML i Java 19/57 Tworzenie drzewa dokumentu - wynik <?xml version="1.0" encoding="utf-8"?> <korzen drzewa> <osoba atrybut="wartość" wiek="31"> <nazwisko>kowalski</nazwisko> <imie>januszek</imie> </osoba> </korzen drzewa>
XML i Java 20/57 Model DOM - drzewo dokumentu z pliku XML Zamiast tworzyć dokument samodzielnie można go stworzyć wczytując/parsując plik XML. Wystarczy klasa File i DocumentBuilder. File fxmlfile = new File("xml/note.xml"); DocumentBuilderFactory docfactory = DocumentBuilderFactory.newInstance(); DocumentBuilder docbuilder = docfactory.newdocumentbuilder(); // tworzenie pustego dokumentu // Document doc = docbuilder.newdocument(); // tworzenie dokumentu z pliku XML Document doc = docbuilder.parse(fxmlfile);...
XML i Java 21/57 Przekształcanie drzewa DOM do pliku Pakiet javax.xml.transform udostępnia API pozwalające przekształcić Dokument z modelu DOM do strumienia wyjściowego. Strumieniem wyjściowym może być plik lub ekran (System.out). Klasy: Transformer - pozwala na przekształcenie źródła dokumentu z modelu DOM do strumienia wyjściowego. TransformerFactory - klasa pozwala otrzymać obiekt klasy Transformer.
XML i Java 22/57 Zapis dokumentu XML - Transformer try { DocumentBuilderFactory docfactory = DocumentBuilderFactory.newInstance(); DocumentBuilder docbuilder = docfactory.newdocumentbuilder(); Document doc = docbuilder.newdocument();... TransformerFactory transformerfactory = TransformerFactory.newInstance(); Transformer transformer = transformerfactory.newtransformer(); DOMSource source = new DOMSource(doc); StreamResult result = new StreamResult(new File("zapisany.xml")); transformer.transform(source, result); catch (ParserConfigurationException pce) { pce.printstacktrace(); catch (TransformerException te) { te.printstacktrace();
XML i Java 23/57 Tworzenie drzewa dokumentu - przykład try { DocumentBuilderFactory docfactory = DocumentBuilderFactory.newInstance(); DocumentBuilder docbuilder = docfactory.newdocumentbuilder(); Document doc = docbuilder.newdocument(); Element korzen = doc.createelement("korzen_drzewa"); doc.appendchild(korzen); Element osoba = doc.createelement("osoba"); korzen.appendchild(osoba); Element nazwisko = doc.createelement("nazwisko"); nazwisko.appendchild(doc.createtextnode("kowalski")); osoba.appendchild(nazwisko); Element imie = doc.createelement("imie"); imie.appendchild(doc.createtextnode("januszek")); osoba.appendchild(imie); TransformerFactory transformerfactory = TransformerFactory.newInstance(); Transformer transformer = transformerfactory.newtransformer(); DOMSource source = new DOMSource(doc); // wypisanie dokumentu XML na ekran StreamResult result = new StreamResult(System.out); transformer.transform(source, result); catch (ParserConfigurationException pce) { pce.printstacktrace(); catch (TransformerException te) { te.printstacktrace();
XML i Java 24/57 Tworzenie drzewa dokumentu - przykład try { DocumentBuilderFactory docfactory = DocumentBuilderFactory.newInstance(); DocumentBuilder docbuilder = docfactory.newdocumentbuilder(); Document doc = docbuilder.newdocument(); Element korzen = doc.createelement("korzen_drzewa"); doc.appendchild(korzen); Element osoba = doc.createelement("osoba"); korzen.appendchild(osoba); Element nazwisko = doc.createelement("nazwisko"); nazwisko.appendchild(doc.createtextnode("kowalski")); osoba.appendchild(nazwisko); Element imie = doc.createelement("imie"); imie.appendchild(doc.createtextnode("januszek")); osoba.appendchild(imie); TransformerFactory transformerfactory = TransformerFactory.newInstance(); Transformer transformer = transformerfactory.newtransformer(); DOMSource source = new DOMSource(doc); // zapisanie dokumentu XML do pliku StreamResult result = new StreamResult(new File("zapisany.xml")); transformer.transform(source, result); catch (ParserConfigurationException pce) { pce.printstacktrace(); catch (TransformerException te) { te.printstacktrace();
XPath i XQuery w języku Java XML i Java 25/57
XML i Java 26/57 XPath w języku Java Pakiet javax.xml.xpath. Obsługa xpath jest domyślnie w bibliotekach Javy, inaczej niż XQuery. Interfejsy/Klasy: XPath - interfejs udostępnia dostęp do wyrażeń XPath, XPathFactory - klasa pozwala na stworzenie instancji obiektu XPath, XPathExpressionException - klasa do obsługi błędów w wyrażeniu XPath, XPathConstants - klasa zawiera pola statyczne określające typ zwracanej wartości przez metode evaluate interfejsu XPath. org.xml.sax.inputsource - klasa opakowująca dane wejściowe, np. plik XML w obiekt.
XML i Java 27/57 XPath Interfejs javax.xml.xpath.xpath, najważniejsze metody: evaluate(string expression, InputSource source) - przetwarza wyrażenie expression w obszarze określonym przez source, wartość zwracana jako String, evaluate(string expression, InputSource source, QName returntype) - jak wyżej tylko returntype określa typ zwracanej wartości - typy XPathConstants, compile(string expression) - kompiluje wyrażenie XPath do późniejszego użycia, zwraca XPathExpression, reset() - resetuje XPath do stanu jaki miał on zaraz po utworzeniu XPathFactory.newXPath().
XML i Java 28/57 Typy XPathConstants Pola klasy XPathConstants (według specyfikacji XPath 1.0): BOLEAN - typ loginczy, DOM OBJECT MODEL - URI dla modelu obiektowego DOM, NODE - typ danych odpowiadający węzłowi, NODESET - typ danych odpowiadający zbiorowi węzłów, NUMBER - wartości liczbowa, STRING - napis, typ string.
XML i Java 29/57 XPath w języku Java - nazwa przedszkola // utworzenie obiektu xpath XPath xpath = XPathFactory.newInstance().newXPath(); String expression = "/przedszkole/nazwa"; InputSource inputsource = new InputSource("xml/przedszkole.xml"); try { NodeList nodes = (NodeList) xpath.evaluate( expression, inputsource, XPathConstants.NODESET ); // lista węzłów bo NODESET... Node n = nodes.item(0); // wartości węzła są zawsze w węzłach tekstowych jako dzieci elementu System.out.println( n.getnodename() + " - " + n.getfirstchild().getnodevalue() ); catch (XPathExpressionException e) { e.printstacktrace();
XML i Java 30/57 XPath w języku Java - imiona dzieci z grupy drugiej XPath xpath = XPathFactory.newInstance().newXPath(); String expression = "//grupa[@id=2]"; InputSource inputsource = new InputSource("xml/przedszkole.xml"); try { Node grupa = (Node) xpath.evaluate(expression, inputsource, XPathConstants.NODE); System.out.println(grupa.getNodeName()); XPath xpath2 = XPathFactory.newInstance().newXPath(); String expression2 = "dziecko/osoba/imie"; // wyrażnie wybiera dane z wyników pierwrzego wyrażenia - grupa NodeList imiona = (NodeList) xpath2.evaluate( expression2, grupa, XPathConstants.NODESET); for(int i=0; i<imiona.getlength(); ++i) { Node n = imiona.item(i); System.out.println( n.getnodename() + " - " + n.getfirstchild().getnodevalue()); catch (XPathExpressionException e) { e.printstacktrace();
XML i Java 31/57 XQuery w języku Java Podstawowe API Javy nie zawiera obsługi XQuery. Aby wykorzystać XQuery w języku Java należy wykorzystać dodatkowy pakiet. Biblioteka Saxonica (www.saxonica.com) Dokumentacja: http://www.saxonica.com/documentation/index.html Dwa pakiety (http://saxon.sourceforge.net/): saxon9he.jar - Saxon Home Edition dla Javy saxon9-xqj.jar - XQJ (ang. XQuery API for Java)
XML i Java 32/57 XQuery w języku Java Pakiet javax.xml.xquery Interfejs: XQDataSource - pozwala na tworzenie połączenia XQConnection. XQConnection - pozwala na uzyskanie połączenia z odpowiednim mechanizmem XQuery. Połączenie jest uzyskiwane przez objekt XQDataSource. XQExpression - towrzy obiekt wyrażeń z języka XQuery. Metoda executequery() pozwala na wykonanie zapytania. XQSequence - interfejs obsługujący sekwencje pozycji opisanych zgodnie z XDM (ang. XQuery and XPath Data Model) XQDataSource ds = new SaxonXQDataSource(); XQConnection conn = ds.getconnection(); XQExpression exp = conn.createexpression(); XQSequence seq = exp.executequery( "for $i in doc( xml/przedszkole.xml )//nazwa return $i" ); com.saxonica.xqj.saxonxqdatasource - Implementacja XQJ XQDataSource biblioteki Saxon.
XML i Java 33/57 XQuery - przykład Dokumentacja Java API: http://www.saxonica.com/documentation/index.html#!javadoc try { XQDataSource ds = new SaxonXQDataSource(); XQConnection conn = ds.getconnection(); XQExpression exp = conn.createexpression(); XQSequence seq = exp.executequery( "for $i in doc( xml/przedszkole.xml )//nazwa return $i"); while (seq.next()) { System.out.println(seq.getSequenceAsString(null)); catch (XQException e) { e.printstacktrace();
SAX - Simple API for XML w języku Java XML i Java 34/57
SAX - podstawowe API SAX nie działa tak jak DOM. Nie wczytuje dokumentu do pamięci jak również nie tworzy reprezentacji obiektowej dokumentu XML. Zamiast tego SAX wywołuje odpowiednie funkcje w odpowiedzi na napotkane zdarzenia. Pakiet org.xml.sax Pakiet org.xml.sax.helpers DefaultHandler - domyślna klasa bazowa do obsługi zdarzeń SAX2. W obiekcie tej klasy należy dodać funkcje obsługujące zdarzenia, początku elementu, końca elementu, itp. Pakiet javax.xml.parsers - udostępnia klasy pozwalające przetwarzać dokumenty XML. Klasy: SAXParser - parser SAX dla XML opakowujący/zawierający interfejs XMLReader. SAXParserFactory - klasa pozwala na otrzymanie parsera SAX (klasa SAXParser), który pozwala na parsowanie dokumentów XML. XML i Java 35/57
SAX - DefaultHandler Wybrane medody klasy org.xml.sax.helpers.defaulthandler. Programista musi przeładować poniższe metody aby obsłużyć zdarzenia wywoływane podczas parsowania dokumentu XML. startdocument() - obsługuje zdarzenie napotkania przez parser początku dokumentu. enddocument() - obsługuje zdarzenie napotkania przez parser końca dokumentu. startelement(string uri, String localname, String qname, Attributes attributes) - obsługuje zdarzenie napotkania początku elementu (qname określa nazwę elementu, attributes lista atrybutów dostępnych przez interfejs Attributes). endelement(string uri, String localname, String qname) - obsługuje zdarzenie końca elementu (qname określa nazwę elementu). characters(char[] ch, int start, int length) - odbiera informacje o danych znakowych wewnątrz elementu. Wszystkie powyższe metody w przypadku błędów wyrzucają SAXException. XML i Java 36/57
XML i Java 37/57 SAX - DefaultHandler - przykład DefaultHandler handler = new DefaultHandler() { public void characters(char[] ch,int start,int length) throws SAXException { System.out.println("Dane znakowe: " + new String(ch, start, length)); ; public void startelement(string uri, String localname,string qname, Attributes attributes) throws SAXException { System.out.println("Początek elementu :" + qname); public void endelement(string uri, String localname, String qname) throws SAXException { System.out.println("Koniec elementu :" + qname); public void startdocument() throws SAXException { System.out.println("Początek DOKUMENTU"); public void enddocument() throws SAXException { System.out.println("Koniec DOKUMENTU");
XML i Java 38/57 Interfejs Attributes Interfejs Attributes pozwala na dostęp do listy atrybutów na trzy sposoby: przez indeks atrybutu, przez nazwę atrybutu z podaniem URI przestrzeni nazw, przez nazwę atrybutu razem z prefiksem (nawa kwalifikowana - qname). Metody intefrejsu Attributes: getindex(string qname) - zwraca indeks atrybutu o podanej nazwie kwalifikowanej (razem z prefiksem), getindex(string uri, String localname) - zwraca indeks atrybutu o podanej nazwie w przestrzeni nazw określonej podanym URI.
XML i Java 39/57 Interfejs Attributes Wybrane metody intefrejsu Attributes: getlength() - zwraca liczbę atrybutów w liście, getlocalname(int index) - zwraca nazwę atrybutu i podanym indeksie, getqname(int index) - zwraca pełną, kwalifikowaną nazwę atrybutu, geturi(int index) - zwraca URI prestrzeni nazw atrybutu o podanym indeksie, getvalue(int index) - zwraca wartość atrybutu o podanym indeksie, getvalue(string qname) - zwraca wartość atrybutu o podanej nazwie, gettype(int index) - zwraca typ atrybutu o podanym indeksie, gettype(string qname) - zwraca typ atrybutu o podanej nazwie.
XML i Java 40/57 Typy atrybutów interfejsu Attributes Typy atrybutów zwracane przez metodę gettype() intefrejsu Attributes: CDATA, ID, IDREF, IDREFS, NMTOKEN, NMTOKENS, ENTITY, ENTITIES, NOTATION.
XML i Java 41/57 Interfejs Attributes - przykład Wyświetlenie na ekranie nazwy i wartości wszystkich atrybutów parsowanego elementu. // metoda z klasy DefaultHandler wykonywania przy napodkaniu nowego elementu public void startelement( String uri, String localname,string qname, Attributes attributes) throws SAXException { for(int i=0; i < attributes.getlength(); i++) { System.out.print( attributes.getlocalname(i) + attributes.getvalue(i) );
XML i Java 42/57 SAX - SAXParser, SAXParserFactory Klasa SAXParserFactory, metody: newinstance() - metoda statyczna, tworzy nową instancję obiektu SAXParserFactory, newsaxparser() - tworzy nową instancję parsera SAXParser. Klasa SAXParser, metody: parse(file f, DefaultHandler dh) - przetwarza zawartość pliku XML używając od obsługi obiektu klasy DefaultHandler. try { SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser saxparser = factory.newsaxparser(); DefaultHandler handler = new DefaultHandler() {... ; saxparser.parse("dokument.xml", handler); catch (Exception e) { e.printstacktrace();
Zapis dokumentu XML Interfejs javax.xml.stream.xmlstreamwriter, najważniejsze medoty: writestartdocument() - zapisuje deklarację XML, writeenddocument() - zamyka otwarte znaczniki i zapisuje je w pliku, writestartelement(string localname) - zapisuje początkowy znacznik o nazwie localname, writeendelement() - zapisuje odpowiedni znacznik końcowy bazując na stanie XMLStreamWriter, writecharacters(string text) - zapisuje zawartość tekstową (text), writeattribute(string localname, String value) - zapisuje atrybut o nazwie localname i wartości value, writecomment(string data) - zapisuje do strumienia komentarz o wartości data. Plik tekstowy jest przetwarzany na strumień za pomocą FileOutputStream. Uzyskujemy obiekt OutputStream. Na bazie tego tworzymy OutputStreamWriter, który służy do stworzenia interfejsu XMLStreamWriter. XML i Java 43/57
XML i Java 44/57 Zapis dokumentu XML - XMLStreamWriter Przykład tworzenia dokumentu XML za pomocą klasy XMLStreamWriter. OutputStream outputstream = new FileOutputStream(new File("doc.xml")); XMLStreamWriter out = XMLOutputFactory.newInstance().createXMLStreamWriter( new OutputStreamWriter(outputStream, "utf-8")); out.writestartdocument(); // tworzy nagłówek XML out.writestartelement("doc"); // znacznik otwierający doc out.writestartelement("title"); out.writecharacters("document Title"); out.writeendelement(); out.writeendelement(); out.writeenddocument(); // znacznik zamykający doc, konieczny jeśli... out.close();
Serializacja do XML w języku Java XML i Java 45/57
XML i Java 46/57 Serializacja w języku Java W procesie serializacji używane są strumienie z języka Java. Znaczna część klas będących strumieniami udostępnia tylko zapis/odczyt obiektów podstawowych (liczby, stringi, tablice). Java zawiera udogodnienie pozwalające na strumieniowanie dowolnych obiektów. Przekształcenie takiego strumienia na postać binarną lub znakową (np. XML) to serializacja. Odczytanie zapisanych w formie binarnej czy tekstowej obiektów to deserializacja. Ważne jest aby proces serializacji był odwracalny.
XML i Java 47/57 Po co jest serializacja? Potrzeba utrwalenia danych w aplikacjach. Możliwe przyczyny: konieczność zachowania danych w pamięci między uruchomieniami aplikacji, brak miejsca w pamięci na wszystkie dane aplikacji jednocześnie - potrzeba zapisania części z nich, zabezpieczenie przed utratą danych. Jeśli nie ma konieczności przeszukiwania składowanych informacji można zamiast baz danych wybrać właśnie serializację. W przypadku serializacji to użytkownik decyduje o miejscu przechowywania plików z danymi na dysku. Serializacja zapewnia pewną trwałość danych przetwarzanych w aplikacjach.
XML i Java 48/57 Gdzie używa się serializacji? Gdzie używa się serializacji? Jeśli mamy rozproszone aplikacje obiektowe to najłatwiej przesyłać przez sieć całe obiekty. Na gniazdach sieciowych można strumieniami przesyłać całe obiekty. Serializacja z użyciem obiektów jest też używana do przekazywania parametrów i wartości zwracanych przy zdalnym wywoływaniu metod. Serializacja leży u podstaw Java RMI wykorzystywanego w wielu technologiach.
XML i Java 49/57 Serializacja do obiektów binarnych Serializacja na postać binarną wykorzystuje klasy: ObjectOutputStream (metoda writeobject(object) ), ObjectInputStream (metoda readobject() ), Obiekt podlegający serializacji musi implementować interfejs java.io.serializable. Jest to interfejs bez metod. Pełni tylko funkcję znacznika. Serializowany jest obiekt przekazany w metodzie writeobject i wszystkie zawarte w nim obiekty. Serializacji poddawany jest cały graf obiektów. Wszystkie obiekty podlegające serializacji powinny implementować interfejs java.io.serializable.
XML i Java 50/57 Serializacja do postaci binarnej - przykład SerBin.java import java.io.*; class Książka implements Serializable { String tytuł; int rokwydania; Autor autor; Książka(String tytuł, int rokwydania, Autor autor) { this.tytuł = tytuł; this.rokwydania = rokwydania; this.autor = autor; System.out.println("wywołanie konstruktora klasy Książka"); public String tostring() { String adrpamięć = super.tostring(); return adrpamięć+"(" + tytuł + ", " + rokwydania + ", " + autor + ")";
XML i Java 51/57 Serializacja do postaci binarnej - przykład SerBin.java class Autor implements Serializable { String nazwisko; String imię; Autor(String nazwisko, String imię) { this.nazwisko = nazwisko; this.imię = imię; System.out.println("wywołanie konstruktora klasy Autor"); public String tostring() { String adrpamięć = super.tostring(); return adrpamięć + "(" + nazwisko + ", " + imię + ")";
XML i Java 52/57 Serializacja do postaci binarnej - przykład SerBin.java public class SerBin { public static void main(string[] args) throws Exception { Autor sienkiewicz = new Autor("Sienkiewicz", "Henryk"); Książka pust = new Książka("W pustyni i w puszczy", 1911, sienkiewicz); System.out.println(pust); ObjectOutputStream out = new ObjectOutputStream( new BufferedOutputStream( new FileOutputStream("ksiazka.bin"))); out.writeobject("książka"); out.writeobject(pust); out.close(); ObjectInputStream in = new ObjectInputStream( new BufferedInputStream( new FileInputStream("ksiazka.bin"))); String nagłówek = (String) in.readobject(); System.out.println(nagłówek); Książka puszcz = (Książka) in.readobject(); in.close(); System.out.println(puszcz);
XML i Java 53/57 Serializacja do obiektów binarnych Jeśli w obiekcie będzie kilka referencji do tego samego obiektu to po deserializacji odpowiednie referencje będą zachowane (np. dwie osoby mające ten sam adres). Przy deserializacji, mimo powstawania nowych obiektów, nie są wywoływane konstruktory. Domyślnie serializowane są wszystkie niestatyczne składowe przekazanego obiektu. Nie zawsze jest to działanie pożądane. Niektórch danych (np. dane poufne) czy obiektów (np. strumienie czy wątki) nie powinno się serializować. Nie wszystkie obiekty implementują interfejs java.io.serializable - nie wszystko da się serializować. Rozwiązaniem jest: rezygnacja z domyślnego mechanizmu serializacji (trzeba wtedy samemu napisać kod odpowiedzialny za serializację) wskazanie atrybutów, które nie podlegają serializacji (transient). Atrybuty wyłączone z serializacji oznaczamy modyfikatorem transient.
XML i Java 54/57 Serializacja do XML Klasy ObjectOutputStream i ObjectInputStream - serializacja binarna między aplikacjami w języku Java. Do wymiany danych między różnymi językami programowania stosuje się język XML, a od jakiegoś czasu również JSON. Serializacja do XML jest tak samo łatwa jak serializacja do postaci binarnej. Zamiast klas ObjectOutputStream i ObjectInputStream używa się klas XMLDecoder i XMLEncoder (pakiet java.beans). Serializacja do XML nie wymaga interfejsu java.io.serializable ale zgodności z Java Beans czyli: klasy muszą posiadać bezparametrowy publiczny konstruktor, muszą posiadać metody set i get dla każdego atrybutu.
XML i Java 55/57 Serializacja do XML - przykład Autor.java public class Autor { String nazwisko; String imię; Autor(String nazwisko, String imię) { this.nazwisko = nazwisko; this.imię = imię; System.out.println("wywołanie konstruktora klasy Autor"); public String tostring() { String adrpamięć = super.tostring(); return adrpamięć + "(" + nazwisko + ", " + imię + ")"; public String getnazwisko() { return nazwisko; public String getimię() { return imię; public void setnazwisko(string nazwisko) { this.nazwisko = nazwisko; public void setimię(string imię) { this.imię = imię; public Autor() { System.out.println("wywołanie bezparametrowego konstruktora klasy Autor");
XML i Java 56/57 Serializacja do XML - przykład Książka.java public class Książka { String tytuł; int rokwydania; Autor autor; Książka(String tytuł, int rokwydania, Autor autor) { this.tytuł = tytuł; this.rokwydania = rokwydania; this.autor = autor; System.out.println("wywołanie konstruktora klasy Książka"); public String tostring() { String adrpamięć = super.tostring(); return adrpamięć+"(" + tytuł + ", " + rokwydania + ", " + autor + ")"; public Autor getautor() { return autor; public String gettytuł() { return tytuł; public int getrokwydania() { return rokwydania; public void setautor(autor autor) { this.autor = autor; public void settytuł(string tytuł) { this.tytuł = tytuł; public void setrokwydania(int rokwydania) { this.rokwydania = rokwydania; public Książka() { System.out.println("wywołanie bezparametrowego konstruktora klasy Książka");
XML i Java 57/57 Serializacja do XML - przykład SerXML.java import java.beans.*; import java.io.*; public class SerXML { public static void main(string[] args) throws IOException { Autor sienkiewicz = new Autor("Sienkiewicz", "Henryk"); Książka pust = new Książka("W pustyni i w puszczy", 1911, sienkiewicz); Książka quovadis = new Książka("Quo vadis", 1896, sienkiewicz); XMLEncoder e = new XMLEncoder( new BufferedOutputStream( new FileOutputStream("ksiazka.xml"))); System.out.println(pust); System.out.println(quoVadis); e.writeobject(pust); e.writeobject(quovadis); e.close(); XMLDecoder d = new XMLDecoder( new BufferedInputStream( new FileInputStream("ksiazka.xml"))); pust = (Książka) d.readobject(); quovadis = (Książka) d.readobject(); System.out.println(pust); System.out.println(quoVadis);