1. Axın-parsinq ilə tanışlıq
Java-da XML ilə işləmək üçün tarixən iki yanaşma formalaşıb.
Artıq bilirik ki, DOM (Document Object Model) sənədin ağacını yaddaşda qurur. Elementlər arasında hərəkət etmək və onları redaktə etmək rahatdır, lakin böyük fayllar üçün bu çox baha başa gəlir: yaddaş tez tükənir.
Öz növbəsində SAX (Simple API for XML) faylı ardıcıl emal edir və teqlərə rast gələndə hadisələr yaradır. Bu, yaddaş baxımından qənaətcildir, nəhəng sənədlərlə işləmək olar. Amma emalçılar yazmaq narahatdır və struktura geri qayıtmaq mümkün deyil.
StAX (Streaming API for XML) kompromis kimi yarandı. O da SAX kimi axın əsaslıdır, amma proqramçıya daha çox nəzarət verir: biz hadisələri axından yalnız lazım olanda özümüz “çəkmək” üçün alırıq. Bu yanaşma pull-parsinq adlanır və daha anlaşılan, çevik kod yazmağa imkan verir.
StAX-a giriş
StAX (Streaming API for XML) — bu, Java üçün JDK 6+ ilə gəlmiş müasir axın XML parseridir.
Əsas fikir: pull-parsinq (“çəkmə” parseri).
SAX-dan fərqli olaraq, harada parser metodlarınızı özü çağırır (push-model), StAX-da prosesi özünüz idarə edirsiniz:
Siz parserdən: “Növbəti hadisəni ver!” istəyirsiniz
Bənzətmə:
SAX — televiziya kimidir: hadisələr sizə “axır”, siz reaksiya verməlisiniz.
StAX — siz hazır olanda “növbəti video”nu özünüz basdığınız xidmət kimidir.
StAX-ın əsas sinifləri
StAX ilə işləmək üçün javax.xml.stream paketindən iki əsas sinif lazımdır:
- XMLInputFactory — parserlər yaratmaq üçün fabrika.
- XMLStreamReader — XML-i “hissə-hissə” oxuyan axın-parser.
Əsas kod nümunəsi:
import javax.xml.stream.*;
import java.io.FileInputStream;
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader reader = factory.createXMLStreamReader(new FileInputStream("data.xml"));
while (reader.hasNext()) {
int event = reader.next();
// hadisənin işlənməsi
}
reader.close();
2. StAX-ın işi: pull-model
StAX-da siz XML oxunuşunu özünüz idarə edirsiniz:
- Axını açırsınız (məsələn, faylı).
- XMLStreamReader yaradırsınız.
- Növbəti hadisəni almaq üçün dövrədə reader.next() çağırırsınız.
- Hadisənin tipini yoxlayırsınız (START_ELEMENT, END_ELEMENT, CHARACTERS və s.).
- Lazımi yerə çatdıqda — məlumatı emal edirsiniz.
- Parseri bağlayırsınız.
İş sxemi:
flowchart TD
A[XMLStreamReader-i açmaq] --> B{hasNext?}
B -- bəli --> C["next()"]
C --> D{Hadisə tipi?}
D -- START_ELEMENT --> E[Element başlanğıcının emalı]
D -- CHARACTERS --> F[Mətnin emalı]
D -- END_ELEMENT --> G[Element sonunun emalı]
D -- END_DOCUMENT --> H[Bitir]
B -- xeyr --> H
Nə üçün rahatdır?
- Növbəti elementi nə vaxt oxumağa qərar verirsiniz.
- Lazım olan yerdə “dayanmaq”, faylın yalnız bir hissəsini emal etmək mümkündür.
- SAX-da olduğu kimi bir yığın emalçı yazmağa ehtiyac yoxdur.
3. StAX-da hadisə tipləri
reader.next() çağırdığınızda, parser hadisə tipini — tam ədəd (interfeys XMLStreamConstants-dan sabit) qaytarır. Əsas hadisə tipləri bunlardır:
- START_ELEMENT — XML elementinin başlanğıcı (<tag>).
- END_ELEMENT — XML elementinin sonu (</tag>).
- CHARACTERS — teqlər arasında mətn məzmunu.
- END_DOCUMENT — sənədin sonu.
Hadisələrin emalı nümunəsi:
while (reader.hasNext()) {
int event = reader.next();
switch (event) {
case XMLStreamConstants.START_ELEMENT:
String name = reader.getLocalName();
System.out.println("Elementin başlanğıcı: " + name);
break;
case XMLStreamConstants.CHARACTERS:
String text = reader.getText().trim();
if (!text.isEmpty()) {
System.out.println("Mətn: " + text);
}
break;
case XMLStreamConstants.END_ELEMENT:
System.out.println("Elementin sonu: " + reader.getLocalName());
break;
}
}
4. Faydalı nüanslar
StAX nə vaxt istifadə olunmalıdır?
StAX ideal seçimdir, əgər:
- XML fayl çox böyükdür (gigabaytlarla) və onu tam yaddaşa yükləmək istəmirsiniz.
- Sənədin yalnız bir hissəsini emal etmək lazımdır (məsələn, konkret elementi tapıb dayanmaq).
- Sadə və anlaşılan kod tələb olunur: StAX, SAX-dan daha sadədir və bir yığın emalçı yazmağı tələb etmir.
Vəzifə nümunələri:
- Böyük XML faylının importu (məsələn, 1C-dən ixrac, bank çıxarışları, məhsul kataloqları).
- Yalnız lazım olan elementlərin axtarışı və emalı (məsələn, milyonlarla yazı arasından yalnız <transaction>).
- XML-i yerindəcə çevirmə (məsələn, filtrləmə, aqreqasiya).
DOM, SAX və StAX müqayisəsi
| Yanaşma | Yaddaş | Sadəlik | Çeviklik | Nə vaxt istifadə etməli |
|---|---|---|---|---|
| DOM | Yüksək (hər şey yaddaşdadır) | Çox sadə | Ağacı dəyişmək olar | Kiçik/orta fayllar, XML-i redaktə etmək lazım olanda |
| SAX | Minimum | Mürəkkəb (hadisə emalçıları) | Yalnız oxuma, geri qayıtmaq olmur | Çox böyük fayllar, sadə emal |
| StAX | Minimum | Orta (pull-model) | Hissə-hissə oxumaq və rahat dayanmaq olur | Böyük fayllar, çeviklik və sadəlik lazım olanda |
StAX — qızıl orta:
— DOM kimi yaddaşı israf etmir.
— SAX kimi mürəkkəb emalçılar tələb etmir.
— Parsinq prosesini idarə etməyə imkan verir.
5. Nümunə: StAX ilə böyük XML faylını oxuma
Tutaq ki, bizdə "books.xml" faylı var:
<library>
<book>
<title>Java üçün yeni başlayanlar</title>
<author>Ivan Ivanov</author>
</book>
<book>
<title>Qabaqcıl Java</title>
<author>Pyotr Petrov</author>
</book>
<!-- ... çox kitab ... -->
</library>
Tapşırıq: bütün kitab adlarını çıxarmaq.
StAX kodu:
import javax.xml.stream.*;
import java.io.*;
public class StaxDemo {
public static void main(String[] args) throws Exception {
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader reader = factory.createXMLStreamReader(new FileInputStream("books.xml"));
while (reader.hasNext()) {
int event = reader.next();
if (event == XMLStreamConstants.START_ELEMENT && "title".equals(reader.getLocalName())) {
reader.next(); // CHARACTERS-ə keçirik
System.out.println("Kitab: " + reader.getText());
}
}
reader.close();
}
}
Üstünlüklər:
- Bütün faylı yaddaşa yükləmirik.
- Milyonlarla kitabı da emal etmək olar — proqram çökməyəcək.
6. StAX ilə işləyərkən tipik səhvlər
Səhv №1: parseri və ya axını bağlamağı unutdunuz. Həmişə XMLStreamReader-i və axını (InputStream) bağlayın ki, resurs sızmaları olmasın.
Səhv №2: hadisənin tipini yoxlamırsınız. Bütün hadisələr elementin başlanğıcı və ya sonu deyil. Hadisənin tipini yoxlayın, əks halda boş sətirlər ala və ya lazım olan məlumatı ötürə bilərsiniz.
Səhv №3: elementlərin iç-içəliyini nəzərə almırsınız. XML strukturu mürəkkəbdirsə (məsələn, bölmələrin içində kitablar), cari iç-içəlik səviyyəsinə nəzarət edin ki, elementləri qarışdırmayasınız.
Səhv №4: böyük fayllar üçün DOM istifadə edirsiniz. Fayl böyükdürsə — DOM istifadə etməyin, əks halda OutOfMemoryError ala bilərsiniz. Böyük fayllar üçün — yalnız StAX və ya SAX.
Səhv №5: istisnaları emal etmirsiniz. Fayllarla və XML ilə iş zamanı istisnalar ata bilər (XMLStreamException, IOException). Onları emal edin və ya yuxarı ötürün.
GO TO FULL VERSION