Java a XML Java i XML jsou přenositelné V javě existuje podpora pro práci s XML, nejčastější akce prováděné při zpracování XML: • načítání XML elementů • generování nových elementů nebo úprava starého • zápis do XML dokumentu • transformace XML do jiných formátů Parsování XML Java obsahuje množství knihoven pro práci s XML, provedou rozdělení XML do jednotlivých částí = parsování. Těmto nástrojům se říká parsery a bývají součástí každého moderního programovacího jazyka. Parser by měl umět: • číst XML dokument a kontrolovat jeho strukturu, validovat podle DTD nebo XSD • během čtení extrahovat názvy a hodnoty elementů a atributů • nabízí abstraktní model XML dokumentu = infoset Parsery se dělí podle zvoleného způsobu zpracování, každý způsob je popsán pomocí svého API = programátorské rozhraní. Základní dělení: • proudové čtení • stromová reprezentace dokumentu Proudové čtení Typickým představitelem SAX = Simple API for XML. Pro každou ucelenou část vyvolává událost, naším úkolem je napsat obsluhy těchto událostí (viz. návrhový vzor vydavatelodběratel). Výhody: • velká rychlost • malá paměťová náročnost • podporované API, je součástí Java Core API od JDK 1.4 Nevýhody: • dokument se zpracovává sekvenčně, při čtení se nelze vracet • načtené zpracovává nebo někam ukládá Stromová prezentace dokumentu Celý dokument se načte naráz do stromové struktury v paměti. Typickým představitelem je DOM = Document Object Model. Výhody: • celý infoset je najednou dostupný v paměti • načtený dokumet se může měnit • stejně jako SAX je DOM podporované od JDK 1.4 • výhodou dobrá spolupráce s jazykem XPath = XML Path Language Nevýhody: • malá rychlost načítání • velká paměťová náročnost
10/26/09
1/7
Java a XML
Příklad - Proudové čtení import org.xml.sax.*; import org.xml.sax.helpers.*; import javax.xml.parsers.*; public class ParsovaniXML { private static final String SOUBOR = "vyukovyProgram/texty/uvod.xml"; public static void main(String[] args)
{
try { /* vytvoření universálního parseru */ SAXParserFactory uniPar = SAXParserFactory.newInstance(); /* validace podle souboru DTD nebo XSD uniPar.setValidating(false); */ /* vytvoření objektu parseru starší verze SAX1 (použit implicitní parser Xerces */ SAXParser parserSAX1 = uniPar.newSAXParser(); /* vytvoření objektu parseru vyšší verze SAX2 */ XMLReader parser = parserSAX1.getXMLReader(); /* nastavení reakce na chyby souboru XML */ parser.setErrorHandler(new ChybyZjisteneParserem()); /* nastavení obsluh pro čtení XML dat pomocí prázdného adaptéru - ten nic nedělá: parser.setContentHandler(new DefaultHandler()); nebo pomocí mého adaptéru, který dědí od DefaultHandler */ MujHandler handler = new MujHandler(); parser.setContentHandler(handler); /* parserování určitého souboru */ parser.parse(SOUBOR); handler.text(); System.out.println(SOUBOR + "přečten bez chyb"); } catch(Exception e) { e.printStackTrace(); } } } --------------------------------------------------------------------------------
Proudové čtení používáme metody: • • • •
• kde • •
public void startDocument() public void startElement(String uri, String localName, String Attributes attrs) public void characters(char[] ch, int start, int delka) public void endElement(String uri, String localName, String qName)
qName,
public void endDocument() ... URI jménného prostoru, není-li použit, je prázdný localName ... jméno lementu v souvislosti se jmenným prostorem, když není použit, je prázdné!!! uri
10/26/09
2/7
Java a XML
• • • • •
... úplné jméno elementu atts ... seznam atributů ch ... pole znaků, ve kterých je uložena hodnota elementu, pro krátké xml je to celý textový soubor start ... index počátečního znaku aktuální hodnoty length ... počet znaků qName
1. Hodnota elementu může přijít po částech - v několika voláních metody chatacter(), proto je zapotřebí je ukládat postupně do StringBufferu a spojovat. 2. ch obsahuje i znaky mezi elementy (např. odřádkování), je zapotřebí kontrolovat, jestli jsme uvnitř konkrétního elementu
-------------------------------------------------------------------------------package XML; import org.xml.sax.*; public class ChybyZjisteneParserem implements ErrorHandler { /* vytvoření textu hlášení */ private String textHlaseni(SAXParseException e) return e.getSystemId() + "\n" + "radka: " + e.getLineNumber() + " sloupec: " + e.getColumnNumber() + "\n" + e.getMessage(); }
{
/* obsluha varovných hlášení */ public void warning(SAXParseException e) { System.out.println("Varování: " + textHlaseni(e)); } /* obsluha chyb */ public void error(SAXParseException e) throws SAXException throw new SAXException("Chyba: " + textHlaseni(e)); }
{
/* obsluha fatálních chyb */ public void fatalError(SAXParseException e) throws SAXException throw new SAXException("Kritická chyba: " + textHlaseni(e)); }
{
} -------------------------------------------------------------------------------import org.xml.sax.*; import org.xml.sax.helpers.*; //import javax.xml.parsers.*; public class MujHandler extends DefaultHandler { private static final int VELIKOST_BUFFERU = 10000; private StringBuffer hodnota = new StringBuffer(VELIKOST_BUFFERU); public void text() { System.out.println(hodnota); } public void startDocument() hodnota.setLength(0); }
10/26/09
{
3/7
Java a XML
public void startElement(String uri, String localName, Attributes attrs) { if(qName.equals("podnadpis")) hodnota.append("\n"); hodnota.append("\n* " + qName + "\n\t"); } public void characters(char[] ch, int start, int delka) hodnota.append(ch, start, delka); }
String
qName,
{
public void endElement(String uri, String localName, String qName) { hodnota.append("\n* /" + qName); } } -------------------------------------------------------------------------------jidlo.xml <jidlo>
jablka 2.5 banány 2 grapefruidy 0.75 švestky sušené 1.8 --------------------------------------------------------------------------------
Převod infosetu na seznam objektů Napíšeme si odpovídající třídu: public class Ovoce { int cislo; String nazev; int jednotkovaCena; double vaha; public Ovoce(int cislo, String nazev, int jednotkovaCena, double vaha) { this.cislo = cislo; this.nazev = nazev; this.jednotkovaCena = jednotkovaCena; this.vaha = vaha; } public String toString() { return "" + cislo + ". " + nazev + " - " + vaha + " [kg] po " + jednotkovaCena + " [Kc] = " + vaha*jednotkovaCena + " [Kc]"; } }
V paměti budou vzniklé objekty třídy Ovoce uloženy v seznamu typu ArrayList
, ze kteréhoje možné kdykoliv získat potřebné informace. 10/26/09
4/7
Java a XML
Mohu zjistit například celkovou váhu a celkovou cenu ovoce: /* získání obsahu testu ze souboru xml */ VseVPametiSAX pars = new VseVPametiSAX(cestaTest + soubor); ArrayList ot = new ArrayList(); ot = pars.getSeznam(); -------------------------------------------------------------------------------import org.xml.sax.*; import org.xml.sax.helpers.*; import javax.xml.parsers.*; import java.util.*; public class VseVPametiSAX { private String soubor; private static ArrayList ot = new ArrayList(); public ArrayList getSeznam() { return ot; } public VseVPametiSAX(String soubor) { this.soubor=soubor; try { /* vytvoření universálního parseru */ SAXParserFactory uniPar = SAXParserFactory.newInstance(); /* validace podle souboru DTD nebo XSD uniPar.setValidating(false); */ /* vytvoření objektu parseru starší verze SAX1 (použit implicitní parser Xerces */ SAXParser parserSAX1 = uniPar.newSAXParser(); /* vytvoření objektu parseru vyšší verze SAX2 */ XMLReader parser = parserSAX1.getXMLReader(); /* nastavení reakce na chyby souboru XML */ parser.setErrorHandler(new ChybyZjisteneParserem()); /* nastavení obsluh pro čtení XML dat pomocí prázdného adaptéru - ten nic nedělá: parser.setContentHandler(new DefaultHandler()); nebo pomocí mého adaptéru, který dědí od DefaultHandler */ VseVPametiHandler handler = new VseVPametiHandler(); parser.setContentHandler(handler); /* parserování určitého souboru */ parser.parse(soubor); ot = handler.getSeznam(); } catch(Exception e) { e.printStackTrace(); } } } -------------------------------------------------------------------------------import org.xml.sax.*; import org.xml.sax.helpers.*; import java.util.*;
10/26/09
5/7
Java a XML
public class VseVPametiHandler extends DefaultHandler { private static ArrayList ot = new ArrayList(); private static final int VELIKOST_BUFFERU = 1000; private StringBuffer hodnota = new StringBuffer(VELIKOST_BUFFERU); private private private private private private
boolean boolean boolean boolean boolean boolean
uvnitrZneni = false; uvnitrA = false; uvnitrB = false; uvnitrC = false; uvnitrD = false; uvnitrSpravne = false;
String zneni; String a; String b; String c; String d; char spravne; public ArrayList getSeznam() { return ot; } public void startDocument() ot.clear(); }
{
public void startElement(String uri, String localName, String Attributes attrs) { hodnota.setLength(0); if (qName.equals("zneni") == true) uvnitrZneni = true; else if (qName.equals("a") == true) uvnitrA = true; else if (qName.equals("b") == true) uvnitrB = true; else if (qName.equals("c") == true) uvnitrC = true; else if (qName.equals("d") == true) uvnitrD = true; else if (qName.equals("spravne") == true) uvnitrSpravne = true; }
qName,
public void characters(char[] ch, int start, int delka) { if (uvnitrZneni == true || uvnitrA == true || uvnitrB == true || uvnitrC == true || uvnitrD == true || uvnitrSpravne == true) hodnota.append(ch, start, delka); } public void endElement(String uri, String localName, String qName) { if (uvnitrZneni == true) { zneni = hodnota.toString(); uvnitrZneni = false; } else if (uvnitrA == true) { a = hodnota.toString(); uvnitrA = false; } else if (uvnitrB == true) { b = hodnota.toString(); uvnitrB = false; } else if (uvnitrC == true) { c = hodnota.toString(); uvnitrC = false; } else if (uvnitrD == true) {
10/26/09
6/7
Java a XML
d = hodnota.toString(); uvnitrD = false; } else if (uvnitrSpravne == true) { spravne = hodnota.toString().charAt(0); uvnitrSpravne = false; } else if (qName.equals("otazka") == true) { ot.add(new Otazka(zneni, a, b, c, d, spravne)); }
//pridat novy objekt
} /* public void endDocument() { System.out.println("pocet prvku v kolekci: " + ot.size()); } */ }
SAX ... http://www.kiv.zcu.cz/~herout/java/ujj4/index.html • vytvořím objekt parseru (implicitním parserem je Xerces) ◦ vytvořím obálku pro univerzální parser ◦ nastavení konfigurace pro budoucí parser ◦ vytvoří nový parser ◦ nastavenení reakcí na chyby • zpracování parsovaného XML dokumentu • převod infosetu na seznam objektů
10/26/09
7/7
Java a XML