JavaRush /Java blogi /Random-UZ /Java dasturchisi uchun XML asoslari - 3-qismning 3.1-qism...
Ярослав
Daraja
Днепр

Java dasturchisi uchun XML asoslari - 3-qismning 3.1-qismi - SAX

Guruhda nashr etilgan
Kirish Hali so'nggi bo'lmagan maqolamning barcha o'quvchilariga salom va men sizni tabriklamoqchiman: XML haqidagi murakkab narsalar ortda qoldi. Ushbu maqola Java-da kodni o'z ichiga oladi. Bir oz nazariya bo'ladi, keyin esa amaliyot. SAX-dagi bitta material Word-da 10 sahifani to'ldirganligi sababli, men chegaralarga sig'a olmasligimni angladim. Shuning uchun, 3-modda, qanchalik g'alati tuyulmasin, 3 ta alohida maqolaga bo'linadi. Hammasi shu tartibda bo'ladi: SAX -> DOM -> JAXB. Ushbu maqola faqat SAXga qaratilgan. PS Kursning biron bir joyida HTML faylidagi barcha ichki elementlarni ko'rsatish kerak bo'lgan vazifa bor edi. Ushbu maqoladan so'ng, siz buni oddiy va murakkab ishlov berish algoritmlari bilan satr-satr o'qimasdan qilishingiz mumkin BufferedReader, shuningdek, shunga o'xshash yechim oxirgi amaliy misolda keltirilgan. Keling, boshlaymiz :) SAX (Simple API for XML) - NAZARIYA SAX ishlov beruvchisi shunday tuzilganki, u oddiygina XML fayllarni ketma-ket o'qiydi va turli hodisalarga reaksiyaga kirishadi, shundan so'ng u ma'lumotlarni maxsus hodisa ishlov beruvchisiga uzatadi. Unda juda ko'p voqealar mavjud, ammo eng tez-tez uchraydigan va foydalilari quyidagilar:
  1. startDocument— hujjatning boshi
  2. endDocument- hujjatning oxiri
  3. startElement- elementni ochish
  4. endElement- elementni yopish
  5. characters— elementlar ichidagi matn ma'lumotlari.
Barcha hodisalar voqea ishlov beruvchisida qayta ishlanadi , ular yaratilishi va usullar bekor qilinishi kerak . Afzalliklari: ma'lumotlarni o'qishning "to'g'ridan-to'g'ri" usuli tufayli yuqori ishlash, past xotira xarajatlari. Kamchiliklari: cheklangan funksionallik, ya'ni chiziqli bo'lmagan masalalarda biz uni takomillashtirishga to'g'ri keladi. SAX (XML uchun oddiy API) - PRACTICE Hech narsani qidirmaslik va chalkashtirmaslik uchun darhol importlar ro'yxati:
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
Endi, birinchi navbatda, biz SAXParser yaratishimiz kerak:
public class SAXExample {
    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
        // Creation фабрики и образца parserа
        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser parser = factory.newSAXParser();
    }
}
Ko'rib turganingizdek, siz avval zavod yaratishingiz kerak, keyin esa zavodda parserni o'zi yaratishingiz kerak. Endi bizda parserning o'zi bor, biz uning hodisalari uchun ishlov beruvchiga muhtojmiz. Buning uchun bizga qulaylik uchun alohida sinf kerak:
public class SAXExample {
    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser parser = factory.newSAXParser();
    }

    private static class XMLHandler extends DefaultHandler {
        @Override
        public void startDocument() throws SAXException {
            // Тут будет логика реакции на начало documentа
        }

        @Override
        public void endDocument() throws SAXException {
            // Тут будет логика реакции на конец documentа
        }

        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
            // Тут будет логика реакции на начало element
        }

        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            // Тут будет логика реакции на конец element
        }

        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
            // Тут будет логика реакции на текст между elementми
        }

        @Override
        public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
            // Тут будет логика реакции на пустое пространство внутри элементов (пробелы, переносы строчек и так далее).
        }
    }
}
Biz nazariyada sanab o'tilgan voqealarni boshqarish uchun zarur bo'lgan barcha usullar bilan sinf yaratdik. Yana bir oz qo'shimcha nazariya: Haqida bir oz characters: agar elementda matn bo'lsa, masalan, " salom " bo'lsa, nazariy jihatdan usulni har bir alohida belgi uchun ketma-ket 5 marta chaqirish mumkin, ammo bu unchalik muhim emas, chunki hamma narsa hali ham ishlaydi. va usullari haqida :startElementendElementuri - bu element joylashgan bo'shliq, localName- bu prefikssiz elementning nomi, qName- bu prefiksli elementning nomi (agar mavjud bo'lsa, aks holda faqat nomi). elementdan). uriva localNameagar biz zavodda bo'sh joyni qayta ishlashni yoqmagan bo'lsak, har doim bo'sh. Bu zavod usuli yordamida amalga oshiriladi setNamespaceAware(true). uriKeyin bo'sh joy ( ) va ularning oldida prefiksli elementlarni olishimiz mumkin ( localName). Vazifa №1 - Bizda quyidagi XML mavjud
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<company>
    <name>IT-Heaven</name>
    <offices>
        <office floor="1" room="1">
            <employees>
                <employee name="Maksim" job="Middle Software Developer" />
                <employee name="Ivan" job="Junior Software Developer" />
                <employee name="Franklin" job="Junior Software Developer" />
            </employees>
        </office>
        <office floor="1" room="2">
            <employees>
                <employee name="Herald" job="Middle Software Developer" />
                <employee name="Adam" job="Middle Software Developer" />
                <employee name="Leroy" job="Junior Software Developer" />
            </employees>
        </office>
    </offices>
</company>
Bizning maqsadimiz: ushbu fayldan barcha xodimlar haqida barcha ma'lumotlarni olish. Birinchidan, biz sinf yaratishimiz kerakEmployee:
public class Employee {
    private String name, job;

    public Employee(String name, String job) {
        this.name = name;
        this.job = job;
    }

    public String getName() {
        return name;
    }

    public String getJob() {
        return job;
    }
}
Va bizning asosiy sinfimizda SAXExamplebarcha xodimlar ro'yxati kerak:
private static ArrayList<Employee> employees = new ArrayList<>();
Endi XML faylida bizga kerak bo'lgan ma'lumotlar qayerda ekanligini diqqat bilan ko'rib chiqamiz. Va, biz ko'rib turganimizdek, bizga kerak bo'lgan barcha ma'lumotlar elementlarning atributlari employee. Va startElementbizda bunday foydali parametr borligi sababli attributes, bizda juda oddiy vazifa bor. Birinchidan, kodimizni chalkashtirib yubormaslik uchun keraksiz usullarni olib tashlaymiz. Bizga faqat kerak startElement. Va usulning o'zida biz xodim yorlig'ining atributlaridan ma'lumot to'plashimiz kerak. Diqqat:
public class SAXExample {
    private static ArrayList<Employee> employees = new ArrayList<>();

    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser parser = factory.newSAXParser();
    }

    private static class XMLHandler extends DefaultHandler {
        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
            if (qName.equals("employee")) {
                String name = attributes.getValue("name");
                String job = attributes.getValue("job");
                employees.add(new Employee(name, job));
            }
        }
    }
}
Mantiq oddiy: agar element nomi bo'lsa employee, biz shunchaki uning atributlari haqida ma'lumot olamiz. Foydali usul mavjud attributes, bunda atribut nomini bilib, uning qiymatini olishingiz mumkin. Biz ishlatgan narsamiz. Endi biz elementning boshlanishi uchun hodisa ishlov beruvchisini yaratdik, biz XML faylimizni tahlil qilishimiz kerak . Buni amalga oshirish uchun buni bajaring:
public class SAXExample {
    private static ArrayList<Employee> employees = new ArrayList<>();

    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser parser = factory.newSAXParser();

        XMLHandler handler = new XMLHandler();
        parser.parse(new File("resource/xml_file1.xml"), handler);

        for (Employee employee : employees)
            System.out.println(String.format("Name сотрудника: %s, его должность: %s", employee.getName(), employee.getJob()));
    }

    private static class XMLHandler extends DefaultHandler {
        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
            if (qName.equals("employee")) {
                String name = attributes.getValue("name");
                String job = attributes.getValue("job");
                employees.add(new Employee(name, job));
            }
        }
    }
}
Tahlil qilish usulida siz xml fayli va siz yaratgan ishlov beruvchiga yo'lni o'tkazishingiz kerak. Shunday qilib, ushbu koddan foydalanib, biz ushbu XML dan ma'lumot oldik:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<company>
    <name>IT-Heaven</name>
    <offices>
        <office floor="1" room="1">
            <employees>
                <employee name="Maksim" job="Middle Software Developer" />
                <employee name="Ivan" job="Junior Software Developer" />
                <employee name="Franklin" job="Junior Software Developer" />
            </employees>
        </office>
        <office floor="1" room="2">
            <employees>
                <employee name="Herald" job="Middle Software Developer" />
                <employee name="Adam" job="Middle Software Developer" />
                <employee name="Leroy" job="Junior Software Developer" />
            </employees>
        </office>
    </offices>
</company>
Va biz quyidagi natijani oldik:
Name сотрудника: Maksim, его должность: Middle Software Developer
Name сотрудника: Ivan, его должность: Junior Software Developer
Name сотрудника: Franklin, его должность: Junior Software Developer
Name сотрудника: Herald, его должность: Middle Software Developer
Name сотрудника: Adam, его должность: Middle Software Developer
Name сотрудника: Leroy, его должность: Junior Software Developer
Missiya amalga oshirildi! Vazifa №2 - bizda quyidagi XML mavjud:
<?xml version="1.0" encoding="UTF-8"?>
<company>
    <name>IT-Heaven</name>
    <offices>
        <office floor="1" room="1">
            <employees>
                <employee>
                    <name>Maksim</name>
                    <job>Middle Software Developer</job>
                </employee>
                <employee>
                    <name>Ivan</name>
                    <job>Junior Software Developer</job>
                </employee>
                <employee>
                    <name>Franklin</name>
                    <job>Junior Software Developer</job>
                </employee>
            </employees>
        </office>
        <office floor="1" room="2">
            <employees>
                <employee>
                    <name>Herald</name>
                    <job>Middle Software Developer</job>
                </employee>
                <employee>
                    <name>Adam</name>
                    <job>Middle Software Developer</job>
                </employee>
                <employee>
                    <name>Leroy</name>
                    <job>Junior Software Developer</job>
                </employee>
            </employees>
        </office>
    </offices>
</company>
Bizning maqsadimiz: ushbu fayldan barcha xodimlar haqida barcha ma'lumotlarni olish. Bu muammo noto'g'ri tuzilgan XML fayli kod yozishni qanday qiyinlashtirishi mumkinligini yaxshi ko'rsatib beradi. Ko'rib turganingizdek, ism va joylashuv haqidagi ma'lumotlar endi nameva elementlari ichida matn ma'lumoti sifatida saqlanadi job. Elementlar ichidagi matnni o'qish uchun bizda belgilar usuli mavjud. Buning uchun biz mantiqiy takomillashtirilgan yangi ishlov beruvchi sinfini yaratishimiz kerak. Shuni unutmangki, ishlov beruvchilar har qanday murakkablikdagi mantiqni saqlashga qodir bo'lgan to'liq huquqli sinflardir. Shuning uchun, endi biz protsessorimizni sozlaymiz. Aslida, shuni ta'kidlash kifoyaki, biz har doim navbatma-navbat nameturamiz jobva qanday tartibda bo'lishimiz muhim emas, biz osongina ism va kasbni alohida o'zgaruvchilarga saqlashimiz mumkin va ikkala o'zgaruvchi ham saqlanganida, bizning xodimimizni yaratamiz. Faqat bu erda, elementning boshlanishi bilan bir qatorda, bizda element ichidagi matn uchun parametr yo'q. Biz matnda usullardan foydalanishimiz kerak. Ammo, agar ular butunlay boshqacha usullar bo'lsa, biz qanday qilib element ichidagi matn ma'lumotlarini olamiz? Mening yechimim: biz faqat oxirgi elementning nomini eslab qolishimiz va charactersma'lumotni qaysi elementda o'qiyotganimizni tekshirishimiz kerak. Shuni ham yodda tutish kerakki, <codee>belgilar elementlar ichidagi barcha belgilarni o'qiydi, ya'ni barcha bo'shliqlar va hatto satr tanaffuslari o'qiladi. Va bizga ularga kerak emas. Biz bu maʼlumotlarni eʼtiborsiz qoldirishimiz kerak, chunki u notoʻgʻri.</codee> Kod:
public class SAXExample {
    private static ArrayList<Employee> employees = new ArrayList<>();

    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser parser = factory.newSAXParser();

        AdvancedXMLHandler handler = new AdvancedXMLHandler();
        parser.parse(new File("resource/xml_file2.xml"), handler);

        for (Employee employee : employees)
            System.out.println(String.format("Name сотрудника: %s, его должность: %s", employee.getName(), employee.getJob()));
    }

    private static class AdvancedXMLHandler extends DefaultHandler {
        private String name, job, lastElementName;

        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
            lastElementName = qName;
        }

        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
            String information = new String(ch, start, length);

            information = information.replace("\n", "").trim();

            if (!information.isEmpty()) {
                if (lastElementName.equals("name"))
                    name = information;
                if (lastElementName.equals("job"))
                    job = information;
            }
        }

        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            if ( (name != null && !name.isEmpty()) && (job != null && !job.isEmpty()) ) {
                employees.add(new Employee(name, job));
                name = null;
                job = null;
            }
        }
    }
}
Ko'rib turganingizdek, XML fayl tuzilishining oddiy murakkabligi tufayli bizning kodimiz sezilarli darajada murakkablashdi. Biroq, kod murakkab emas. Tavsif: biz xodim ( name, job) haqidagi ma'lumotlarni saqlash uchun o'zgaruvchilarni , shuningdek, lastElementNameqaysi element ichida ekanligimizni yozib olish uchun o'zgaruvchini yaratdik. Shundan so'ng, usulda charactersbiz ma'lumotni filtrlaymiz va agar u erda hali ham ma'lumot mavjud bo'lsa, bu bizga kerak bo'lgan matn ekanligini anglatadi va keyin bu ism yoki kasb ekanligini aniqlaymiz lastElementName. Usulda endElementbiz barcha ma'lumotlar o'qilganligini tekshiramiz va agar shunday bo'lsa, biz xodimni yaratamiz va ma'lumotni qayta tiklaymiz. Yechimning chiqishi birinchi misolga teng:
Name сотрудника: Maksim, его должность: Middle Software Developer
Name сотрудника: Ivan, его должность: Junior Software Developer
Name сотрудника: Franklin, его должность: Junior Software Developer
Name сотрудника: Herald, его должность: Middle Software Developer
Name сотрудника: Adam, его должность: Middle Software Developer
Name сотрудника: Leroy, его должность: Junior Software Developer
Shunday qilib, bu muammo hal qilindi , lekin siz murakkabligi yuqori ekanligini sezishingiz mumkin. Shunday qilib, matn ma'lumotlarini atributlarda saqlash ko'pincha alohida elementlarga qaraganda to'g'riroq bo'ladi degan xulosaga kelishimiz mumkin. Va yana bir shirin vazifa, JavaRush-da HTML-da element haqidagi ma'lumotni ko'rsatish bo'yicha muammoni qisman hal qiladi, faqat uni biroz tahrirlash kerak bo'ladi, bu erda biz shunchaki element ichidagi barcha elementlarni sanab o'tamiz :) Vazifa №3 - element elementi berilgan bo'lsa, barcha ichki elementlarning nomlari va atributlarini ko'rsating; agar element topilmasa, buni ko'rsating. Ushbu vazifani bajarish uchun biz quyidagi XML faylidan foydalanamiz:
<?xml version="1.0" encoding="UTF-8"?>
<root>
    <oracle>
        <connection value="jdbc:oracle:thin:@10.220.140.48:1521:test1" />
        <user value="secretOracleUsername" />
        <password value="111" />
    </oracle>

    <mysql>
        <connection value="jdbc:mysql:thin:@10.220.140.48:1521:test1" />
        <user value="secretMySQLUsername" />
        <password value="222" />
    </mysql>
</root>
Ko'rib turganingizdek, bizda uchta mumkin bo'lgan stsenariy mavjud: root, mysql, oracle. Keyin dastur ichidagi barcha elementlar haqidagi barcha ma'lumotlarni ko'rsatadi. Buni qanday qilishimiz mumkin? Va bu juda oddiy: biz faqat mantiqiy o'zgaruvchini e'lon qilishimiz kerak isEntered, bu bizga element kerak yoki yo'qligini ko'rsatadi va agar ichkarida bo'lsa, barcha ma'lumotlarni o'qing startElement. Yechim kodi:
public class SAXExample {
    private static boolean isFound;

    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser parser = factory.newSAXParser();

        SearchingXMLHandler handler = new SearchingXMLHandler("root");
        parser.parse(new File("resource/xml_file3.xml"), handler);

        if (!isFound)
            System.out.println("Элемент не был найден.");
    }

    private static class SearchingXMLHandler extends DefaultHandler {
        private String element;
        private boolean isEntered;

        public SearchingXMLHandler(String element) {
            this.element = element;
        }

        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
            if (isEntered) {
                System.out.println(String.format("Найден элемент <%s>, его атрибуты:", qName));

                int length = attributes.getLength();
                for(int i = 0; i < length; i++)
                    System.out.println(String.format("Name атрибута: %s, его meaning: %s", attributes.getQName(i), attributes.getValue(i)));
            }

            if (qName.equals(element)) {
                isEntered = true;
                isFound = true;
            }
        }

        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            if (qName.equals(element))
                isEntered = false;
        }
    }
}
Ushbu kodda bizga ma'lumot kerak bo'lgan elementni kiritishda biz bayroqni isEnteredtrue ga o'rnatamiz, ya'ni biz element ichidamiz. Va biz elementning ichida bo'lganimizdan so'ng, biz har bir yangi elementni qayta ishlaymiz startElement, chunki u bizning elementimizning ichki elementi ekanligini bilib olamiz. Shunday qilib, biz element nomini va uning sarlavhasini chiqaramiz. Agar element faylda topilmagan bo'lsa, bizda isFoundelement topilganda o'rnatiladigan o'zgaruvchi mavjud va agar u noto'g'ri bo'lsa, element topilmaganligi haqida xabar paydo bo'ladi. Ko'rib turganingizdek, misolda biz konstruktorga elementni SearchingXMLHandleruzatdik . rootUning uchun xulosa:
Найден элемент <oracle>, его атрибуты:
Найден элемент <connection>, его атрибуты:
Name атрибута: value, его meaning: jdbc:oracle:thin:@10.220.140.48:1521:test1
Найден элемент <user>, его атрибуты:
Name атрибута: value, его meaning: secretOracleUsername
Найден элемент <password>, его атрибуты:
Name атрибута: value, его meaning: 111
Найден элемент <mysql>, его атрибуты:
Найден элемент <connection>, его атрибуты:
Name атрибута: value, его meaning: jdbc:mysql:thin:@10.220.140.48:1521:test1
Найден элемент <user>, его атрибуты:
Name атрибута: value, его meaning: secretMySQLUsername
Найден элемент <password>, его атрибуты:
Name атрибута: value, его meaning: 222
Shunday qilib, biz ichki elementlar va ularning atributlari haqida barcha ma'lumotlarni oldik. Muammo hal qilindi. <h2>Epilog</h2>Siz ko'rdingizki, SAX juda qiziqarli vosita va juda samarali va u turli yo'llar bilan, turli maqsadlarda va hokazolarda ishlatilishi mumkin, muammoga faqat o'ng tomondan qarash kerak. tomoni, № 2 va 3-sonli topshiriqlarda ko'rsatilgandek, bu erda SAX muammoni hal qilishning to'g'ridan-to'g'ri usullarini taqdim etmagan, ammo bizning zukkoligimiz tufayli biz vaziyatdan chiqish yo'lini topa oldik. Maqolaning keyingi qismi butunlay DOMga bag'ishlanadi. Umid qilamanki, sizga SAX bilan tanishish yoqdi. Tajriba, mashq va hamma narsa juda oddiy ekanligini tushunasiz. Hammasi shu, dasturlashda omad tilaymiz va tez orada DOM haqidagi qismni kutamiz. O'qishlaringizga omad :) Oldingi maqola: [Raqobat] Java dasturchisi uchun XML asoslari - 2/3 qism Keyingi maqola: [Raqobat] Java dasturchisi uchun XML asoslari - 3 qismning 3.2 - DOM
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION