JavaRush /Java Blogu /Random-AZ /Java Proqramçısı üçün XML Əsasları. 3-dən 3.2-ci hissə - ...
Ярослав
Səviyyə
Днепр

Java Proqramçısı üçün XML Əsasları. 3-dən 3.2-ci hissə - DOM

Qrupda dərc edilmişdir
<h2>Giriş</h2>Məqalənin bütün oxucularına salam, bu hissə DOM-a həsr olunub. Növbəti JAXB-ə həsr olunacaq və bununla da XML əsasları dövrü tamamlanacaq. Əvvəlcə bir az nəzəriyyə, sonra isə yalnız təcrübə olacaq. Gəlin başlayaq. <h2>DOM (Sənəd Obyekt Modeli) - NƏZƏRİYYƏ</h2>DOM işləyicisi elə qurulmuşdur ki, o, bütün XML-i birdən oxuyur və onu yadda saxlayır, ağac şəklində iyerarxiya yaradır və biz asanlıqla hərəkət edə bilərik. və bizə lazım olan elementlərə daxil olun. Beləliklə, yuxarı elementə bir keçid verildikdə, onun daxili elementlərinə bütün bağlantıları əldə edə bilərik. Üstəlik, elementin içərisində olan elementlər bu elementin uşaqlarıdır və onların anasıdır. Bütün XML-i yaddaşda oxuduqdan sonra, sadəcə olaraq onun strukturu ilə səyahət edəcəyik və lazım olan hərəkətləri yerinə yetirəcəyik. Java-da DOM-un proqramlaşdırma hissəsi haqqında bir az: DOM müxtəlif məlumatları təsvir etmək üçün yaradılmış bir çox interfeysə malikdir. Bütün bu interfeyslər bir ümumi interfeysi miras alır - Node. Çünki əslində DOM-da ən çox yayılmış məlumat növü hər hansı bir şey ola bilən Node-dur. Hər bir Node məlumat əldə etmək üçün aşağıdakı faydalı üsullara malikdir:
  1. getNodeName– host adını alın.
  2. getNodeValue- node dəyərini əldə edin.
  3. getNodeType– node tipini əldə edin.
  4. getParentNode– verilmiş nodeun yerləşdiyi qovşağı alın.
  5. getChildNodes– bütün törəmə qovşaqları əldə edin (verilmiş node daxilində olan qovşaqlar).
  6. getAttributes– bütün node atributlarını əldə edin.
  7. getOwnerDocument– bu qovşağın sənədini əldə edin.
  8. getFirstChild/getLastChild– ilk/son əldə edilən qovşağı alın.
  9. getLocalName– prefikssiz ad almaq üçün ad boşluqlarını emal edərkən faydalıdır.
  10. getTextContent– element daxilindəki bütün mətni və verilmiş element daxilindəki bütün elementləri, o cümlədən sətir fasilələri və boşluqları qaytarır.
Metod 9-a dair qeyd: ad sahəsinin işlənməsini işə salmaq üçün DocumentFactory-də setNamespaceAware(true) metodundan istifadə etməsəniz, o, həmişə null olacaq. İndi vacib bir təfərrüat: metodlar bütün Nodelər üçün ümumidir, lakin Node-da biz həm elementə, həm də atributa malik ola bilərik. Və burada suallar var: bir element hansı dəyərə malik ola bilər? Atribut hansı törəmə qovşaqlara malik ola bilər? Digərləri isə ardıcıl deyil. Və hər şey olduqca sadədir: hər bir üsul Node növündən asılı olaraq işləyəcək . Qarışıq qalmamaq üçün təbii ki, məntiqdən istifadə etmək kifayətdir. Məsələn: atributlar hansı xüsusiyyətlərə malik ola bilər? Elementin başqa hansı mənası var? Bununla belə, hər şeyi özünüz sınamamaq üçün rəsmi sənədlərdə Node növündən asılı olaraq hər bir metodun necə işlədiyinə dair çox faydalı bir cədvəl var: Keyfiyyət pis oldu, buna görə də sənədlərə keçid var (cədvəl: Səhifənin yuxarı hissəsi): Node Documentation Xatırlamaq lazım olan ən vacib şey:
  1. YALNIZ elementlərin atributları var.
  2. Elementlərin mənası yoxdur.
  3. Element qovşağının adı etiketin adı ilə, atribut qovşağının adı isə atributun adı ilə eynidir.
<h2>DOM (Sənəd Obyekt Modeli) - TƏCRÜBƏ</h2>Praktik hissədə biz XML-də məlumat axtarışı üzrə müxtəlif növ tapşırıqları təhlil edəcəyik. Rahatlığı müqayisə etmək üçün əvvəlki məqalədən də iki tapşırıq götürdük. Başlayaq və idxaldan başlamaq yaxşı olardı:
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;
Mən idxalı təmin edirəm ki, sinifləri qarışdırmayasınız :) Tapşırıq №1 - bütün işçilər haqqında məlumat əldə edib aşağıdakı XML faylından konsola çıxarmalıyıq:
<?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>
Gördüyümüz kimi, işçi elementlərində saxlanılan bütün məlumatlara sahibik. Onu proqramımızın bir yerində saxlamaq üçün bir sinif yaradaq 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;
    }
}
İndi məlumatların saxlanması üçün strukturun təsvirinə sahib olduğumuz üçün işçiləri saxlayacaq kolleksiyaya ehtiyacımız var. Onu kodun özündə yaradacağıq. Biz həmçinin XML-imizə əsaslanan Sənəd yaratmalıyıq:
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"));
    }
}
Sənədi aldıqdan sonra XML faylının bütün strukturu üzərində qeyri-məhdud səlahiyyətimiz var. İstənilən vaxt istənilən elementi əldə edə, istənilən məlumatı yoxlamaq üçün geri qayıda və ümumiyyətlə, SAX-da olduğundan daha çevik yanaşma edə bilərik. Bu tapşırığın kontekstində biz sadəcə bütün işçi elementlərini çıxarmalı və sonra onlar haqqında bütün məlumatları çıxarmalıyıq. Bu olduqca sadədir:
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()));
    }
}
Bu həllin təsviri həlldə düzdür. Kodla tanış olduqdan sonra nəzəriyyəyə qayıtmaq və onu yenidən oxumaq məsləhətdir. Əslində hər şey instinktiv olaraq aydındır. Şərhləri diqqətlə oxuyun və heç bir sualınız olmasın, əgər varsa, şərhlərdə yaza bilərsiniz, cavab verəcəm və ya linkə və ya sadəcə IDEA-nı işə salın və əgər varsa, kodla özünüz oynamağa çalışın. sən hələ belə etməmisən. Beləliklə, kodu işlətdikdən sonra aşağıdakı nəticəni əldə etdik:
Информации о сотруднике: 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.
Gördüyünüz kimi, tapşırıq uğurla tamamlandı! Gəlin növbəti tapşırığa keçək :) Tapşırıq No 2 - konsoldan elementin adı daxil edilir, onun haqqında onun daxilindəki bütün elementlər və onların atributları haqqında aşağıdakı XML faylından məlumatı göstərmək lazımdır:
<?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>
Hər şey olduqca sadədir: elementi saydığımız adı ilə almalıyıq və sonra bütün uşaq qovşaqlarından keçməliyik. Bunu etmək üçün elementlər olan bütün uşaq qovşaqlarının bütün uşaq qovşaqlarını təkrarlamaq lazımdır. Bu problemin həlli:
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());
        }
    }
}
Həllin bütün təsviri şərhlərdədir, amma nəzəriyyədən bir şəkildən bir nümunə istifadə edərək istifadə etdiyimiz yanaşmanı bir az qrafik şəkildə göstərmək istərdim. Biz güman edəcəyik ki, html teqi haqqında məlumatı göstərməliyik. Gördüyünüz kimi, ağacın kökündən yuxarıdan aşağıya doğru getməliyik. Bütün xətlər qovşaqlardır. Həlldə biz istənilən elementin əvvəlindən onun bütün qovşaqlarından rekursiv şəkildə keçəcəyik və əgər onun qovşaqlarından biri elementdirsə, biz də bu elementin bütün qovşaqlarını təkrarlayırıq. Beləliklə, kodu işlətdikdən sonra kök element üçün aşağıdakı çıxışı əldə etdik:
Элемент был найден!
Найден элемент: 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
Problem uğurla həll edildi! Tapşırıq №3 – tələbələr, professorlar və işçilər haqqında məlumatın saxlandığı aşağıdakı XML faylından məlumatı oxuyub konsola çıxarmaq lazımdır:
<?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>
Tapşırıq olduqca sadə, lakin maraqlıdır. Birincisi, biz 4 sinif yaratmalıyıq: işçi, professor və tələbə, eləcə də ümumi mücərrəd sinif İnsan hər bir sinifdən dəyişən ad dəyişənini ortaq məxrəc altında gətirmək üçün: Abstrakt valideyn sinfi
public abstract class Human {
    private String name;

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

    public String getName() {
        return name;
    }
}
tələbə
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;
    }
}
professor
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;
    }
}
işçi
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;
    }
}
Artıq dərslərimiz hazırdır, sadəcə olaraq tələbə, professor və üzv elementlərinin hamısını əldə etmək üçün kod yazmaq və onların atributlarını əldə etmək kifayətdir. Saxlama üçün biz hamı üçün ümumi olan ana sinif obyektlərini saxlayacaq kolleksiyadan istifadə edəcəyik - İnsan. Və beləliklə, bu problemin həlli:
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;
            }
        }
    }
}
Qeyd edək ki, sənəddən bütün bu elementləri əldə etmək üçün bizə yalnız element adı lazımdır. Bu, sizə lazım olan məlumatı tapmaq prosesini xeyli asanlaşdırır. Kod haqqında bütün məlumatlar şərhlərdə qeyd olunur. Əvvəlki tapşırıqlarda olmayan yeni heç nə istifadə olunmayıb. Kod çıxışı:
Профессор 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
Problem həll edildi! DOM-dan nə vaxt və nə vaxt SAX-dan istifadə etmək tövsiyələri Bu alətlər arasındakı fərq funksionallıq və sürətdədir. Əgər sizə daha çevik funksionallıq lazımdırsa və proqram performansını israf etməyə imkanınız varsa, seçiminiz DOM-dur, lakin əsas məqsədiniz yaddaş xərclərini azaltmaqdırsa, DOM ən yaxşı seçim deyil, çünki o, XML faylından bütün məlumatları oxuyur və saxlayır. Buna görə də, SAX ardıcıl oxu metodu daha ucuzdur. Qısaca: performansa ehtiyacınız varsa - SAX, funksionallıq - DOM. <h2>Nəticə</h2>Hər bir proqramçının öz alətləri var və tapşırıqdan asılı olaraq müəyyən alətlərdən istifadə etməlisiniz. SAX və DOM haqqında məqalələrdə məqsədim sizə XML fayllarından məlumat çıxarmağı və onları sizə lazım olan şəkildə emal etməyi öyrətmək idi. Bununla belə, bu məqalələri oxumuş olsanız belə, bu vasitələrdən necə istifadə edəcəyinizi öyrəndiyinizi iddia edə bilməzsiniz. Siz məşq etməli, məqalələrdən kodu sınamalı, onun necə işlədiyini başa düşməli və özünüz bir şey yazmağa çalışmalısınız. Axı, ən vacib şey təcrübədir. Son məqalə yaxın günlərdə və yəqin ki, müsabiqə bitdikdən sonra dərc olunacaq və JAXB-yə həsr olunacaq. JAXB proqramınızda obyektləri XML formatında saxlamaq üçün bir vasitədir. Hamısı budur, ümid edirəm ki, bu məqalə faydalı oldu və proqramlaşdırmanızda uğurlar :) Əvvəlki məqalə: [Müsabiqə] Java Proqramçısı üçün XML Əsasları - Part 3.1/3 - SAX
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION