JavaRush /Blog Java /Random-MS /Asas XML untuk Pengaturcara Java - Bahagian 3.1 daripada ...
Ярослав
Tahap
Днепр

Asas XML untuk Pengaturcara Java - Bahagian 3.1 daripada 3 - SAX

Diterbitkan dalam kumpulan
Pengenalan Helo kepada semua pembaca artikel saya yang belum terakhir, dan saya ingin mengucapkan tahniah kepada anda: perkara yang rumit tentang XML ada di belakang kami. Artikel ini akan mengandungi kod dalam Java. Akan ada sedikit teori, dan kemudian latihan. Disebabkan fakta bahawa satu bahan di SAX memenuhi 10 halaman dalam Word, saya menyedari bahawa saya tidak dapat memenuhi hadnya. Oleh itu, artikel 3 akan dibahagikan kepada 3 artikel berasingan, tidak kira betapa peliknya ia mungkin kedengaran. Semuanya akan mengikut urutan ini: SAX -> DOM -> JAXB. Artikel ini hanya akan menumpukan pada SAX. PS Terdapat tugas di suatu tempat dalam kursus di mana ia perlu untuk memaparkan semua elemen dalaman dalam fail HTML. Selepas artikel ini, anda akan dapat melakukan ini tanpa membaca baris demi baris dengan BufferedReaderalgoritma pemprosesan konvensional dan kompleks, dan juga penyelesaian yang serupa akan diberikan dalam contoh praktikal terakhir. Mari kita mulakan :) SAX (API Mudah untuk XML) - TEORI Pengendali SAX direka sedemikian rupa sehingga ia hanya membaca fail XML secara berurutan dan bertindak balas kepada peristiwa yang berbeza, selepas itu ia menghantar maklumat kepada pengendali acara khas. Ia mempunyai beberapa acara, tetapi yang paling kerap dan berguna adalah yang berikut:
  1. startDocument- permulaan dokumen
  2. endDocument- akhir dokumen
  3. startElement- membuka elemen
  4. endElement- menutup elemen
  5. characters— maklumat teks dalam elemen.
Semua acara diproses dalam pengendali acara , yang mesti dibuat dan kaedah ditindih . Kelebihan: prestasi tinggi kerana kaedah membaca data "langsung", kos memori yang rendah. Kelemahan: fungsi terhad, yang bermaksud bahawa dalam masalah bukan linear kita perlu memperhalusinya. SAX (API Mudah untuk XML) – AMALKAN segera senarai import supaya anda tidak mencari dan mengelirukan apa-apa:
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;
Sekarang, pertama, kita perlu mencipta SAXParser:
public class SAXExample {
    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
        // Creation фабрики и образца parserа
        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser parser = factory.newSAXParser();
    }
}
Seperti yang anda lihat, anda perlu membuat kilang terlebih dahulu, dan kemudian mencipta parser itu sendiri di kilang. Sekarang kita mempunyai penghurai itu sendiri, kita memerlukan pengendali untuk acaranya. Untuk ini, kami memerlukan kelas yang berasingan untuk kemudahan kami sendiri:
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 {
            // Тут будет логика реакции на пустое пространство внутри элементов (пробелы, переносы строчек и так далее).
        }
    }
}
Kami mencipta kelas dengan semua kaedah yang kami perlukan untuk mengendalikan acara yang disenaraikan dalam teori. Sedikit lagi teori tambahan: Sedikit tentang characters: jika elemen mengandungi teks, sebagai contoh, " hello ", maka, secara teorinya, kaedah itu boleh dipanggil 5 kali berturut-turut untuk setiap watak individu, tetapi ini bukan masalah besar, kerana semuanya masih akan berfungsi. Mengenai kaedah startElementdan endElement:uri - ini ialah ruang di mana elemen itu terletak, localName- ini adalah nama elemen tanpa awalan, qName- ini adalah nama elemen dengan awalan (jika ada, sebaliknya hanya nama daripada unsur). uridan localNamesentiasa kosong jika kami belum mendayakan pemprosesan ruang di kilang. Ini dilakukan menggunakan kaedah kilang setNamespaceAware(true). Kemudian kita boleh mendapatkan ruang ( uri) dan elemen dengan awalan di hadapannya ( localName). Tugasan #1 - Kami mempunyai XML berikut
<?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>
Matlamat kami: untuk mendapatkan semua maklumat tentang semua pekerja daripada fail ini. Pertama, kita perlu membuat kelasEmployee:
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;
    }
}
Dan dalam kelas utama kami, SAXExamplekami memerlukan senarai dengan semua pekerja:
private static ArrayList<Employee> employees = new ArrayList<>();
Sekarang mari kita lihat dengan teliti di mana maklumat yang kita perlukan berada dalam fail XML. Dan, seperti yang dapat kita lihat, semua maklumat yang kita perlukan adalah sifat-sifat unsur employee. Dan kerana startElementkita mempunyai parameter yang berguna seperti attributes, maka kita mempunyai tugas yang agak mudah. Mula-mula, mari kita keluarkan kaedah yang tidak perlu supaya tidak mengacaukan kod kita. Kami hanya memerlukan startElement. Dan dalam kaedah itu sendiri, kita mesti mengumpul maklumat daripada atribut tag pekerja. Perhatian:
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));
            }
        }
    }
}
Logiknya mudah: jika nama unsur ialah employee, kami hanya akan menerima maklumat tentang atributnya. Terdapat attributeskaedah yang berguna di mana, mengetahui nama atribut, anda boleh mendapatkan nilainya. Itu yang kami gunakan. Memandangkan kami telah mencipta pengendali acara untuk permulaan elemen, kami perlu menghuraikan fail XML kami . Untuk melakukan ini, hanya lakukan ini:
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));
            }
        }
    }
}
Dalam kaedah parse anda mesti lulus laluan ke fail xml dan pengendali yang anda buat. Oleh itu, menggunakan kod ini kami mengekstrak maklumat daripada XML ini:
<?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>
Dan kami mendapat output berikut:
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
Misi tercapai! Tugasan #2 - kami mempunyai XML berikut:
<?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>
Matlamat kami: untuk mendapatkan semua maklumat tentang semua pekerja daripada fail ini. Masalah ini akan menunjukkan dengan baik bagaimana fail XML yang tidak berstruktur boleh menyukarkan penulisan kod. Seperti yang anda lihat, maklumat tentang nama dan kedudukan kini disimpan sebagai maklumat teks di dalam elemen namedan job. Untuk membaca teks dalam elemen, kami mempunyai kaedah aksara. Untuk melakukan ini, kita perlu mencipta kelas pengendali baharu dengan logik yang dipertingkatkan. Jangan lupa bahawa pengendali adalah kelas lengkap yang mampu menyimpan logik dari sebarang kerumitan. Oleh itu, sekarang kami akan menala pemproses kami. Malah, sudah cukup untuk ambil perhatian bahawa kami sentiasa namebergilir job-gilir, dan tidak kira dalam susunan apa, kami boleh dengan mudah menyimpan nama dan profesion ke dalam pembolehubah berasingan, dan apabila kedua-dua pembolehubah disimpan, cipta pekerja kami. Hanya di sini, bersama dengan permulaan elemen, kami tidak mempunyai parameter untuk teks di dalam elemen. Kita perlu menggunakan kaedah pada teks. Tetapi bagaimana kita mendapatkan maklumat teks di dalam elemen jika ini adalah kaedah yang sama sekali berbeza? Penyelesaian saya: kita hanya perlu mengingati nama elemen terakhir, dan characterssemak elemen yang sedang kita baca maklumat. Anda juga perlu ingat bahawa <codee>aksara membaca semua aksara di dalam elemen, yang bermaksud bahawa semua ruang dan juga pemisah baris akan dibaca. Dan kita tidak memerlukan mereka. Kita perlu mengabaikan data ini kerana ia tidak betul.</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;
            }
        }
    }
}
Seperti yang anda lihat, disebabkan kerumitan cetek struktur fail XML, kod kami menjadi lebih rumit dengan ketara. Walau bagaimanapun, kod itu tidak rumit. Perihalan: kami mencipta pembolehubah untuk menyimpan data tentang pekerja ( name, job) , serta pembolehubah lastElementNameuntuk merekodkan elemen yang berada di dalamnya. Selepas ini, dalam kaedah characterskami menapis maklumat, dan jika masih terdapat maklumat di sana, maka ini bermakna bahawa ini adalah teks yang kami perlukan, dan kemudian kami menentukan sama ada ia adalah nama atau profesion menggunakan lastElementName. Dalam kaedah endElement, kami menyemak sama ada semua maklumat telah dibaca, dan jika ya, kami membuat pekerja dan menetapkan semula maklumat tersebut. Output penyelesaian adalah bersamaan dengan contoh pertama:
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
Oleh itu, masalah ini telah diselesaikan , tetapi anda dapat melihat bahawa kerumitannya lebih tinggi. Oleh itu, kita boleh membuat kesimpulan bahawa menyimpan maklumat teks dalam atribut selalunya akan menjadi lebih betul daripada dalam elemen individu. Dan satu lagi tugasan manis yang sebahagiannya akan menyelesaikan masalah dalam JavaRush tentang memaparkan maklumat tentang elemen dalam HTML, cuma ia perlu diedit sedikit, di sini kita hanya akan menyenaraikan semua elemen di dalam elemen :) Tugasan No. 3 - memandangkan elemen elemen, paparkan nama dan atribut semua elemen dalaman; jika elemen itu tidak dijumpai, paparkan ini. Untuk tugas ini kami akan menggunakan fail XML berikut:
<?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>
Seperti yang anda lihat, kami mempunyai tiga kemungkinan senario di sini: root, mysql, oracle. Kemudian program akan memaparkan semua maklumat tentang semua elemen di dalamnya. Bagaimana kita boleh melakukan ini? Dan ia agak mudah: kita hanya perlu mengisytiharkan pembolehubah logik isEntered, yang akan menunjukkan sama ada kita memerlukan elemen di dalam, dan jika di dalam, baca semua data dari startElement. Kod penyelesaian:
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;
        }
    }
}
Dalam kod ini, apabila memasukkan elemen yang kami perlukan maklumat, kami menetapkan bendera isEnteredkepada benar, yang bermaksud bahawa kami berada di dalam elemen tersebut. Dan sebaik sahaja kami berada di dalam elemen, kami hanya memproses setiap elemen baharu startElement, mengetahui bahawa ia betul-betul elemen dalaman elemen kami. Jadi kami mengeluarkan nama elemen dan tajuknya. Jika elemen tidak ditemui dalam fail, maka kami mempunyai pembolehubah isFoundyang ditetapkan apabila elemen ditemui, dan jika ia palsu, mesej akan dipaparkan bahawa elemen itu tidak ditemui. Dan seperti yang anda boleh lihat, dalam contoh SearchingXMLHandlerkami menyerahkan rootelemen kepada pembina. Kesimpulan untuk beliau:
Найден элемент <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
Oleh itu, kami menerima semua maklumat tentang elemen dalaman dan sifatnya. Masalah selesai. <h2>Epilog</h2>Anda telah melihat bahawa SAX adalah alat yang menarik dan agak berkesan, dan ia boleh digunakan dengan cara yang berbeza, untuk tujuan yang berbeza, dan seterusnya, anda hanya perlu melihat masalah dari sebelah kanan sampingan, seperti yang ditunjukkan dalam tugasan No. 2 dan No. 3, di mana SAX tidak menyediakan kaedah langsung untuk menyelesaikan masalah, tetapi, berkat kepintaran kami, kami dapat mencari jalan keluar dari situasi itu. Bahagian seterusnya artikel akan ditumpukan sepenuhnya kepada DOM. Saya harap anda seronok mengenali SAX. Eksperimen, berlatih dan anda akan faham bahawa semuanya agak mudah. Dan itu sahaja, semoga berjaya dengan pengaturcaraan anda dan nantikan bahagian tentang DOM tidak lama lagi. Semoga berjaya dalam pengajian anda :) Artikel sebelumnya: [Pertandingan] Asas XML untuk Pengaturcara Java - Bahagian 2 daripada 3 Artikel seterusnya: [Pertandingan] Asas XML untuk Pengaturcara Java - Bahagian 3.2 daripada 3 - DOM
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION