• Nem Talált Eredményt

DOM feldolgozás

In document Programozási technológiák – Jegyzet (Pldal 125-130)

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

A szerződés

1. XML dokumentumok kezelése

1.3. A DOM API használata

1.3.1. DOM feldolgozás

@Override

public void error(SAXParseException spe) throws SAXException { String message = "Error: " + getParseExceptionInfo(spe);

throw new SAXException(message);

}

@Override

public void fatalError(SAXParseException spe) throws SAXException { String message = "Fatal Error: " + getParseExceptionInfo(spe);

throw new SAXException(message);

} });

Összerendeljük az XML dokumentumot egy sémával. Ez elvégezhető XML dokumentumból éppúgy, mint Java kódból. Utóbbi esetben a sémadokumentum helyét szintén egy property beállításával hozhatjuk a feldolgozó tudomására.

static final String JAXP_SCHEMA_SOURCE =

"http://java.sun.com/xml/jaxp/properties/schemaSource";

if (schemaSource != null) {

saxParser.setProperty(JAXP_SCHEMA_SOURCE, new File(schemaSource));

}

A példában a schemaSource változó a sémát tartalmazó fájl neve.

1.3. A DOM API használata

A DOM API lehetővé teszi XML dokumentumok beolvasását és érvényességük ellenőrzését, valamint létrehozásukhoz is támogatást nyújt.

1.3.1. DOM feldolgozás

Az XML dokumentumok DOM feldolgozása során felépített fa csomópontokból áll, amelyek különféle típusúak lehetnek. Az alábbi táblázat a fontosabb csomóponttípusokat foglalja össze.

6.2. táblázat - XML dokumentumok csomópontjai

Csomópont A csomópont neve A csomópont értéke

Attr Az attribútum neve Az attribútum értéke

CDATASection #cdata-section A CDATA-szakasz tartalma

Comment #comment A megjegyzés tartalma

Document #document null

DocumentFragment #document-fragment null

DocumentType A dokumentumtípus neve null

Element Az elem neve null

Adatkezelés

Csomópont A csomópont neve A csomópont értéke

EntityReference A hivatkozott egyed neve null

Notation A jelölés neve null

ProcessingInstruction A feldolgozási utasítás célja A cél kivételével a teljes tartalom

Text #text A szöveges csomópont tartalma

Ezeknek a csomóponttípusoknak az ismerete alapvető fontosságú a DOM-mal történő feldolgozás során.

Az alábbi példametódus egy állományból olvas be egy XML dokumentumot, amely termékekről tartalmaz információkat. A fájl feldolgozása a DOM API segítségével történik. A feldolgozás során termékobjektumokat hozunk létre, amelyeket egy listában tárolunk el.

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

Az XML-feldolgozót (vagyis a DocumentBuilder objektumot) az alapértelmezett gyár állítja elő. A builder olvassa be és elemzi a parse metódusának paramétereként átadott XML dokumentumot, amelyből előállítja a faszerkezetet, majd visszatér a fa gyökércsomópontjával. A gyökér egy Document típusú objektum, amely a belépési pontot jelenti a dokumentumot reprezentáló fába.

try {

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

DocumentBuilder docBuilder = factory.newDocumentBuilder();

Document doc = docBuilder.parse(xmlFile);

...

Product product = null;

Fontos

Az XML dokumentum technikai értelemben történő feldolgozása a fenti kódban látható három sorral kész is van. A gyártó legyártotta a feldolgozót, amely a parse metódus meghívásakor felépítette a DOM fát a memóriában. Innentől kezdve a feldolgozó feladata csupán annyi, hogy a kliens számára a DOM API-n keresztül hozzáférést biztosítson a fa tartalmához és szerkezetéhez. Elképzelhető, hogy az elemzés sikertelen, amennyiben például a dokumentum nem jólformált. Ezt a parse metódus egy SAXException kivételobjektum eldobásával jelzi.

A DOM fa gyökérelemén keresztül közvetlenül férhetünk hozzá annak bármely leszármazottjához, tekintet nélkül arra, hogy az hol helyezkedik el a hierarchiában. A getElementsByTagName metódus paraméterként kapja az XML elem nevét, és visszaadja az összes ilyen nevű elemet mint csomópontot. Ezeket egy listába szervezi, amelynek típusa NodeList. Egy csomópontlistát ciklussal járunk be ugyanúgy, mint bármely más kollekciót. A lista elemeinek típusa Node.

A Java osztályok és az XML dokumentum elemei közötti leképezés

Példánkban – annak érdekében, hogy a reflektív programozás bizonyos elemeit is bemutathassuk – a szakterületi Java osztályaink elemeit különféle annotációkkal ellátva végezzük az XML dokumentumok elemei és a Java objektumaink közötti megfeleltetést. Nem célunk itt az összes szakterületi osztály és definiált annotáció bemutatása, csak a példakódok megértéséhez szükséges mértékben megyünk bele a részletekbe.

Definiáltunk többek között az XmlElement és az XmlAttribute annotációtípusokat. Az XmlElement annotációval osztályokat és adattagokat jelölhetünk el, az annotáció pedig azt mondja meg, hogy az adott osztálynak illetve adattagnak az annotációtípus value paraméterének értékével meghatározott XML elem feleljen meg.

@Target({ElementType.TYPE, ElementType.FIELD})

@Retention(RetentionPolicy.RUNTIME) public @interface XmlElement { public String value();

public String selectorAttribute() default "selector";

}

Adatkezelés

Az XmlAttribute annotáció adattagokat jelölhet, jelentése, hogy az adott adattag az XML dokumentum valamely (a value paraméter értékével meghatározott nevű) attribútumának felel meg.

@Target(ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME) public @interface XmlAttribute { public String value();

}

A fentiek alkalmazására példa a Product osztály:

@XmlElement("product")

public abstract class Product { @XmlAttribute("id")

private String id;

@Collection(keyElement = "*", valueElement = "person", elementName =

"contributors", valueType = Person.class,

setterMethodName = "addContributors", setterMethodArgTypes = {String.class, Person[].class})

private Map<String, List<Person>> contributors;

private String originalTitle;

@XmlElement("yearofpublishing") private Integer yearOfPublishing;

private Integer seriesFromYear;

Adatkezelés

String productTagName = productClass.getAnnotation(XmlElement.class).value();

NodeList productNodeList = doc.getElementsByTagName(productTagName);

for (int i = 0; i < productNodeList.getLength(); i++) {

A NodeList objektum item metódusa segítségével kérhetjük le az adott pozíción elhelyezkedő vagy a soron következő elemet (csomópontot).

Node productNode = productNodeList.item(i);

A csomópontok típusa eltérő lehet aszerint, hogy az XML dokumentumban milyen szerepet töltenek be.

Esetünkben elem típusú csomópontokat dolgozunk fel, ezért megvizsgáljuk, hogy az aktuális csomópont megfelelő típusú-e (elem csomópont-e).

if (productNode.getNodeType() == Node.ELEMENT_NODE) {

Ha elem a csomópont, biztonságosan Element típusúra kényszeríthetük. Ez szükséges ahhoz, hogy hozzáférhessünk olyan speciális metódusokhoz, amelyek definíciója az Element interfészben található, nem pedig ősében, a Node interfészben.

Element productElement = (Element) productNode;

Az elem csomópontok tartalmazhatnak attribútumokat, amelyeket a getAttribute metódus segítségével kérdezhetünk le. A metódusnak az attribútum nevét adjuk meg paraméterként. A getAttribute az attribútum értékével mint sztringgel tér vissza. Esetünkben, ha az attribútum értéke "B", akkor a szóban forgó termék egy könyv, egyébként egy DVD.

Mivel a DOM fa már létrejött, és úgyszólván közvetlen hozzáférésünk van az egyes elemeihez, nem az XML dokumentumban lévő sorrendet vesszük alapul a bejárás során, hanem Java oldalról közelítünk: a Product osztály adattagjain iterálunk végig, és kérjük le a nekik megfelelő XML elemeket.

for (Field productField : productFields) { productMethod =

productClass.getMethod(getSetterName(productField.getName()), productField.getType());

Az adattagot módosító XmlAttribute annotáció tartalmazza az adattag XML-beli attribútumnevét, amelyet az Element típusú productElement objektum getAttribute metódusának átadva megkapjuk az attribútum értékét, majd a beállító metódust meghívva eltároljuk ezt az értéket a termékobjektum megfelelő adattagjában.

if (productField.isAnnotationPresent(XmlAttribute.class)) { tagName =

productField.getAnnotation(XmlAttribute.class).value();

Egy termék adattagjainak értéke itt szöveges vagy egyszerű típusú érték lehet, például egy szám.

if

Adatkezelés

Az adattag XmlElement annotációval van ellátva, amely tartalmazza az adattag XML elem nevét, amelynek alapján az Element típus getElementsByTagName metódusa egy csomópont listát ad vissza.

else

Egy Element típusú objektum közvetlen leszármazottait a getChildNodes metódus segítségével kaphatjuk meg. A csomópontlista bármely eleme közvetlenül elérhető a megfelelő index használatával (kk).

NodeList valueNodeList = keyElement.getChildNodes();

for (int kk = 0; kk < valueNodeList.getLength(); kk++) {

XML dokumentumok validációja a DOM stílusú feldolgozás során is hasonló módon történik, mint SAX API esetében.

Mivel a JAXP elemzői alapértelmezett esetben figyelmen kívül hagyják a névtereket, ezért explicit módon kérni kell (a gyártó objektumtól), hogy olyan elemző jöjjön létre, amely tekintetbe veszi a névtereket is. Ez a beállítás a sémavalidáció megfelelő működéséhez szükséges.

factory.setNamespaceAware(true);

factory.setValidating(true);

//csak XSD-vel szembeni validáció esetén állítjuk be a használni kívánt //elemző nyelvet:

static final String JAXP_SCHEMA_LANGUAGE =

"http://java.sun.com/xml/jaxp/properties/schemaLanguage";

static final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";

try {

factory.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);

Adatkezelés

...

}

Különbség a SAX API-hoz képest, hogy ott magán a XML feldolgozón végeztük el a beállítást, míg a DOM API esetében ezt a gyáron végezzük.

In document Programozási technológiák – Jegyzet (Pldal 125-130)