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

Java dasturchi uchun XML asoslari. 3-qismning 3.2-qismi - DOM

Guruhda nashr etilgan
<h2>Kirish</h2>Maqolaning barcha o'quvchilariga salom, bu qism DOMga bag'ishlangan. Keyingisi JAXB ga bag'ishlanadi va shu bilan XML asoslari sikli tugallanadi. Avval bir oz nazariya bo'ladi, keyin esa faqat amaliyot. Qani boshladik. <h2>DOM (Hujjat ob'ekt modeli) - NAZARIYA</h2>DOM ishlov beruvchisi shunday yaratilganki, u bir vaqtning o'zida barcha XML-ni o'qiydi va uni saqlaydi, biz osongina harakat qilishimiz mumkin bo'lgan daraxt ko'rinishidagi ierarxiyani yaratadi. va bizga kerak bo'lgan elementlarga kirish. Shunday qilib, biz yuqori elementga havola berilgan holda, uning ichki elementlariga barcha havolalarni olishimiz mumkin. Bundan tashqari, element ichida joylashgan elementlar ushbu elementning bolalari va bu ularning ota-onasidir. Barcha XML ni xotiraga o‘qib chiqqach, biz shunchaki uning tuzilishi bo‘ylab sayohat qilamiz va kerakli amallarni bajaramiz. Java-da DOM-ning dasturlash qismi haqida bir oz: DOM turli ma'lumotlarni tasvirlash uchun yaratilgan ko'plab interfeyslarga ega. Ushbu interfeyslarning barchasi bitta umumiy interfeysni meros qilib oladi - Node. Chunki, aslida, DOM-da eng keng tarqalgan ma'lumotlar turi bu tugun bo'lib, u har qanday narsa bo'lishi mumkin. Har bir tugun ma'lumotni olish uchun quyidagi foydali usullarga ega:
  1. getNodeName- xost nomini oling.
  2. getNodeValue- tugun qiymatini oling.
  3. getNodeType- tugun turini oling.
  4. getParentNode– berilgan tugun joylashgan tugunni oling.
  5. getChildNodes– barcha olingan tugunlarni oling (ma'lum bir tugun ichidagi tugunlar).
  6. getAttributes- barcha tugun atributlarini olish.
  7. getOwnerDocument– ushbu tugunning hujjatini oling.
  8. getFirstChild/getLastChild- birinchi/oxirgi olingan tugunni oling.
  9. getLocalName– prefikssiz nom olish uchun nomlar maydonini qayta ishlashda foydalidir.
  10. getTextContent- element ichidagi barcha matnni va berilgan element ichidagi barcha elementlarni, shu jumladan qatorlar va bo'shliqlarni qaytaradi.
9-usul bo'yicha eslatma: agar siz DocumentFactory'da nom maydonini qayta ishlashni boshlash uchun setNamespaceAware(true) usulidan foydalanmasangiz, u har doim null bo'ladi. Endi muhim tafsilot: usullar barcha tugunlar uchun umumiydir, ammo tugunda biz ham elementga, ham atributga ega bo'lishimiz mumkin. Va bu erda savollar mavjud: element qanday qiymatga ega bo'lishi mumkin? Atribut qanday hosila tugunlariga ega bo'lishi mumkin? Va boshqalar barqaror emas. Va hamma narsa juda oddiy: har bir usul tugun turiga qarab ishlaydi . Adashib qolmaslik uchun, albatta, mantiqdan foydalanish kifoya. Masalan: atributlar qanday atributlarga ega bo'lishi mumkin? Element yana qanday ma'noga ega? Biroq, hamma narsani o'zingiz sinab ko'rmaslik uchun, rasmiy hujjatlarda har bir usul tugun turiga qarab qanday ishlashi haqida juda foydali jadval mavjud: Sifat yomon bo'lib chiqdi, shuning uchun bu erda hujjatlarga havola (jadval: sahifaning yuqori qismi): Tugun hujjatlari Esda tutilishi kerak bo'lgan eng muhim narsa:
  1. FAQAT elementlar atributlarga ega.
  2. Elementlarning ma'nosi YO'Q.
  3. Element tugunining nomi teg nomi bilan bir xil, atribut tugunining nomi esa atribut nomi bilan bir xil.
<h2>DOM (Hujjat ob'ekt modeli) - AMALIYAT</h2>Amaliy qismda biz XMLda ma'lumot qidirish bo'yicha har xil turdagi vazifalarni tahlil qilamiz. Qulaylikni solishtirish uchun avvalgi maqoladan ikkita vazifani ham oldik. Keling, boshlaylik va importdan boshlash yaxshi bo'lardi:
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;
Sinflarni chalkashtirmaslik uchun importni taqdim etaman :) Vazifa №1 - barcha xodimlar haqida ma'lumot olishimiz va uni quyidagi XML faylidan konsolga chiqarishimiz kerak:
<?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>
Ko'rib turganimizdek, bizda xodimlarning elementlarida saqlangan barcha ma'lumotlar mavjud. Uni dasturimizning biror joyida saqlash uchun keling, sinf yarataylik 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;
    }
}
Endi bizda ma'lumotlarni saqlash tuzilmasining tavsifi bor, biz xodimlarni saqlaydigan to'plamga muhtojmiz. Biz uni kodning o'zida yaratamiz. Shuningdek, biz XML asosida Hujjat yaratishimiz kerak:
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"));
    }
}
Hujjatni olganimizdan so'ng, biz XML faylining butun tuzilishi bo'yicha cheksiz vakolatga egamiz. Biz istalgan vaqtda istalgan elementni olishimiz, istalgan maʼlumotni tekshirish uchun orqaga qaytishimiz va umuman olganda, SAXʼdagidan koʻra moslashuvchanroq yondashuv. Ushbu vazifa doirasida biz faqat xodimlarning barcha elementlarini ajratib olishimiz kerak va keyin ular haqida barcha ma'lumotlarni chiqarib olishimiz kerak. Bu juda oddiy:
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()));
    }
}
Ushbu yechimning tavsifi to'g'ri yechimda. Kodni ko'rib chiqqandan so'ng, nazariyaga qaytish va uni qayta o'qish tavsiya etiladi. Aslida, hamma narsa instinktiv tarzda aniq. Izohlarni diqqat bilan o'qing va hech qanday savol bo'lmasligi kerak, agar mavjud bo'lsa, sharhlarda yozishingiz mumkin, men javob beraman, yoki havolada yoki shunchaki IDEA ni ishga tushiring va agar bo'lsa o'zingiz kod bilan o'ynashga harakat qiling. siz hali bunday qilmagansiz. Shunday qilib, kodni ishga tushirgandan so'ng biz quyidagi natijani oldik:
Информации о сотруднике: Name - Maksim, должность - Middle Software Developer.
Информации о сотруднике: Name - Ivan, должность - Junior Software Developer.
Информации о сотруднике: Name - Franklin, должность - Junior Software Developer.
Информации о сотруднике: Name - Herald, должность - Middle Software Developer.
Информации о сотруднике: Name - Adam, должность - Middle Software Developer.
Информации о сотруднике: Name - Leroy, должность - Junior Software Developer.
Ko'rib turganingizdek, vazifa muvaffaqiyatli bajarildi! Keyingi vazifaga o'tamiz :) 2-topshiriq - konsoldan element nomi kiritiladi, bu haqda siz uning ichidagi barcha elementlar va ularning atributlari haqidagi ma'lumotlarni quyidagi XML faylidan ko'rsatishingiz kerak:
<?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>
Hammasi juda oddiy: biz elementni biz hisoblaydigan nomi bilan olishimiz kerak, so'ngra barcha tugunlar orqali o'tishimiz kerak. Buni amalga oshirish uchun siz element bo'lgan barcha tugunlarning barcha tugunlari orqali takrorlashingiz kerak. Ushbu muammoning yechimi:
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());
        }
    }
}
Yechimning to'liq tavsifi sharhlarda, lekin men nazariyadagi rasmdan misol yordamida biz qo'llagan yondashuvni biroz grafik tarzda ko'rsatmoqchiman. Biz html tegi haqidagi ma'lumotlarni ko'rsatishimiz kerak deb hisoblaymiz. Ko'rib turganingizdek, daraxtning ildizidan yuqoridan pastgacha borishimiz kerak. Barcha chiziqlar tugunlardir. Yechimda biz kerakli elementning boshidan uning barcha tugunlari bo'ylab rekursiv ravishda o'tamiz va agar uning tugunlaridan biri element bo'lsa, biz ham ushbu elementning barcha tugunlari orqali takrorlaymiz. Shunday qilib, kodni ishga tushirgandan so'ng biz ildiz elementi uchun quyidagi natijani oldik:
Элемент был найден!
Найден элемент: 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
Muammo muvaffaqiyatli hal qilindi! 3-topshiriq – talabalar, professor-o‘qituvchilar va xodimlar haqidagi ma’lumotlar saqlanadigan quyidagi XML faylidan ma’lumotlarni o‘qib chiqishingiz va konsolga chiqarishingiz kerak:
<?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>
Vazifa juda oddiy, ammo qiziqarli. Birinchidan, biz 4 ta sinfni yaratishimiz kerak: xodim, professor va talaba, shuningdek, umumiy mavhum sinf Inson har bir sinfdan o'zgaruvchining nomini umumiy maxraj ostida olib kelish uchun: Abstrakt ota-onalar sinfi
public abstract class Human {
    private String name;

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

    public String getName() {
        return name;
    }
}
Talaba
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;
    }
}
Xodim
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;
    }
}
Endi bizning darslarimiz tayyor, biz talaba, professor va a'zoning barcha elementlarini olish uchun kod yozishimiz kerak va keyin ularning atributlarini olishimiz kerak. Saqlash uchun biz hamma uchun umumiy bo'lgan ota-sinf ob'ektlarini saqlaydigan to'plamdan foydalanamiz - Human. Shunday qilib, bu muammoni hal qilish:
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;
            }
        }
    }
}
E'tibor bering, ushbu elementlarning barchasini hujjatdan olish uchun bizga faqat element nomi kerak. Bu sizga kerakli ma'lumotlarni topish jarayonini sezilarli darajada osonlashtiradi. Kod haqidagi barcha ma'lumotlar sharhlarga kiritilgan. Oldingi vazifalarda mavjud bo'lmagan yangi narsa ishlatilmadi. Kod chiqishi:
Профессор 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
Muammo hal qilindi! DOM-dan qachon foydalanish va SAX-dan qachon foydalanish bo'yicha tavsiyalar Ushbu vositalar orasidagi farq funksionallik va tezlikda. Agar sizga ko'proq moslashuvchan funksionallik kerak bo'lsa va dastur ishlashini behuda sarflasangiz, sizning tanlovingiz DOM, lekin asosiy maqsadingiz xotira xarajatlarini kamaytirish bo'lsa, DOM eng yaxshi tanlov emas, chunki u XML faylidagi barcha ma'lumotlarni o'qiydi va saqlaydi. Shuning uchun, SAX ketma-ket o'qish usuli arzonroq. Qisqacha: agar sizga ishlash kerak bo'lsa - SAX, funksionallik - DOM. <h2>Xulosa</h2>Har bir dasturchi o'z vositalariga ega va vazifaga qarab siz ma'lum vositalardan foydalanishingiz kerak. SAX va DOM haqidagi maqolalarda mening maqsadim sizga XML fayllaridan ma'lumot olish va ularni kerakli tarzda qayta ishlashni o'rgatish edi. Biroq, agar siz ushbu maqolalarni o'qigan bo'lsangiz ham, ushbu vositalardan qanday foydalanishni o'rgangan deb da'vo qila olmaysiz. Siz mashq qilishingiz, maqolalardagi kodni sinab ko'rishingiz, uning qanday ishlashini tushunishingiz va o'zingiz biror narsa yozishga harakat qilishingiz kerak. Axir, eng muhimi - bu amaliyot. Oxirgi maqola yaqin kunlarda va, shekilli, tanlov tugagandan so'ng chop etiladi va JAXBga bag'ishlanadi. JAXB - bu sizning dasturingizdagi ob'ektlarni XML formatida saqlash uchun vositadir. Hammasi shu, umid qilamanki, ushbu maqola foydali bo'ldi va dasturlashda omad tilaymiz :) Oldingi maqola: [Raqobat] Java dasturchisi uchun XML asoslari - 3 qismning 3.1 qismi - SAX
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION