• Nem Talált Eredményt

A StAX API használata

In document Programozási technológiák – Jegyzet (Pldal 132-137)

A szerződés alapú tervezés alapelvei

A szerződés

1. XML dokumentumok kezelése

1.4. A StAX API használata

A DOM implementációk gyűjteményéből le kell kérni egy LS modult megvalósító implementációt, ha ilyen létezik, majd ezen implementáció segtségével egy szerializáló objektum létrehozására van szükség. A szerializáló működését különféle paraméterekkel befolyásolhatjuk, a példában az emberi fogyasztásra is szánt dokumentumok számára kvázi kötelező format-pretty-print paraméter beállításának mikéntje látható.

A szerializáló objektum egy DOM csomópont kiírását képes elvégezni, ez példánkban a dokumentumfa gyökere. A kiíráshoz azonban szükség van egy LSOutput-ra, ahová a kimenet megy majd. A kimenetre vonatkozóan előírjuk az UTF-8-as karakterkódolást, és beállítjuk, hogy milyen stream-re menjen a kimenet.

Végül a szerializátor objektum write metódusával tudjuk a kívánt csomópontot a kivánt kimenetre írni.

1.4. A StAX API használata

A StAX API lehetővé teszi XML dokumentumok beolvasását és érvényességük ellenőrzését, ezenkívül eszközöket biztosít létrehozásukhoz is.

1.4.1. StAX feldolgozás

A StAX API-val történő feldolgozás során az iterátor API típusait és metódusait használjuk.

A példametódus egy állományból olvas be egy XML dokumentumot az eseményiterátor API segítségével. A dokumentum termékekről tartalmaz információkat. A feldolgozás során termékobjektumokat hozunk létre, amelyeket egy listában tárolunk el.

public List<Product> readXmlWithStAX(File xmlFile) { List<Product> productList = new ArrayList<>();

Az XML eseményeket olvasó objektumot az alapértelmezett gyár állítja elő. A createXMLEventReader gyártó metódus paramétere az XML fájl bemeneti adatfolyam objektumként. Az ily módon létrehozott XMLEventReader objektumot használjuk fel az események beolvasására.

try {

XMLInputFactory inputFactory = XMLInputFactory.newInstance();

InputStream in = new FileInputStream(xmlFile);

XMLEventReader eventReader = inputFactory.createXMLEventReader(in);

Adatkezelés

Product product = null;

Method productMethod = null;

Az XML dokumentum beolvasása egy while ciklus segítségével történik. Mindddig beolvassuk a következő eseményt, amíg el nem érjük a dokumentum végét.

while (eventReader.hasNext()) {

XMLEvent event = eventReader.nextEvent();

Ha az esemény egy elem kezdő tagja, akkor az eseményt átkonvertáljuk a javax.xml.stream.events.StartElement interfészt megvalósító objektummá, hogy elérjük a StartElement típus metódusait.

if (event.isStartElement()) {

StartElement productStartElement = event.asStartElement();

Az elem getName metódusa a teljes minősített nevet tartalmazza, de nekünk csak a lokális névre van szükségünk. A név lokális részét a getLocalPart metódus segítségével kérhetjük el.

if

(productStartElement.getName().getLocalPart().equalsIgnoreCase("product")) {

Egy elem adott nevű attribútumát a getAttributeByName metódussal kaphatjuk meg, amely egy javax.xml.namespace.QName objektumot vár paraméterként. QName objektumot kétféleképpen készíthetünk sztring objektumból: a QName konstruktorával vagy statikus valueOf metódusával. Az attribútum értékét a javax.xml.stream.events.Attribute típus getValue metódusával kérdezhetjük le.

Megjegyzés

A QName osztály az XML specifikációban megadott teljesen minősített nevet reprezentál, amely tehát egy névtér-URI-ból, egy lokális részből és egy prefixből áll.

// Attribute attribute = startElement.getAttributeByName(new

Ha a StartElement objektum a termékobjektum egy adattagját leíró nyitóelem olvasásának eredményeként keletkezett, akkor továbbmegyünk a következő eseményre, amely az XML elem szöveges értékét tartalmazó csomópont beolvasása, majd eltároljuk ezt az értéket a termékobjektum megfelelő adattagjában.

if (event.isStartElement()) {

Adatkezelés

Amennyiben többféle esemény is érdekel, az egyes eseményfajták szerinti olvasást egy switch szerkezettel végezhetjük el legkönnyebben:

Adatkezelés

1.4.2. Validálás

Az XML dokumentum validálásához itt példaként a javax.xml.validation.Validator osztályt használjuk.

Ez az osztály azonban (bizonyos megkötések mellett) nemcsak StAX API-val használható, de akár SAX-szal és DOM-mal is képes együttműködni (ebben az értelemben pedig alternatívát biztosít a korábban már látott validációs lehetőségekhez). Legfontosabb metódusa a validate, amely a korábban a transzformációk során már említett javax.xml.transform csomag Source és Result interfészeit megvalósító egy-egy osztályt kap paraméteréül, és a forráson elvégezve a validációt, a célobjektumba helyezi az (esetlegesen kibővített) XML-t.

Megjegyzés

A validate metódus megengedi, hogy – amennyiben a hívót nem érdekli az érvényesítés során esetlegesen kibővülő XML –, a Resultnull értékű legyen (az egyparaméteres változat meghívása ezzel egyenértékű). Ekkor bármilyen forrás (SAXSource, DOMSource, StAXSource, StreamSource) megadható. Amennyiben azonban megadjuk a Result típusú paraméter értékét is, úgy teljesülnie kell annak a megkötésnek, hogy a Source és a Result tényleges típusának meg kell egyeznie! Vagyis ha a SourceDOMSource, akkor a Result csak DOMResult lehet, és így tovább. Amennyiben ez nem így van, a validate metódus ezt egy IllegalArgumentException típusú kivétel eldobásával jelzi.

A Validator osztály setErrorHandler metódusával a érvényesítést végző objektumhoz társíthatunk egy hibakezelőt (ahogyan azt a SAX stílusú feldolgozásról szóló részben már bemutattuk). Abban az esetben, ha a validáció során hiba történik, a validate metódus a kapcsolt hibakezelő megfelelő

//Ha eljutunk eddig a pontig és nem keletkezik kivétel, akkor az XML dokumentum érvényes.

System.out.println("Az XML dokumentum érvényes.");

1.4.3. XML dokumentum létrehozása StAX API segítségével

Az XML dokumentum StAX API alapján történő létrehozását szintén az eseményiterátor API-n keresztül mutatjuk be.

Az alábbi példametódus (writeXmlWithStAX) egy termékeket tartalmazó lista tartalmát írja ki egy XML állományba.

public void writeXmlWithStAX(File xmlFile, List<Product> productList) throws ... {

Az XML eseményíró objektumot az alapértelmezett gyár állítja elő. A createXMLEventWriter gyártó metódus paramétere az XML fájl kimeneti adatfolyam objektumként. Az ily módon létrehozott XMLEventWriter objektumot használjuk fel az események dokumentumba írására.

Az eseményírón kívül egy XMLEventFactory objektumra is szükség van, amely az XML eseményeket állítja elő. Az XMLEventFactory objektum gyártó metódusai által létrehozott eseményeket kapja meg paraméterként az XMLEventWriter objektum hozzáfűző (add) metódusa.

XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();

XMLEventWriter eventWriter = outputFactory.createXMLEventWriter(new FileOutputStream(xmlFile));

XMLEventFactory eventFactory = XMLEventFactory.newInstance();

Whitespace-karaktert (újsort) reprezentáló esemény előállítása.

Adatkezelés

A dokumentum kezdetét reprezentáló eseményobjektum létrehozása és kiírása.

StartDocument startDocument = eventFactory.createStartDocument();

eventWriter.add(startDocument);

Egy-egy XML elem nyitócímkéjét a createStartElement metódus gyártja le. Mivel a példában nem használunk névtereket, a createStartElement metódus QName prefix és QName URI argumentuma is üressztring.

StartElement startElement = eventFactory.createStartElement("", "", "products");

eventWriter.add(startElement);

eventWriter.add(newLine);

...

A termékobjektumokat tartalmazó listán iterálunk végig, miközben a termékek egyes részeit, vagyis az adattagok értékét egyesével hozzáfűzzük a kiírandó elemekhez, azaz a kiírást végző XMLEventWriter objektumhoz.

for (Product product : productList) {

eventWriter.add(eventFactory.createStartElement("", "", "product"));

String selectorValue = (product instanceof Book ? "Book" : "DVD");

Attribútum létrehozása és hozzáfűzése az aktuális eseményhez, most egy termék kezdőcímkéjéhez.

eventWriter.add(eventFactory.createAttribute("selector", selectorValue));

...

XmlElement xmlelem = productField.getAnnotation(XmlElement.class);

productMethod = ... létrehozására szolgál, amelyeket a paraméterként kapott eseményíró objektumhoz ad hozzá. A metódus második és harmadik argumentuma a kiírandó elem neve és értéke.

private void createNode(XMLEventWriter eventWriter, String name, String value) throws XMLStreamException {

XMLEventFactory eventFactory = XMLEventFactory.newInstance();

XMLEvent newLine = eventFactory.createDTD("\n");

XMLEvent tab = eventFactory.createDTD("\t");

StartElement startElement = eventFactory.createStartElement("", "", name);

eventWriter.add(tab);

eventWriter.add(startElement);

A paraméterként kapott XML elem értékét átkonvertáljuk Characters objektummá.

Characters characters = eventFactory.createCharacters(value);

eventWriter.add(characters);

Létrehozzuk a zárócímkét is.

EndElement endElement = eventFactory.createEndElement("", "", name);

Miután az adott termék minden adattagját hozzáadtuk az eseményíróhoz, bezárjuk a terméket leíró elemet, vagyis az eseményíróhoz hozzáadunk egy product zárócímkét.

eventWriter.add(endElement);

eventWriter.add(newLine);

}

Adatkezelés

Miután az adott termék minden adattagját hozzáadtuk az eseményíróhoz, bezárjuk a termék elemet. Az eseményíróhoz hozzáadunk egy product záró tagot.

eventWriter.add(eventFactory.createEndElement("", "", productTagName));

eventWriter.add(newLine);

}

A dokumentum gyökérelemének zárócímkéjét is hozzáfűzzük az események láncához.

eventWriter.add(eventFactory.createEndElement("", "", "products"));

eventWriter.add(newLine);

Ezután következik a dokumentum végét reprezentáló objektum..

eventWriter.add(eventFactory.createEndDocument());

Az XML dokumentum tényleges kiírása a megadott fájlba az eseményíró obejktum close metódusának hívásakor történik

eventWriter.close();

}

In document Programozási technológiák – Jegyzet (Pldal 132-137)