Delphi - XML adatkészlet konvertálása adatbázisba

forráskód letöltése
Az előző héten egy olyan komponenst készítettünk, amely egy adatkészletet el tudott menteni egy XML fájlba. Ilyen XML fájlokkal máshol is találkozhatunk, ezért most egy olyan komponenst készítünk, amely képes ezekből az XML-ben tárolt adatkészletekből egy adatbázis táblát előállítani. A mellékelt példaprogram megnyitása előtt az XmlToDb.pas-ban lévő komponenst telepítenie kell a Delphi alá.

Az XML fájl feldolgozásához szükségünk lesz a Microsoft XML Type Library-ra, tehát ha még korábban nem tettük volna meg, akkor most készítsük ezt el. Ehhez válasszuk a Project menü Import Type Library menüpontját, majd a listából az Microsoft XML elemet. Ezután kattintsunk a Create Unit gombra, aminek hatására létrejön az MSXML_TLB unit.

A komponensben létrehozunk néhány olyan property-t, ami majd az adatbázis tábla bizonyos tulajdonságait adja meg. A DatabaseName property az alias neve, ami alatt a táblát létre szeretnénk hozni. A TableName property a tábla neve. Ha nem adjuk meg a DatabaseName property-t, akkor ebben megadhatjuk a tábla teljes elérési útvonalát is. A TableType property-ben a szokásos adatbázis típusok közül választhatunk. Azt azonban figyelembe kell venni, hogy nem biztos, hogy az XML adatkészletben definiált mezőtípusok minden adatbázis típusnál használhatók.
Az XML fájl nevét a FileName property-ben lehet megadni, de ez nem kötelező, mert a feldolgozást végző Execute eljárásnak van egy olyan változata is, ahol paraméterként megadhatjuk a fájl nevét.

A feldolgozás tehát az Execute eljárásban történik. Ebben először ellenőrizzük, hogy a FileName paraméterben megadott fáj létezik-e. A fájlbetöltéséhez, és további feldolgozásához szükség lesz egy IXMLDOMDocument objektumra.
    XMLDoc:=CoDOMDocument.Create;
Ennek load függvényével megpróbáljuk betölteni a fájlt. A függvény visszatérési értéke igaz, ha ez sikerült, és hamis, ha nem.
    if XMLDoc.load(FileName) then ...
Egy XML fájlban sok mindent lehet tárolni, ezért ellenőrizzük, hogy a gyökér elem neve „DATAPACKET”-e, és csak akkor folytatjuk a feldolgozást, ha az. Az elem nevét a documentElement.tagName property-ből olvashatjuk ki:
      if CompareText('DATAPACKET', XMLDoc.documentElement.tagName)=0 then ...
Ha ez is rendben van, akkor létrehozunk egy TTable típusú objektumot.
        Table:=TTable.Create(self);

A DatabaseName, TableName és TableType property-knek azonnal értéket tudunk adni a komponens azonos nevű property-jeiből:
          Table.DatabaseName:=FDatabaseName;
          Table.TableName:=FTableName;
          Table.TableType:=FTableType;
A tábla létrehozásához a FieldDefs property-t is fel kell tölteni a mezők tulajdonságaival. Ezt végzi el a GetFieldDefs eljárás, aminek első paramétere az IXMLDOMDocument típusú objektum (XMLDoc), a második pedig a Table objektum FieldDefs objektuma.
          GetFieldDefs(XMLDoc, Table.FieldDefs);
A GetFieldDefs eljárásban megkeressük a FIELDS elemet a dokumentumban:
var
  FieldsNode: IXMLDOMNode;
...
  FieldsNode:=FindNode(XMLDoc.documentElement.firstChild, 'FIELDS');
 
Ha megtaláltuk, akkor egy ciklusban végigmegyünk az ebben található elemeken, amelyeket a childNodes property-n keresztül érünk el. Az elemek számát a childNodes.length property-ből tudjuk kiolvasni:
    i:=0;
    while i<FieldsNode.childNodes.length do ...
Ha az aktuális elem neve FIELD, akkor az egy meződefiníciót tartalmaz. A nevet a nodeName property-ből tudjuk kiolvasni.
var
  DefNode: IXMLDOMNode;
...
      DefNode:=FieldsNode.childNodes[i];
      if CompareText(DefNode.nodeName, 'FIELD')=0 then ...
A mezők tulajdonságai a FIELD elem attribútumaiban vannak meghatározva. Az attrname attribútum a mezők azonosítására szolgál, sok esetben ez egyben a mező neve is. A fieldname attribútum a mező nevét tartalmazza, de ha ez nincs megadva, akkor a mező neve az attrname attribútum értéke.
Egy attribútum értékének kiolvasására létrehoztuk a GetAttrValue függvényt. Ez egy ciklusban végignézi az elem attribútumait, melyek az attributes objektumon keresztül érhetők el. Ha az attribútum neve megegyezik a paraméterként megadott névvel, akkor az attribútum értékével tér vissza.
A mező típusának meghatározásához szintén egy külön függvény, a GetFieldType szükséges, mivel ez egy eléggé összetett feladat. A mező típusa elsősorban a fieldtype attribútum értékétől függ, de lehetnek még kiegészítő attribútumok is, amelyek ezt befolyásolják, illetve további tulajdonságokat is meghatároznak, mint például a sztring típusnál a mező hossza.
A mezők tulajdonságainak beolvasása után következik a kulcsmezők meghatározása. Ezek a PARAMS elemben vannak felsorolva a PRIMARY_KEY attribútumban, sorszám szerint, szóközzel elválasztva. Ha például az első két mező kulcsmező, akkor az attribútum értéke „1 2”. A tábla IndexDefs property-jét ennek megfelelően állítjuk be. Ezután a CreateTable metódussal létrehozzuk a táblát, majd a GetRecords eljárással feltöltjük a rekordokkal.
A rekordok a ROWDATA elemen belül találhatók meg. Minden rekordhoz egy-egy ROW elem tartozik. A ROW elem attribútumainak neve a FIELD elemekben megadott attrname attribútumok értékei, az értékek pedig a hozzájuk tartozó mezők értékei. A GetRecords eljárás végigmegy az összes ROW elemen, majd az attribútumok értékeit sorban beírja a megfelelő mezőkbe. Minden ROW elemhez létrehoz egy új rekordot a táblában, majd miután beírta a mezők értékeit, a Post eljárással véglegesíti azokat.
A feldolgozás során több hiba is előfordulhat, ezekhez külön eseményeket hozunk létre. Az Execute eljárás végén ellenőrizzük az ErrC változó értékét, és az ennek megfelelő eseménykezelő eljárást hívjuk meg.