12. gyakorlat¶
XML technológiák¶
Standard Generalized Markup Language (SGML)¶
Az SGML egy általános jelölő nyelv, amelyet ISO szabvány definiál. A célja, hogy egy adott szintaktikának megfelelő dokumentumot könnyen lehessen kezelni. Az SGML konkrét alkalmazása a HTML, de az XML is az SGML részhalmaza. Az SGML bonyolult, ezért széles körben nem is terjedt el, ezért ezzel külön nem is foglalkozunk, csak az XML-lel.
Extensible Markup Language (XML)¶
Az 1. gyakorlaton már megismerkedtünk az XML-lel, és a félév során már a gyakorlati alkalmazását is láttuk, mert a maven projekt fájl (pom.xml
), illetve a webes résznél a konfigurációs fájl (web.xml
) is XML volt. Azonban ezek inkább a gyakorlatban történő alkalmazhatóságra példák, és nem arra, hogy magát az XML-t hogyan kell felépíteni, mit lehet és mit nem lehet használni, illetve hogyan kell validálni azt. A következőkben az XML technológiákkal fogunk megismerkedni, amihez az alábbi példát fogjuk használni.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
Document Type Definition (DTD)¶
A DTD szabályok halmaza, amely SGML típusú nyelvekhez határoz meg dokumentumtípust. A DTD meghatározza, hogy
- milyen elemek lehetnek a dokumentumban,
- az elemek hogyan kapcsolódhatnak egymáshoz,
- milyen tartalmuk lehet,
- milyen tulajdonságuk lehet.
Fontos, hogy a DTD-ben minden olyan elemet definiálni kell, ami az XML-ben előfordul!
A DTD-t kétféleképpen lehet megadni:
- Belső, amikor a DTD ugyanabban a fájlban van, mint amire vonatkozik.
- Külső, amikor a DTD egy külön fájlban van, és csak egy hivatkozást tartalmaz a dokumentum a DTD-re.
A DTD felépítésénél definiáljuk az XML fa szerkezetét, amihez első lépésben a fa gyökerét adjuk meg. A jelentkezés xml esetében a fa gyökere a jelentkezés, amit a következő módon definiálunk.
1 2 3 4 |
|
Egy konkrét XML-hez nagyon sokféle validációs szabályt definiálhatunk, mert nem tudhatjuk, hogy mi kötelező és mi nem, melyik elemből mennyi a minimum és maximum, melyik elemre milyen megkötések vannak, stb. Mi most egyet fogunk megadni, ami logikusan következik az XML-ből, illetve bemutatja a DTD lehetőségeit is.
A jelentkezes
elemnek van egy attribútuma (id
) és két gyereke, a hallgato
és a kurzusok
. Ezt az ELEMENT
és ATTLIST
segítségével adhatjuk meg.
1 2 3 4 5 |
|
Az idoszak
típusát is megadtuk, ez tetszőleges szöveg (CDATA
) lehet, (amit a feldolgozó nem is fogja feldolgozni), illetve definiáltuk, hogy kötelező megadni (#REQUIRED
).
Attribútum¶
Az attribútum fontosabb lehetséges típusa:
CDATA
- szöveges adatID
- egyedi azonosító, azaz egy azonosító nem fordulhat elő kétszer (pl. akurzus
id
-ja)- Felsorolás, amikor definiáljuk, hogy pontosan milyen értékeket vehet fel (pl. a
kurzus
esetében ajovahagyas
) ENTITY
ésENTITIES
- külső hivatkozás megadása (később lesz rá példa)IDREF
ésIDREFS
- egy vagy több másik elemre történő hivatkozásNMTOKEN
ésNMTOKENS
- Valid XML név
Az attribútum követelmények a következők lehetnek:
-
#REQUIRED
- kötelező megadni, például a jelentkezési időszakot vagy a hallgatónak az egyedi azonosítóját1 2
<!ATTLIST jelentkezes idoszak CDATA #REQUIRED> <!ATTLIST kurzus id ID #REQUIRED>
-
#FIXED
- kötelező megadni, de csak egy fix értéket vehet fel, ami példa lehet, hogy az egyetem csak az SZTE lehet1
<!ATTLIST jelentkezes egyetem CDATA #FIXED "SZTE">
-
#IMPLIED
- opcionális, azaz megadhatjuk, de nem kötelező, például a nyelv a kurzusoknál1
<!ATTLIST kurzus nyelv CDATA #IMPLIED>
-
felsorolás - megadhatjuk, hogy milyen értékeket vehet fel, mint például a jóváhagyásos kurzusoknál, de megadhatunk alapértelmezett értéket is, hogy ne kelljen minden nem jóváhagyásoshoz kiírni a "nem"-et
1
<!ATTLIST kurzus jovahagyas (igen | nem) "nem">
Elem¶
Az elemek esetében megadhatjuk, hogy mi legyen a tartalmuk:
EMPTY
- üres, az elemnek nem lehet tartalma (pl. HTML esetében a<br />
)
ANY
- tetszőleges tartalmat megadhatunk, amit az XML megenged
#PCDATA
- parsed data, azaz olyan adattartalom, amit az XML-parser feldolgoz
- Gyerek elemek - további XML elemek
-
Ezek kombinációja, amikor többféle tartalmat is megadhatunk, pl. a hallgató esetében
1
<!ELEMENT hallgato (hnev, szuletesnap, szak)>
A gyerek elemek esetében azt is megadhatjuk, hogy hányszor forduljanak elő:
-
Szekvencia: ha vesszővel elválasztva adjuk mega, akkor minden elemnek léteznie kell
1
<!ELEMENT hallgato (hnev, szuletesnap, szak)>
-
Ha több elem közül kell választani egyet, akkor a | jellel adhatjuk meg, pl.
tanar
vagyoratarto
1
<!ELEMENT kurzus (... (tanar|oratarto) )>
-
Ismétlődés operátorok
- Nincs - pontosan egyszer kell előfordulnia
- ? - egyszer vagy egyszer sem, pl. lehet, hogy még nem ismert a kurzus időpontja
- + - legalább egyszer szerepelnie kell, pl. a hallgatónak legalább egy szakja van
-
* - akárhányszor szerepelhet (akár el is lehet hagyni), pl. tetszőleges kurzust felvehet
1 2 3
<!ELEMENT hallgato (hnev, szuletesnap, szak+)> <!ELEMENT kurzusok (kurzus*)> <!ELEMENT kurzus (nev, kredit, hely, idopont?, (tanar|oratarto)+ )>
Teljes példa¶
Ezen építőelemek felhasználva a jelentkezes.xml
-hez tartozó egy lehetséges DTD a következő:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
Hivatkozások¶
Külső hivatkozások¶
Az első külső hivatkozás maga a DTD lehet. Megtehetjük, hogy a fenti DTD-t bemásoljuk az XML elejére, de ez nem célszerű, mert így minden XML tartalmazza a DTD-t, ami nagyobb méretű lesz, a DTD redundánsan szerepel az összes XML-ben, illetve, ha módosítjuk a DTD-t, akkor minden XML-ben ki kell cserélni. Ezért célszerű külső hivatkozásként megadni a DTD-t, és ilyenkor az XML elejére csak a hivatkozást kell beszúrni.
1 |
|
De nem csak a DTD-re lehet külső hivatkozást definiálni, hanem ,,bármire''. Például a kurzusok
vagy a kurzus
esetében is meg lehet adni, hogy valami külső fájlra vagy egy web címre hivatkozzon.
1 2 |
|
Belső hivatkozások¶
A DTD lehetőséget biztosít változó definíciókra is, és ezekre a változókra később hivatkozhatunk is. Például ha az SZTE-t nem akarjuk mindenhova kiírni, helyette felveszünk egy változót, annak értékül adjuk, és ha valamiért változik az egyetem neve, akkor csak egy helyen kell módosítani. A korábbi példa kapcsolódó része (valid XML-lé alakítva):
1 2 3 4 5 6 7 8 |
|
Hivatkozások használatának veszélyei¶
Használjuk vagy ne használjuk a ne használjuk a hivatkozásokat? Láthatjuk, hogy számos előnyük van:
- csak egy helyen szerepel a DTD,
- csak egy helyen adok értéket a változónak, és aztán használom.
Szóval akkor használjuk, mi baj történhet?
DTD változók¶
Tegyük fel, hogy van egy alkalmazásunk, ami egy webszerveren fut, és valami inputot várunk XML formátumban. Elővigyázatosak vagyunk, és hogy védjük a szervert (tárhely, memória, processzor kapacitás), lekorlátozzuk a feltöltendő fájlok méretét. Ekkor megnyugodhatunk, mi baj történhet, ,,mindenre'' gondolunk.
Vagy mégsem? Mi van akkor, ha az egyik ,,barátunk'' meglep minket a következő XML-lel?
1 2 3 4 5 6 7 8 9 10 |
|
Mi fog történni ekkor? Az XML feldolgozó elvégzi a dolgát, és előállítja az XML-t, amihez ki kell számolnia m
-et, amihez előbb l
-re is szüksége van, ... De mekkora lesz m
?
a
10 bájtosb
8-szor tartalmazzaa
-t, azaz 10 * 8 = 80 bájtc
8-szor tartalmazzab
-t, azaz 10 * 8 * 8 = 10 * 82 = 640 bájtd
8-szor tartalmazzac
-t, azaz 10 * 83 = 5 KBe
8-szor tartalmazzad
-t, azaz 10 * 84 = 40 KB- ...
m
8-sor tartalmazzad
-t, azaz 10 * 812 = 640 GB!!!
Azaz a fenti ,,ártatlannak tűnő'' XML feldolgozásához 640GB memóriára van szükség.
XML External Entity (XXE) sebezhetőség¶
A külső hivatkozások hasznosak, de azokat is fenntartásokkal kell kezelni. Például, ha valami külső hivatkozás tartalmát a felhasználó láthatja, akkor esetleg olyan információhoz is hozzájuthat, amihez nincs jogosultsága. De ki lenne ilyen amatőr, hogy ezt megengedi, és vajon mihez férhet hozzá? Nos, egy valós példa erre, hogy korábban a google toolbart testre lehetett szabni XML segítségével. Ez egy hasznos funkció volt, csak nem (vagy nem megfelelően) validálták az XML-t, így ha valaki a szerveren található /etc/passwd
vagy az /etc/hosts
fájlok tartalmával akarta kiegészíteni a toolbarját, akkor megtehette
- https://blog.detectify.com/2014/04/11/how-we-got-read-access-on-googles-production-servers/
- https://news.softpedia.com/news/Google-Rewards-Experts-for-XXE-Vulnerability-in-Toolbar-Button-Gallery-437290.shtml
XML Schema Definition (XSD)¶
Annak ellenére, hogy a DTD-vel is definiálthatjuk az XML formátumát, van néhány hátránya, amiért inkább az XSD-t érdemes használni. Anélkül, hogy ismernénk az XSD-t, a DTD-vel kapcsolatban lehetett néhol hiányérzetünk, ezért most előre összefoglaljuk a fontosabb különbségeket, illetve az XSD előnyeit a DTD-vel szemben:
- Az XSD XML alapú, míg a DTD nem, azaz a DTD-hez meg kell tanulni egy újabb szintaxist (ami azért nem annyira bonyolult ).
- Az XSD sokféle típust definiál (szám, dátum, ...), míg a DTD alapból ezt nem támogatja.
- Ezért nem tudtunk a születési évnek dátum típus megkövetelni, vagy a kredit számnak nemnegatív egész értéket.
- Az XSD-vel definiálhatjuk a gyerek elemek számát és sorrendjét, míg a DTD ezt nem támogatja.
- Az XML-ben használhatunk névtereket, és az XSD támogatja ezt.
- Azért a DTD mellett szól például, hogy definiálhatunk
ENTITY
-t, amit az XSD nem támogat.
XSD Bevezető¶
Az XSD XML alapon definiálja, hogy az adott XML hogyan nézhet ki, azaz
- milyen elemek és attribútumok fordulhatnak elő,
- mennyi gyerek elem és milyen sorrendben fordulhat elő,
- az elemek és attribútumok típusait,
- és az elemek és attribútumok fix értékeit.
Az XSD megadása egy XML fájllal történik, ahol az XSD nyelvtanban definiált elemeket használhatjuk.
A gyökérben megadjuk, hogy az XSD névteret használjuk, és ezen elemeket az xs
prefixszel fogjuk használni.
1 2 3 4 |
|
Az XSD-ben megtalálhatóak azok az alaptípusok, amelyek a legtöbb nyelvben léteznek, például:
- szöveg: string
- szám: integer, long, short, byte, ..., float, double, ...
- dátum: date, time, ...
- egyéb: boolean
Element¶
Egy XML elemet az XSD-ben az element
segítségével adhatunk meg, ahol meg kell adni a nevét és azt, hogy mi lehet a tartalma. Az element
lehet egyszerű, amikor egy XSD a típusa, de lehet összetett is, amikor mi írjuk le, hogy mit tartalmazhat.
Például a kredit
vagy a tanár
esetében, amikor egyszerű elemnek tekintjük:
1 2 |
|
Komplex elemet complexType
segítségével definiálhatunk, ahol meg kell adnunk azt is, hogy
- milyen elemeket tartalmazzon,
- melyikből mennyit tartalmazzon,
- és hogy számít-e a sorrendjük van sem.
Összetett elem¶
Ha olyan összetett elemet szeretnénk definiálni, ahol az összes gyereknek elő kell fordulnia, de a sorrend tetszőleges lehet, akkor az all
-t kell használni. Például a kurzusnak lehet neve, kreditje, helye, ... (a tanár vagy óratartó választást most még nem vesszük figyelembe).
1 2 3 4 5 6 7 8 9 10 11 |
|
Ha az elemek sorrendje is fontos, akkor a sequence
-t kell használni:
1 2 3 4 5 6 7 8 9 10 11 |
|
Azt is megtehetjük, hogy az elemek közül választunk (choice
), például, ha a kurzusnak tanára vagy óratartója van, és ilyenkor vagy az egyiket, vagy a másikat kell megadni:
1 2 3 4 5 6 7 8 |
|
Számosság megadása¶
Lehetőségünk van azt is megadni, hogy egy elem hányszor forduljon, illetve összesen hány elem lehet. Ezekre a minOccurs
és maxOccurs
attribútumokat használhatjuk.
Például ha a kurzus esetében az időpont opcionális, azaz nem kötelező, akkor a minOccurs
értékét 0-ra kell állítani, és így elhagyható lesz. Továbbá ha legfeljebb 5 tanára lehet (most tekintsünk el a tanár vagy oktató megközelítéstől) a kurzusnak, akkor azt a következő módon lehet megadni:
1 2 3 4 5 6 7 8 9 10 11 |
|
A minOccurs
értéke 0 vagy 1 lehet, a maxOccurs
tetszőleges egész. Mindkettőnek az alapértelmezett értéke 1, azaz minden gyerek elemnek egyszer kell szerepelnie, ha ezt nem specifikáljuk másképp.
Referencia másik elemre¶
Mivel az XML-ben elég mély egymásba ágyazási hierarchia alakulhat ki, azért az XSD is elég bonyolult és mély lehet, ezért célszerű bizonyos részeket kiszervezni, és azokra csak hivatkozásokat megadni. Ilyen lehet, hogy a jelentkezes
-t két nagyobb részre bontjuk, a hallgato
-ra és a kurzusok
-ra.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Attribútum¶
Az attribútumokat az attribute
segítségével adhatjuk meg, ahol meg kell adni az attribútum nevét, a típusát, és hogy kötelező (required
) vagy opcionális (optional
), és esetleg van-e alapértelmezett értéke.
Néhány példa az attribútumokra, ahol az evf
vagy az id
megadása kötelező, a nyelv
opcionális, mint ahogy a jovahagyas
is, de ott még alapértelemezett értéket is megadunk.
1 2 3 4 |
|
Ha egy elemnek van attribútuma, akkor az már nem lehet egyszerű elem, hiába nincs további gyereke. Például a szak
esetében csak a szakot kell megadni szöveggel, de van egy evf
attribútuma is.
1 2 3 4 5 6 7 8 9 |
|
Vagy például a kurzus
attribútumainak megadása a következő lehet:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Saját típus, megszorítások¶
Eddig csak a beépített típusokat használtuk, azonban lehetőségünk van megszorításokat is alkalmazni a típusokra, illetve új típusokat is definiálhatunk, amit később felhasználhatunk. Egy logikus megszorítás, hogy a kredit értéknek legyen minimum és maximum értéke. így a korábbi
1 |
|
helyett megadjuk, hogy továbbra is egész szám, de a megszorításokat is definiáljuk:
1 2 3 4 5 6 7 8 |
|
Saját típus definiálásánál meg kell adni a típus nevét, valamint azt, hogy mit reprezentáljon. Például a hallgatók és a kurzusok azonosítóinak olyan string azonosítókat fogadunk el, amelyek legalább 5 és legfeljebb 10 hosszúak.
1 2 3 4 5 6 |
|
Ha a jóváhagyáshoz szeretnénk egy típust definiálni, ami csak igen vagy nem lehet, akkor az string típus lesz, és megadott értékeket vehet fel.
1 2 3 4 5 6 |
|
De lehetőség van minta alapján is megszorítást definiálni. Ilyen lehet például az, hogy melyik időszakra vonatkozik, ahol a mintának az eleje az évszám/évszám
, majd ezt követi egy vagy két I
. Ez a minta nem fogja ellenőrizni, hogy az évszám jó-e, de legalább ilyen formátumban kapjuk meg.
1 2 3 4 5 |
|
Teljes XML¶
Ezen építőelemek felhasználásával egy lehetséges XSD a jelentkezes.xml példához a következő:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
|
XML gyökere¶
A fenti XSD esetében egyértelműnek tűnik, hogy a jelentkezes
-t várjuk el az XML gyökerének, de ez nem így van, mert egy olyan XML is valid, aminek a hallgató a gyökere, és csak azt a részt valósítja meg.
1 2 3 4 5 6 7 |
|
Hasznos linkek¶
- XML online validálása: https://www.xmlvalidation.com/index.php?id=1&L=0
- DTD: https://www.w3schools.com/xml/xml_dtd_intro.asp
- XSD: https://www.w3schools.com/xml/schema_intro.asp