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

Asas XML untuk Pengaturcara Java. Bahagian 3.2 daripada 3 - DOM

Diterbitkan dalam kumpulan
<h2>Pengenalan</h2>Helo kepada semua pembaca artikel, bahagian ini didedikasikan untuk DOM. Yang seterusnya akan ditumpukan kepada JAXB dan, dengan ini, kitaran asas XML akan selesai. Mula-mula akan ada sedikit teori, dan kemudian hanya latihan. Mari kita mulakan. <h2>DOM (Model Objek Dokumen) - TEORI</h2>Pengendali DOM direka bentuk sedemikian rupa sehingga ia membaca semua XML sekaligus dan menyimpannya, mewujudkan hierarki dalam bentuk pokok yang melaluinya kita boleh bergerak dengan mudah dan akses elemen yang kami perlukan. Oleh itu, kita boleh, diberi pautan ke elemen teratas, mendapatkan semua pautan ke elemen dalamannya. Lebih-lebih lagi, unsur-unsur yang berada di dalam elemen adalah anak-anak unsur ini, dan ia adalah ibu bapa mereka. Sebaik sahaja kami telah membaca semua XML ke dalam ingatan, kami hanya akan melalui strukturnya dan melakukan tindakan yang kami perlukan. Sedikit tentang bahagian pengaturcaraan DOM dalam Java: DOM mempunyai banyak antara muka yang dicipta untuk menerangkan data yang berbeza. Semua antara muka ini mewarisi satu antara muka biasa - Node. Kerana, sebenarnya, jenis data yang paling biasa dalam DOM ialah Node, yang boleh menjadi apa sahaja. Setiap Nod mempunyai kaedah berguna berikut untuk mendapatkan maklumat:
  1. getNodeName– dapatkan nama hos.
  2. getNodeValue– dapatkan nilai nod.
  3. getNodeType– dapatkan jenis nod.
  4. getParentNode– dapatkan nod di mana nod yang diberikan berada.
  5. getChildNodes– dapatkan semua nod terbitan (nod yang berada di dalam nod tertentu).
  6. getAttributes– dapatkan semua atribut nod.
  7. getOwnerDocument– dapatkan dokumen nod ini.
  8. getFirstChild/getLastChild– dapatkan nod terbitan pertama/terakhir.
  9. getLocalName– berguna apabila memproses ruang nama untuk mendapatkan nama tanpa awalan.
  10. getTextContent– mengembalikan semua teks dalam elemen dan semua elemen dalam elemen tertentu, termasuk pemisah baris dan ruang.
Nota tentang kaedah 9: ia akan sentiasa mengembalikan null melainkan anda telah menggunakan kaedah setNamespaceAware(true) dalam DocumentFactory untuk mencetuskan pemprosesan ruang nama. Sekarang, perincian penting: kaedah adalah biasa kepada semua Nod, tetapi dalam Node kita boleh mempunyai kedua-dua elemen dan atribut. Dan inilah persoalannya: apakah nilai yang boleh dimiliki oleh sesuatu elemen? Apakah nod terbitan yang boleh dimiliki oleh atribut? Dan yang lain tidak konsisten. Dan semuanya agak mudah: setiap kaedah akan berfungsi bergantung pada jenis Node . Ia cukup untuk menggunakan logik, sudah tentu, supaya tidak keliru. Sebagai contoh: apakah atribut yang boleh dimiliki oleh atribut? Apakah maksud lain unsur tersebut? Walau bagaimanapun, untuk tidak mencuba semuanya sendiri, dalam dokumen rasmi terdapat jadual yang sangat berguna tentang cara setiap kaedah berfungsi bergantung pada jenis Node: Kualiti ternyata buruk, jadi berikut adalah pautan ke dokumentasi (jadual di bahagian atas halaman): Dokumentasi Nod Perkara paling penting untuk diingat:
  1. HANYA elemen mempunyai atribut.
  2. Unsur TIADA makna.
  3. Nama nod elemen adalah sama dengan nama tag, dan nama nod atribut adalah sama dengan nama atribut.
<h2>DOM (Model Objek Dokumen) - AMALAN</h2>Dalam bahagian praktikal, kami akan menganalisis pelbagai jenis tugasan untuk mencari maklumat dalam XML. Kami juga mengambil dua tugasan dari artikel sebelumnya untuk membandingkan kemudahan. Mari kita mulakan, dan adalah baik untuk bermula dengan import:
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;
Saya menyediakan import supaya anda tidak mengelirukan kelas :) Tugasan No. 1 - kita perlu mendapatkan maklumat tentang semua pekerja dan mengeluarkannya ke konsol daripada fail 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>
Seperti yang dapat kita lihat, kita mempunyai semua maklumat yang disimpan dalam elemen pekerja. Untuk menyimpannya di suatu tempat dalam program kami, mari buat kelas Employee:
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;
    }
}
Sekarang kita mempunyai penerangan tentang struktur untuk menyimpan data, kita memerlukan koleksi yang akan menyimpan pekerja. Kami akan menciptanya dalam kod itu sendiri. Kami juga perlu membuat Dokumen berdasarkan XML kami:
public class DOMExample {
    // Список для сотрудников из XML file
    private static ArrayList<Employee> employees = new ArrayList<>();

    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
        // Получение фабрики, чтобы после получить билдер documentов.
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

        // Получor из фабрики билдер, который парсит XML, создает структуру Document в виде иерархического дерева.
        DocumentBuilder builder = factory.newDocumentBuilder();

        // Запарсor XML, создав структуру Document. Теперь у нас есть доступ ко всем elementм, Howим нам нужно.
        Document document = builder.parse(new File("resource/xml_file1.xml"));
    }
}
Sebaik sahaja kami menerima dokumen, kami mempunyai kuasa tanpa had ke atas keseluruhan struktur fail XML. Kami boleh mengambil sebarang elemen pada bila-bila masa, kembali untuk menyemak sebarang data dan, secara umum, pendekatan yang lebih fleksibel daripada yang kami ada di SAX. Dalam konteks tugas ini, kita hanya perlu mengekstrak semua elemen pekerja, dan kemudian mengekstrak semua maklumat tentang mereka. Ia agak mudah:
public class DOMExample {
    // Список для сотрудников из XML file
    private static ArrayList<Employee> employees = new ArrayList<>();

    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
        // Получение фабрики, чтобы после получить билдер documentов.
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

        // Получor из фабрики билдер, который парсит XML, создает структуру Document в виде иерархического дерева.
        DocumentBuilder builder = factory.newDocumentBuilder();

        // Запарсor XML, создав структуру Document. Теперь у нас есть доступ ко всем elementм, Howим нам нужно.
        Document document = builder.parse(new File("resource/xml_file1.xml"));

        // Получение списка всех элементов employee внутри корневого element (getDocumentElement возвращает ROOT элемент XML file).
        NodeList employeeElements = document.getDocumentElement().getElementsByTagName("employee");

        // Перебор всех элементов employee
        for (int i = 0; i < employeeElements.getLength(); i++) {
            Node employee = employeeElements.item(i);

            // Получение атрибутов каждого element
            NamedNodeMap attributes = employee.getAttributes();

            // Добавление сотрудника. Атрибут - тоже Node, потому нам нужно получить meaning атрибута с помощью метода getNodeValue()
            employees.add(new Employee(attributes.getNamedItem("name").getNodeValue(), attributes.getNamedItem("job").getNodeValue()));
        }

        // Вывод информации о каждом сотруднике
        for (Employee employee : employees)
            System.out.println(String.format("Информации о сотруднике: Name - %s, должность - %s.", employee.getName(), employee.getJob()));
    }
}
Perihalan penyelesaian ini tepat dalam penyelesaian. Adalah dinasihatkan, selepas melihat kod, untuk kembali kepada teori dan membacanya semula. Malah, semuanya jelas secara naluri. Baca komen dengan teliti dan tidak sepatutnya ada sebarang soalan, dan jika ada, anda boleh menulis dalam komen, saya akan menjawab, atau dalam pautan, atau hanya jalankan IDEA anda dan cuba bermain dengan kod itu sendiri jika anda belum berbuat demikian lagi. Jadi selepas menjalankan kod 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.
Seperti yang anda lihat, tugas itu berjaya diselesaikan! Mari kita teruskan ke tugas seterusnya :) Tugasan No. 2 - nama elemen dimasukkan dari konsol, yang anda perlukan untuk memaparkan maklumat tentang semua elemen di dalamnya dan atributnya dari 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>
Segala-galanya agak mudah: kita mesti mendapatkan elemen dengan namanya, yang kita kira, dan kemudian melalui semua nod kanak-kanak. Untuk melakukan ini, anda perlu mengulangi semua nod anak semua nod anak yang merupakan unsur. Penyelesaian kepada masalah ini:
public class DOMExample {
    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
        // Ридер для считывания имени тега из консоли
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

        // Получение фабрики, чтобы после получить билдер documentов.
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

        // Получor из фабрики билдер, который парсит XML, создает структуру Document в виде иерархического дерева.
        DocumentBuilder builder = factory.newDocumentBuilder();

        // Запарсor XML, создав структуру Document. Теперь у нас есть доступ ко всем elementм, Howим нам нужно.
        Document document = builder.parse(new File("resource/xml_file3.xml"));

        // Считывание имени тега для поиска его в файле
        String element = reader.readLine();

        // Получение списка элементов, однако для удобства будем рассматривать только первое совпадение в documentе.
        // Так же заметьте, что мы ищем элемент внутри documentа, а не рут element. Это сделано для того, чтобы рут элемент тоже искался.
        NodeList matchedElementsList = document.getElementsByTagName(element);

        // Даже если element нет, всегда будет возвращаться список, просто он будет пустым.
        // Потому, чтобы утверждать, что element нет в файле, достаточно проверить размер списка.
        if (matchedElementsList.getLength() == 0) {
            System.out.println("Tag " + element + " не был найден в файле.");
        } else {
            // Получение первого element.
            Node foundedElement = matchedElementsList.item(0);

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

            // Если есть данные внутри, вызов метода для вывода всей информации
            if (foundedElement.hasChildNodes())
                printInfoAboutAllChildNodes(foundedElement.getChildNodes());
        }
    }

    /**
     * Рекурсивный метод, который будет выводить информацию про все узлы внутри всех узлов, которые пришли параметром, пока не будут перебраны все узлы.
     * @param list Список узлов.
     */
    private static void printInfoAboutAllChildNodes(NodeList list) {
        for (int i = 0; i < list.getLength(); i++) {
            Node node = list.item(i);

            // У элементов есть два вида узлов - другие элементы or текстовая информация. Потому нужно разбираться две ситуации отдельно.
            if (node.getNodeType() == Node.TEXT_NODE) {
                // Фильтрация информации, так How пробелы и переносы строчек нам не нужны. Это не информация.
                String textInformation = node.getNodeValue().replace("\n", "").trim();

                if(!textInformation.isEmpty())
                    System.out.println("Внутри element найден текст: " + node.getNodeValue());
            }
            // Если это не текст, а элемент, то обрабатываем его How элемент.
            else {
                System.out.println("Найден элемент: " + node.getNodeName() + ", его атрибуты:");

                // Получение атрибутов
                NamedNodeMap attributes = node.getAttributes();

                // Вывод информации про все атрибуты
                for (int k = 0; k < attributes.getLength(); k++)
                    System.out.println("Name атрибута: " + attributes.item(k).getNodeName() + ", его meaning: " + attributes.item(k).getNodeValue());
            }

            // Если у данного element еще остались узлы, то вывести всю информацию про все его узлы.
            if (node.hasChildNodes())
                printInfoAboutAllChildNodes(node.getChildNodes());
        }
    }
}
Keseluruhan penerangan penyelesaian ada dalam ulasan, tetapi saya ingin menggambarkan sedikit secara grafik pendekatan yang kami gunakan, menggunakan contoh dari gambar dari teori. Kami akan menganggap bahawa kami perlu memaparkan maklumat tentang tag html. Seperti yang anda lihat, kita perlu pergi dari atas ke bawah dari akar pokok. Semua baris adalah nod. Dalam penyelesaian, kami akan pergi secara rekursif dari permulaan elemen yang dikehendaki melalui semua nodnya, dan jika salah satu nodnya ialah elemen, maka kami juga melelar melalui semua nod elemen ini. Jadi selepas menjalankan kod kami mendapat output berikut untuk elemen akar:
Элемент был найден!
Найден элемент: 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
Masalah telah berjaya diselesaikan! Tugasan No. 3 – daripada fail XML berikut, di mana maklumat tentang pelajar, profesor dan pekerja disimpan, anda perlu membaca maklumat dan mengeluarkannya ke konsol:
<?xml version="1.0" encoding="UTF-8"?>
<database>
    <students>
        <student name="Maksim" course="3" specialization="CE" />
        <student name="Stephan" course="1" specialization="CS" />
        <student name="Irvin" course="2" specialization="CE" />
    </students>

    <professors>
        <professor name="Herald" experience="7 years in University" discipline="Math" />
        <professor name="Adam" experience="4 years in University" discipline="Programming" />
        <professor name="Anton" experience="6 years in University" discipline="English" />
    </professors>

    <service>
        <member name="John" position="janitor" />
        <member name="Jordan" position="janitor" />
        <member name="Mike" position="janitor" />
    </service>
</database>
Tugasnya agak mudah, tetapi menarik. Pertama, kita perlu mencipta 4 kelas: pekerja, profesor dan pelajar, serta kelas abstrak biasa Manusia untuk membawa pembolehubah nama dari setiap kelas di bawah penyebut biasa: Kelas induk abstrak
public abstract class Human {
    private String name;

    public Human(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}
Pelajar
public class Student extends Human {
    private String course, specialization;

    public Student(String name, String course, String specialization) {
        super(name);
        this.course = course;
        this.specialization = specialization;
    }

    public String getCourse() {
        return course;
    }

    public String getSpecialization() {
        return specialization;
    }

    public String toString() {
        return "Голодный студент " + getName() + " " + course + "-го курса, обучающийся по специальности " + specialization;
    }
}
Profesor
public class Professor extends Human {
    private String experience, discipline;

    public Professor(String name, String experience, String discipline) {
        super(name);
        this.experience = experience;
        this.discipline = discipline;
    }

    public String getExperience() {
        return experience;
    }

    public String getDiscipline() {
        return discipline;
    }

    public String toString() {
        return "Профессор " + getName() + ", обладающий опытом: \"" + experience + "\", выкладает дисциплину " + discipline;
    }
}
Pekerja
public class Member extends Human {
    private String position;

    public Member(String name, String position) {
        super(name);
        this.position = position;
    }

    public String getPosition() {
        return position;
    }

    public String toString() {
        return "Сотрудник обслуживающего персонала " + getName() + ", должность: " + position;
    }
}
Memandangkan kelas kami sudah sedia, kami hanya perlu menulis kod untuk mendapatkan semua elemen pelajar, profesor dan ahli, dan kemudian mendapatkan atribut mereka. Untuk penyimpanan, kami akan menggunakan koleksi yang akan menyimpan objek kelas induk yang biasa kepada semua - Manusia. Jadi, penyelesaian kepada masalah ini:
public class DOMExample {
    // Коллекция для хранения всех людей
    private static ArrayList<Human> humans = new ArrayList<>();

    // Константы для элементов
    private static final String PROFESSOR = "professor";
    private static final String MEMBER = "member";
    private static final String STUDENT = "student";

    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
        // Получение фабрики, чтобы после получить билдер documentов.
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

        // Получor из фабрики билдер, который парсит XML, создает структуру Document в виде иерархического дерева.
        DocumentBuilder builder = factory.newDocumentBuilder();

        // Запарсor XML, создав структуру Document. Теперь у нас есть доступ ко всем elementм, Howим нам нужно.
        Document document = builder.parse(new File("resource/xml_file3.xml"));

        // Получение информации про каждый элемент отдельно
        collectInformation(document, PROFESSOR);
        collectInformation(document, MEMBER);
        collectInformation(document, STUDENT);

        // Вывод информации
        humans.forEach(System.out::println);
    }

    /**
     * Метод ищет информацию про теги по имени element и вносит всю информацию в коллекцию humans.
     * @param document Документ, в котором будем искать элементы.
     * @param element Name element, теги которого нужно найти. Должна быть одна из констант, которые определяются выше.
     */
    private static void collectInformation(Document document, final String element) {
        // Получение всех элементов по имени тега.
        NodeList elements = document.getElementsByTagName(element);

        // Перебор всех найденных элементов
        for (int i = 0; i < elements.getLength(); i++) {
            // Получение всех атрибутов element
            NamedNodeMap attributes = elements.item(i).getAttributes();
            String name = attributes.getNamedItem("name").getNodeValue();

            // В зависимости от типа element, нам нужно собрать свою дополнительну информацию про каждый подкласс, а после добавить нужные образцы в коллекцию.
            switch (element) {
                case PROFESSOR: {
                    String experience = attributes.getNamedItem("experience").getNodeValue();
                    String discipline = attributes.getNamedItem("discipline").getNodeValue();

                    humans.add(new Professor(name, experience, discipline));
                } break;
                case STUDENT: {
                    String course = attributes.getNamedItem("course").getNodeValue();
                    String specialization = attributes.getNamedItem("specialization").getNodeValue();

                    humans.add(new Student(name, course, specialization));
                } break;
                case MEMBER: {
                    String position = attributes.getNamedItem("position").getNodeValue();

                    humans.add(new Member(name, position));
                } break;
            }
        }
    }
}
Ambil perhatian bahawa kami hanya memerlukan nama elemen untuk mendapatkan semua elemen ini daripada dokumen. Ini sangat memudahkan proses mencari maklumat yang anda perlukan. Semua maklumat tentang kod disertakan dalam ulasan. Tiada apa-apa yang baru digunakan yang tidak terdapat dalam tugasan sebelumnya. Keluaran kod:
Профессор Herald, обладающий опытом: "7 years in University", выкладает дисциплину Math
Профессор Adam, обладающий опытом: "4 years in University", выкладает дисциплину Programming
Профессор Anton, обладающий опытом: "6 years in University", выкладает дисциплину English
Сотрудник обслуживающего персонала John, должность: janitor
Сотрудник обслуживающего персонала Jordan, должность: janitor
Сотрудник обслуживающего персонала Mike, должность: janitor
Голодный студент Maksim 3-го курса, обучающийся по специальности CE
Голодный студент Stephan 1-го курса, обучающийся по специальности CS
Голодный студент Irvin 2-го курса, обучающийся по специальности CE
Masalah selesai! Pengesyoran bila hendak menggunakan DOM dan bila hendak menggunakan SAX Perbezaan antara alatan ini adalah dari segi fungsi dan kelajuan. Jika anda memerlukan fungsi yang lebih fleksibel dan mampu membazirkan prestasi program, maka pilihan anda ialah DOM, tetapi jika matlamat utama anda adalah untuk mengurangkan kos memori, maka DOM bukanlah pilihan terbaik, kerana ia membaca semua maklumat daripada fail XML dan menyimpannya. Oleh itu, kaedah bacaan berurutan SAX adalah lebih murah. Secara ringkas: jika anda memerlukan prestasi - SAX, fungsi - DOM. <h2>Kesimpulan</h2>Setiap pengaturcara mempunyai alatan sendiri dan, bergantung pada tugas, anda perlu menggunakan alatan tertentu. Dalam artikel tentang SAX dan DOM, matlamat saya adalah untuk mengajar anda cara mengekstrak maklumat daripada fail XML dan memprosesnya mengikut cara yang anda perlukan. Walau bagaimanapun, walaupun anda telah membaca artikel ini, anda tidak boleh mendakwa telah mempelajari cara menggunakan alat ini. Anda harus berlatih, menguji kod daripada artikel, memahami cara ia berfungsi, dan cuba menulis sesuatu sendiri. Lagipun, perkara yang paling penting ialah amalan. Artikel terakhir akan diterbitkan dalam beberapa hari akan datang dan, nampaknya, selepas tamat pertandingan, dan akan ditumpukan kepada JAXB. JAXB ialah alat untuk menyimpan objek dalam program anda dalam format XML. Itu sahaja, saya harap artikel ini berguna, dan semoga berjaya dalam pengaturcaraan anda :) Artikel sebelumnya: [Pertandingan] Asas XML untuk Pengaturcara Java - Bahagian 3.1 daripada 3 - SAX
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION