JavaRush /Java Blog /Random-ID /Dasar-Dasar XML untuk Pemrogram Java - Bagian 3.1 dari 3 ...
Ярослав
Level 40
Днепр

Dasar-Dasar XML untuk Pemrogram Java - Bagian 3.1 dari 3 - SAX

Dipublikasikan di grup Random-ID
Pendahuluan Halo kepada semua pembaca artikel saya yang belum terakhir ini, dan saya ingin mengucapkan selamat kepada Anda: hal-hal rumit tentang XML sudah berlalu. Artikel ini akan berisi kode dalam Java. Akan ada sedikit teori, lalu praktik. Karena fakta bahwa satu materi di SAX memenuhi 10 halaman di Word, saya menyadari bahwa saya tidak dapat memenuhi batasan tersebut. Oleh karena itu, pasal 3 akan dibagi menjadi 3 pasal tersendiri, betapapun anehnya kedengarannya. Semuanya akan dalam urutan ini: SAX -> DOM -> JAXB. Artikel ini hanya akan fokus pada SAX. PS Ada tugas di suatu tempat dalam kursus yang mengharuskan menampilkan semua elemen internal dalam file HTML. Setelah artikel ini, Anda akan dapat melakukan ini tanpa membaca baris demi baris dengan BufferedReaderalgoritma pemrosesan konvensional dan kompleks, dan solusi serupa juga akan diberikan pada contoh praktis terakhir. Mari kita mulai :) SAX (API Sederhana untuk XML) - TEORI Penangan SAX dirancang sedemikian rupa sehingga ia hanya membaca file XML secara berurutan dan bereaksi terhadap peristiwa yang berbeda, setelah itu meneruskan informasi ke pengendali peristiwa khusus. Terdapat beberapa kejadian di dalamnya, namun yang paling sering dan berguna adalah sebagai berikut:
  1. startDocument— awal dokumen
  2. endDocument- akhir dokumen
  3. startElement- membuka elemen
  4. endElement- menutup elemen
  5. characters— informasi teks di dalam elemen.
Semua kejadian diproses dalam sebuah event handler , yang harus dibuat dan metodenya diganti . Keuntungan: kinerja tinggi karena metode membaca data "langsung", biaya memori rendah. Kekurangan: fungsionalitas terbatas, yang berarti bahwa dalam masalah non-linier kita harus menyempurnakannya. SAX (Simple API for XML) – PRAKTEK Segera daftar importnya agar tidak mencari dan bingung apa pun:
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-tama, kita perlu membuat 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, pertama-tama Anda perlu membuat pabrik, lalu membuat parser itu sendiri di pabrik. Sekarang kita sudah memiliki parsernya sendiri, kita membutuhkan sebuah handler untuk event-eventnya. Untuk ini kita memerlukan kelas terpisah untuk kenyamanan kita 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 membuat kelas dengan semua metode yang kami perlukan untuk menangani peristiwa yang tercantum dalam teori. Sedikit teori tambahan: Sedikit tentang characters: jika suatu elemen berisi teks, misalnya “ halo ”, maka secara teoritis metode tersebut dapat dipanggil 5 kali berturut-turut untuk setiap karakter, tetapi ini bukan masalah besar, karena semuanya akan tetap berfungsi. Tentang metode startElementdan endElement:uri - ini adalah ruang di mana elemen berada, localName- ini adalah nama elemen tanpa awalan, qName- ini adalah nama elemen dengan awalan (jika ada, jika tidak, hanya namanya saja dari elemen). uridan localNameselalu kosong jika kita belum mengaktifkan ruang pemrosesan di pabrik. Hal ini dilakukan dengan menggunakan metode pabrik setNamespaceAware(true). Kemudian kita bisa mendapatkan spasi ( uri) dan elemen dengan awalan di depannya ( localName). Tugas #1 - Kami memiliki 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>
Tujuan kami: mendapatkan semua informasi tentang seluruh karyawan dari file 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 di kelas utama kami, SAXExamplekami memerlukan daftar dengan semua karyawan:
private static ArrayList<Employee> employees = new ArrayList<>();
Sekarang mari kita perhatikan baik-baik di mana informasi yang kita butuhkan ada di file XML. Dan, seperti yang bisa kita lihat, semua informasi yang kita butuhkan hanyalah atribut dari elemen-elemen tersebut employee. Dan karena startElementkita memiliki parameter yang berguna seperti attributes, maka kita mempunyai tugas yang cukup sederhana. Pertama, mari kita hapus metode yang tidak perlu agar tidak mengacaukan kode kita. Kami hanya membutuhkan startElement. Dan dalam metodenya sendiri, kita harus mengumpulkan informasi dari atribut tag karyawan. 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));
            }
        }
    }
}
Logikanya sederhana: jika nama suatu elemen adalah employee, kita hanya akan menerima informasi tentang atributnya. Ada attributesmetode yang berguna di mana, dengan mengetahui nama suatu atribut, Anda bisa mendapatkan nilainya. Itu yang kami gunakan. Sekarang kita telah membuat event handler untuk awal sebuah elemen, kita perlu mengurai file XML kita . Untuk melakukan ini, lakukan saja 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 metode parse Anda harus meneruskan path ke file xml dan handler yang Anda buat. Jadi, dengan menggunakan kode ini kami mengekstrak informasi dari 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 hasil sebagai 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 selesai! Tugas #2 - kita memiliki 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>
Tujuan kami: mendapatkan semua informasi tentang seluruh karyawan dari file ini. Masalah ini akan menunjukkan dengan baik bagaimana file XML yang tidak terstruktur dengan baik dapat membuat penulisan kode menjadi lebih sulit. Seperti yang Anda lihat, informasi tentang nama dan posisi kini disimpan sebagai informasi teks di dalam elemen nameand job. Untuk membaca teks di dalam elemen, kami memiliki metode karakter. Untuk melakukan ini, kita perlu membuat kelas handler baru dengan logika yang lebih baik. Jangan lupa bahwa penangan adalah kelas lengkap yang mampu menyimpan logika dengan kompleksitas apa pun. Oleh karena itu, sekarang kita akan menyetel prosesor kita. Faktanya, cukup dicatat bahwa kita selalu namebergiliran job, dan tidak peduli bagaimana urutannya, kita dapat dengan mudah menyimpan nama dan profesi ke dalam variabel terpisah, dan ketika kedua variabel disimpan, buatlah karyawan kita. Hanya di sini, bersama dengan awal elemen, kami tidak memiliki parameter untuk teks di dalam elemen. Kita perlu menggunakan metode pada teks. Namun bagaimana kita mendapatkan informasi teks di dalam suatu elemen jika metodenya benar-benar berbeda? Solusi saya: kita hanya perlu mengingat nama elemen terakhir, dan charactersmemeriksa elemen mana yang kita baca informasinya. Anda juga perlu mengingat bahwa <codee>karakter membaca semua karakter di dalam elemen, yang berarti semua spasi dan jeda baris akan dibaca. Dan kita tidak membutuhkannya. Kita perlu mengabaikan data ini karena salah.</codee> Kode:
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, karena kerumitan struktur file XML yang dangkal, kode kita menjadi jauh lebih rumit. Namun, kodenya tidak rumit. Deskripsi: kita membuat variabel untuk menyimpan data tentang karyawan ( name, job) , serta variabel lastElementNameuntuk mencatat elemen mana yang ada di dalamnya. Setelah itu pada metodenya characterskita menyaring informasinya, dan jika masih ada informasi disana, berarti inilah teks yang kita butuhkan, lalu kita tentukan apakah itu nama atau profesi yang menggunakan lastElementName. Dalam metode ini endElement, kami memeriksa apakah semua informasi telah dibaca, dan jika demikian, kami membuat karyawan dan mengatur ulang informasi tersebut. Output dari solusi ini setara 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
Dengan demikian, masalah ini telah terpecahkan , tetapi Anda dapat melihat bahwa kompleksitasnya lebih tinggi. Oleh karena itu, kita dapat menyimpulkan bahwa menyimpan informasi teks dalam atribut seringkali lebih tepat daripada elemen individual. Dan satu lagi tugas manis yang sebagian akan menyelesaikan masalah di JavaRush tentang menampilkan informasi tentang suatu elemen dalam HTML, hanya saja perlu diedit sedikit, di sini kita hanya akan mencantumkan semua elemen di dalam sebuah elemen :) Tugas No.3 - diberi elemen elemen, tampilkan nama dan atribut semua elemen internal; jika elemen tidak ditemukan, tampilkan ini. Untuk tugas ini kita akan menggunakan file 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 memiliki tiga kemungkinan skenario di sini: root, mysql, oracle. Kemudian program akan menampilkan semua informasi tentang semua elemen di dalamnya. Bagaimana kita bisa melakukan ini? Dan ini cukup sederhana: kita hanya perlu mendeklarasikan variabel logis isEntered, yang akan menunjukkan apakah kita memerlukan elemen di dalamnya, dan jika di dalam, baca semua data dari startElement. Kode solusi:
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 kode ini, saat memasukkan elemen yang informasinya kita perlukan, kita menyetel tandanya isEnteredke true, yang berarti kita berada di dalam elemen tersebut. Dan segera setelah kita berada di dalam elemen, kita cukup memproses setiap elemen baru startElement, mengetahui bahwa itu adalah elemen internal elemen kita. Jadi kami menampilkan nama elemen dan judulnya. Jika elemen tidak ditemukan dalam file, maka kita memiliki variabel isFoundyang disetel ketika elemen ditemukan, dan jika salah, akan ditampilkan pesan bahwa elemen tersebut tidak ditemukan. Dan seperti yang Anda lihat, dalam contoh SearchingXMLHandlerkami meneruskan rootelemen ke konstruktor. Kesimpulan untuknya:
Найден элемент <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
Jadi, kami menerima semua informasi tentang elemen internal dan atributnya. Masalah terpecahkan. <h2>Epilog</h2>Anda telah melihat bahwa SAX adalah alat yang cukup menarik dan cukup efektif, dan dapat digunakan dengan cara yang berbeda, untuk tujuan yang berbeda, dan seterusnya, Anda hanya perlu melihat masalahnya dari sisi kanan. sisi, seperti yang ditunjukkan pada tugas No. 2 dan No. 3, di mana SAX tidak memberikan metode langsung untuk menyelesaikan masalah, tetapi berkat kecerdikan kami, kami dapat menemukan jalan keluar dari situasi tersebut. Bagian selanjutnya dari artikel ini akan sepenuhnya dikhususkan untuk DOM. Saya harap Anda senang mengenal SAX. Bereksperimenlah, berlatihlah dan Anda akan memahami bahwa semuanya cukup sederhana. Itu saja, semoga berhasil dengan pemrograman Anda dan nantikan bagian tentang DOM segera. Semoga sukses dalam studimu :) Artikel sebelumnya: [Kompetisi] Dasar-Dasar XML untuk Pemrogram Java - Bagian 2 dari 3 Artikel berikutnya: [Kompetisi] Dasar-dasar XML untuk Pemrogram Java - Bagian 3.2 dari 3 - DOM
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION