JavaRush/Java блог/Random UA/Основи XML для програмістів Java. Частина 2 із 3
Ярослав
40 рівень

Основи XML для програмістів Java. Частина 2 із 3

Стаття з групи Random UA
учасників

Вступ

Здрастуйте, дорогі читачі моєї статті. Це вже друга стаття з циклу про XML, і в цій статті розповідатиме про XML Namespace та XML Schema.
Основи XML
Буквально недавно, мені самому нічого про це відомо не було, проте я подужав чимало матеріалу і намагатимуся пояснити простими словами ці дві важливі теми. Відразу хочу сказати, що схеми - дуже просунутий механізм валідації XML документів і значно функціональніший, ніж DTD, тому повного його вивчення від і до цього не буде. Давайте приступати :)

XML Namespace

Namespace означає «простір імен», проте в цій статті я часто підмінюватиму російський вираз на просто namespace, бо це коротше і комфортніше для розуміння. XML Namespace – це технологія, основна мета якої – зробити так, щоб усі елементи були унікальними у XML файлі та не було плутанини. І так, як це Java курси, то така ж технологія є і Java - пакети. Якби можна було помістити два класи з однаковим ім'ям поруч і використовувати їх, то як ми визначабо, який клас нам потрібен? Ця проблема вирішена пакетами - ми можемо просто розмістити класи в різні пакети та імпортувати їх звідти, точно вказавши ім'я потрібного пакета та шлях до нього, або просто вказавши повний шлях до потрібного класу. Основи XML для програмістів Java.  Частина 2 з 3 - 1Тепер ми можемо зробити так:

public class ExampleInvocation {
    public static void main(String[] args) {
        // створення экземпляра класса из первого пакета.
        example_package_1.Example example1 = new example_package_1.Example();
        
        // створення экземпляра класса из второго пакета.
        example_package_2.Example example2 = new example_package_2.Example();
        
        // створення экземпляра класса из третьего пакета.
        example_package_3.Example example3 = new example_package_3.Example();
    }
}
У XML Namespace все приблизно так само, тільки трохи інакше. Суть така ж: якщо елементи однакові (як класи), то ми просто повинні використовувати їх у різних namespace'ах (вказувати пакети), тоді навіть якщо імена елементів (класів) збігатимуться, ми все одно будемо звертатися до конкретного елементу з простору ( пакета). Для прикладу: у нас у XML є два елементи – передбачення (oracle) та БД Oracle.

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <oracle>
        <connection value="jdbc:oracle:thin:@10.220.140.48:1521:test1" />
        <user value="root" />
        <password value="111" />
    </oracle>
    
    <oracle>
        Сегодня вы будете заняты весь день.
    </oracle>
</root>
І коли ми оброблятимемо даний XML файл, ми будемо серйозно заплутані, якщо замість бази даних нам прийде передбачення, і назад теж. Щоб дозволити колізію елементів, ми можемо кожному з них виділити свій власний простір, щоб розрізняти їх. Для цього є спеціальний атрибут - xmlns: префікс = "унікальне значення для namespace". Після цього ми можемо використовувати префікс перед елементами, щоб вказувати, що він є частиною цього namespace (по суті, ми повинні створити шлях до пакету - namespace, а потім перед кожним елементом вказувати префіксом, до якого пакета він належить).

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <database:oracle xmlns:database="Unique ID #1">
        <connection value="jdbc:oracle:thin:@10.220.140.48:1521:test1" />
        <user value="root" />
        <password value="111" />
    </database:oracle>

    <oracle:oracle xmlns:oracle="Unique ID #2">
        Сегодня вы будете заняты весь день.
    </oracle:oracle>
</root>
У цьому прикладі ми оголосабо два простори імен: database і oracle. Тепер перед елементами можна використовувати префікси namespace'ів. Не треба лякатися, якщо зараз щось незрозуміло. Насправді це дуже просто. Спочатку я хотів написати цю частину статті швидше, проте після середи я вирішив, що потрібно приділити більше уваги цій темі, тому що тут легко заплутатися або в чомусь не розібратися. Зараз буде багато уваги приділено атрибуту xmlns. І так, ще приклад:

<?xml version="1.0" encoding="UTF-8"?>
<root xmlns="https://www.standart-namespace.com/" xmlns:gun="https://www.gun-shop.com/" xmlns:fish="https://www.fish-shop.com/">
    <gun:shop>
        <gun:guns>
            <gun:gun name="Revolver" price="1250$" max_ammo="7" />
            <gun:gun name="M4A1" price="3250$" max_ammo="30" />
            <gun:gun name="9mm Pistol" price="450$" max_ammo="12" />
        </gun:guns>
    </gun:shop>

    <fish:shop>
        <fish:fishes>
            <fish:fish name="Shark" price="1000$" />
            <fish:fish name="Tuna" price="5$" />
            <fish:fish name="Capelin" price="1$" />
        </fish:fishes>
    </fish:shop>
</root>
Ви можете бачити звичайний XML, де використовуються простори gun для унікальних елементів магазину зброї і fish для унікальних елементів рибальського магазину. Можна побачити, що створивши простори, ми використовували один елемент shop відразу до двох різних речей – магазину зброї та магазину риби, і нам достеменно відомо, що це за магазин завдяки тому, що оголосабо простору. Найцікавіше розпочнеться у схемах, коли ми зможемо в такий спосіб ще валідувати різні структури з одними елементами. xmlns - атрибут для оголошення namespace'а, вказувати його можна в будь-якому елементі. Приклад оголошення namespace'а:

xmlns:shop= «https://barber-shop.com/»
Після двокрапки знаходиться префікс - це посилання на простір, яке потім може використовуватися перед елементами, щоб вказувати, що вони родом із цього простору. Значення xmlns має бути УНІКАЛЬНОЮ РЯДКОЮ. Це дуже важливо розуміти: дуже часто використовуються посилання на сайти або URI, щоб оголосити namespace. Це правило є стандартом, так як URI або URL посилання є унікальними, але саме зараз дуже заплутує. Просто запам'ятайте: значенням може бути БУДЬ-ЯКИЙ рядок, який ви захочете, але для точної унікальності та стандарту потрібно використовувати URL або URI адресаи. Те, що можна використовувати будь-які рядки, показано в прикладі oracle:

xmlns:oracle="Unique ID #2"
xmlns:database="Unique ID #1"
Коли ви оголошуєте namespace, ви можете його використовувати в самому елементі і у всіх елементах усередині нього, тому оголошені в root елементі namespace'и можна використовувати у всіх елементах. Це можна побачити в останньому прикладі, і ось більш конкретний приклад:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <el1:element1 xmlns:el1="Element#1 Unique String">
        <el1:innerElement>

        </el1:innerElement>
    </el1:element1>


    <el2:element2 xmlns:el2="Element#2 Unique String">
        <el2:innerElement>

        </el2:innerElement>
    </el2:element2>


    <el3:element3 xmlns:el3="Element#3 Unique String">
        <el3:innerElement>
            <el1:innerInnerElement> <!-- Так нельзя, потому что пространство el1 объявлено только в первом элементе, потому может использовать только внутри первого елемента и его внутренних элементов. -->
                
            </el1:innerInnerElement>
        </el3:innerElement>
    </el3:element3>
</root>
Тут важлива деталь: існує також стандартний namespace в root елементі. Якщо ви оголосабо інші namespace'и, ви перети стандартне і не можете його використовувати. Тоді перед root елементом потрібно поставити якийсь префікс простору, який ви оголосабо раніше. Однак це можна так само обхитрити: ви можете оголосити стандартний простір явно. Достатньо просто не використовувати префікс після xmlns, а одразу записати якесь значення, і всі ваші елементи без префіксу стануть належати саме цьому namespace'у. В останньому прикладі це було використано:

<root xmlns="https://www.standart-namespace.com/" xmlns:gun="https://www.gun-shop.com/" xmlns:fish="https://www.fish-shop.com/">
Ми оголосабо стандартний простір явно, щоб уникнути необхідності використовувати gun чи fish, оскільки рут елемент не є сутністю ні рибальського магазину, ні збройового, тому використання будь-якого простору було б вже логічно неправильним. Далі: якщо ви створабо xmlns:a та xmlns:b, але вони мають одне значення, то це однаковий простір і вони не унікальні. Тому і потрібно використовувати завжди унікальні значення, адже порушення цього правила може створити велику кількість помилок. Наприклад, якби в нас було так оголошено простору:

xmlns="https://www.standart-namespace.com/" xmlns:gun="https://www.gun-shop.com/" xmlns:fish="https://www.gun-shop.com/"
То наш рибальський магазин став би збройовим, а префікс був би все ще рибного магазинчика. Це основні моменти просторів. Я досить багато часу витратив на те, щоб зібрати їх усі і скоротити, а потім ясно висловити, оскільки інформація про простори в Інтернеті дуже величезна і часто одна вода, тому більшість всього, що тут є – я дізнався це сам пробами та помилками . Якщо у вас залишабося питання, можете спробувати ознайомитися з матеріалами за посиланнями в кінці статті.

XML Schema

Відразу хочу сказати, що у цій статті буде лише верхівка айсберга, оскільки тема дуже велика. Якщо ви захочете ознайомитися докладніше зі схемами та навчитися писати їх самому будь-якої складності, то наприкінці статті буде посилання, де буде все про різні типи, обмеження, розширення тощо. Почати хочу з теорії. Схеми мають формат .xsd (xml scheme definition) і є більш просунутою та популярною альтернативою DTD: вони здатні так само створювати елементи, описувати їх і так далі. Проте, додано дуже багато бонусів: перевірка типів, підтримка неймспейсів та ширший функціонал. Помнете, коли ми говорабо про DTD, там був мінус, що він не підтримує простору? Тепер, коли ми це вивчабо, поясню: якби можна було імпортувати дві і більше схеми з DTD, де були б однакові елементи, у нас були б колізії (збіги) і не можна було б їх використати взагалі, адже неясно, який елемент нам потрібен. У XSD цю проблему вирішено, адже ви можете імпортувати схеми в один конкретний простір і використовувати його. По суті, кожна XSD схема має цільовий простір, який означає, в який простір повинна бути записана схема в XML файлі. Таким чином, у самому XML файлі нам потрібно просто створити ці заздалегідь визначені у схемах простору та призначити префікси для них, а потім підключити до кожного з них потрібні схеми, після чого ми можемо спокійно використовувати елементи зі схеми, підставляючи префікси з того простору, куди ми імпортували схеми. Отже, у нас є приклад: Ви можете імпортувати схеми в один конкретний простір і використовувати його. По суті, кожна XSD схема має цільовий простір, який означає, в який простір повинна бути записана схема в XML файлі. Таким чином, у самому XML файлі нам потрібно просто створити ці заздалегідь визначені у схемах простору та призначити префікси для них, а потім підключити до кожного з них потрібні схеми, після чого ми можемо спокійно використовувати елементи зі схеми, підставляючи префікси з того простору, куди ми імпортували схеми. Отже, у нас є приклад: Ви можете імпортувати схеми в один конкретний простір і використовувати його. По суті, кожна XSD схема має цільовий простір, який означає, в який простір повинна бути записана схема в XML файлі. Таким чином, у самому XML файлі нам потрібно просто створити ці заздалегідь визначені у схемах простору та призначити префікси для них, а потім підключити до кожного з них потрібні схеми, після чого ми можемо спокійно використовувати елементи зі схеми, підставляючи префікси з того простору, куди ми імпортували схеми. Отже, у нас є приклад: у самому XML файлі нам потрібно просто створити ці заздалегідь визначені в схемах простору і призначити префікси для них, а потім підключити до кожного з них потрібні схеми, після чого ми можемо спокійно використовувати елементи зі схеми, підставляючи префікси з того простору, куди імпортували схеми . Отже, у нас є приклад: у самому XML файлі нам потрібно просто створити ці заздалегідь визначені в схемах простору і призначити префікси для них, а потім підключити до кожного з них потрібні схеми, після чого ми можемо спокійно використовувати елементи зі схеми, підставляючи префікси з того простору, куди імпортували схеми . Отже, у нас є приклад:

<?xml version="1.0" encoding="UTF-8"?>
<house>
    <address>ул. Есенина, дом №5</address>
    <owner name="Ivan">
        <telephone>+38-094-521-77-35</telephone>
    </owner>
</house>
Ми хочемо валідувати його за допомогою схеми. Для початку нам потрібна схема:

<?xml version="1.0"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="https://www.nedvigimost.com/">
    <element name="house">
        <complexType>
            <sequence>
                <element name="address" type="string" maxOccurs="unbounded" minOccurs="0" />
                <element name="owner" maxOccurs="unbounded" minOccurs="0" >
                    <complexType>
                        <sequence>
                            <element name="telephone" type="string" />
                        </sequence>
                        <attribute name="name" type="string" use="required"/>
                    </complexType>
                </element>
            </sequence>
        </complexType>
    </element>
</schema>
Як ви бачите, схеми – це також XML файли. Ви прямо XML мовою розписуєте те, що вам потрібно. Ця схема здатна валідувати XML файл з прикладу вище. Наприклад: якщо у овнера не буде імені, то схема це побачить. Також, завдяки елементу sequence, завжди має йти спочатку адресаа, а потім власник будинку. Є елементи звичайні та комплексні. Звичайні елементи – це елементи, які містять лише якийсь тип даних. Приклад:

<element name="telephone" type="string" />
Так ми оголошуємо елемент, який зберігає рядок. Інших елементів бути всередині цього елемента не повинно. Також є комплексні елементи. Комплексні елементи здатні зберігати в собі інші елементи, атрибути. Тоді тип вказувати не потрібно, а достатньо всередині елемента почати комплексний тип писати.

<complexType>
    <sequence>
        <element name="address" type="string" maxOccurs="unbounded" minOccurs="0" />
        <element name="owner" maxOccurs="unbounded" minOccurs="0" >
            <complexType>
                <sequence>
                    <element name="telephone" type="string" />
                </sequence>
                <attribute name="name" type="string" use="required"/>
            </complexType>
        </element>
    </sequence>
</complexType>
Так само можна було вчинити інакше: можна було створити комплексний тип окремо, а потім підставляти його в type. Тільки під час написання цього прикладу чомусь треба було оголосити простір під якимось префіксом, а не використовувати стандартний. Загалом, вийшло ось так:

<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="https://www.nedvigimost.com/">
    <xs:element name="house" type="content" />

    <xs:complexType name="content">
        <xs:sequence>
            <xs:element name="address" type="xs:string" maxOccurs="unbounded" minOccurs="0" />
            <xs:element name="owner" maxOccurs="unbounded" minOccurs="0" >
                <xs:complexType>
                    <xs:sequence>
                        <xs:element name="telephone" type="xs:string" />
                    </xs:sequence>
                    <xs:attribute name="name" type="xs:string" use="required"/>
                </xs:complexType>
            </xs:element>
        </xs:sequence>
    </xs:complexType>
</xs:schema>
Таким чином, ми можемо створювати наші власні типи окремо, а потім підставляти їх кудись у атрибут type. Це дуже зручно, тому що дозволяє використовувати один тип у різних місцях. Хотілося б поговорити про підключення схем і закінчити на цьому. Існують два способи підключити схему: в конкретний простір і просто підключити.

Перший спосіб підключення схеми

Перший спосіб має на увазі, що у схеми є конкретний цільовий простір. Воно вказується за допомогою атрибута targetNamespace у scheme елемента. Тоді достатньо створити ЦЕ НАЙБІЛЬШЕ простір у XML файлі, після чого «завантажити» туди схему:

<?xml version="1.0" encoding="UTF-8"?>
<nedvig:house xmlns:nedvig="https://www.nedvigimost.com/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://www.nedvigimost.com/ example_schema1.xsd">
    <address>ул. Есенина, дом №5</address>
    <owner name="Ivan">
        <telephone>+38-094-521-77-35</telephone>
    </owner>
</nedvig:house>
Важливо розуміти два рядки:

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemeLocation="https://www.nedvigimost.com/ example_schema1.xsd"
Перший рядок - просто запам'ятайте його. Вважайте, що це об'єкт, що допомагає завантажувати схеми туди, куди треба. Другий рядок – вже конкретне завантаження. schemaLocation приймає список значень виду значення – значення, розділені пробілом. Перший аргумент – простір імен, який має відповідати цільовому простору імен у схемі (значення targetNamespace). Другий аргумент – відносно чи абсолютний шлях до схеми. І так, як це СПИСОК значення, то ви можете після схеми в прикладі поставити пробіл, і знову ввести цільовий простір та ім'я іншої схеми, і скільки захочете. Важливо:щоб схема потім валідувала щось, вам потрібно оголосити цей простір і з префіксом використовувати. Подивіться уважно останній приклад:

<?xml version="1.0" encoding="UTF-8"?>
<nedvig:house xmlns:nedvig="https://www.nedvigimost.com/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://www.nedvigimost.com/ example_schema1.xsd">
    <address>ул. Есенина, дом №5</address>
    <owner name="Ivan">
        <telephone>+38-094-521-77-35</telephone>
    </owner>
</nedvig:house>
Ми створабо цільовий простір на префіксі nedvig, а потім використовували його. Таким чином, наші елементи почали валідуватись, оскільки ми почали використовувати простір, куди посилається цільовий простір схеми.

Другий спосіб підключення схеми

Другий спосіб підключення схеми передбачає, що схема немає конкретного цільового простору. Тоді ви можете просто підключити її до файлу XML і вона буде валідувати його. Робиться майже так, тільки ви можете не оголошувати простору взагалі в XML файлі, а просто підключити схему.

<?xml version="1.0" encoding="UTF-8"?>
<house xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="example_schema1.xsd">
    <address>ул. Есенина, дом №5</address>
    <owner name="Ivan">
        <telephone>+38-094-521-77-35</telephone>
    </owner>
</house>
Як ви бачите, робиться це за допомогою noNamespaceSchemaLocation і вказівкою шляху до схеми. Навіть якщо схема не має цільового простору, документ валідуватиметься. І останній штрих: ми можемо імпортувати до схем інших схем, після чого використовувати елементи з однієї схеми в іншій. Таким чином, ми можемо використовувати в одних схемах елементи, які вже є в інших. Приклад:

Схема, де оголошується тип owner:


<?xml version="1.0" encoding="UTF-8" ?>
<schema targetNamespace="bonus" xmlns="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
        <complexType name="owner">
            <all>
                <element name="telephone" type="string" />
            </all>
            <attribute name="name" type="string" />
        </complexType>
</schema>

Друга схема, де використовується тип власника з першої схеми:


<?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="main" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:bonus="bonus" elementFormDefault="qualified">
    <import namespace="bonus" schemaLocation="xsd2.xsd" />
    <element name="house">
        <complexType>
            <all>
              <element name="address" type="string" />
                <element name="owner" type="bonus:owner" />
            </all>
        </complexType>
    </element>
</schema>
У другій схемі використовується конструкція:

<import namespace="bonus" schemaLocation="xsd2.xsd" />
За допомогою неї ми імпортували типи та елементи з однієї схеми в іншу до простору bonus. Таким чином ми отримали доступ до типу bonus:owner. А в наступному рядку ми його використали:

<element name="owner" type="bonus:owner" />
Так само невелика увага наступного рядка:

elementFormDefault="qualified"
Цей атрибут оголошується в schema і означає, що у XML файлух кожен елемент має оголошуватися з явним префіксом перед нею. Якщо його немає, то нам достатньо оголосити зовнішній елемент із префіксом, а так потрібно виставляти префікси і у всіх елементах усередині, явно вказуючи, що ми використовуємо саме елементи цієї схеми. І ось, власне, приклад XML файлу, що валідується схемою, яка імпортувала іншу схему:

<?xml version="1.0" encoding="UTF-8"?>
<nedvig:house xmlns:nedvig="main" xmlns:bonus="bonus" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="main xsd.xsd">
    <nedvig:address>ул. Есенина, дом №5</nedvig:address>
    <nedvig:owner name="Ivan">
        <bonus:telephone>+38-094-521-77-35</bonus:telephone>
    </nedvig:owner>
</nedvig:house>
У рядку:

<bonus:telephone>+38-094-521-77-35</bonus:telephone>
Нам потрібно явно оголошувати простір імен bonus, що вказує на цільовий простір першої схеми, тому що elementFormDefault у нас в qualified (перевіряти), тому всі елементи повинні явно вказувати свій простір.

Кінець статті

Наступна стаття буде останньою у циклі і там вже буде про обробку XML файлів засобами Java. Ми навчатимемося діставати інформацію різними способами і так далі. Сподіваюся, що ця стаття була корисною і, навіть якщо тут є десь помилки, навчить вас чогось корисного та нового, а може просто дасть можливість краще розуміти XML файли. Для тих, хто хотів би вивчити це детальніше, я вирішив зібрати невеликий набір посилань:
  • XSD Simple Elements - починаючи з цієї статті починайте читати і йдіть вперед, там зібрана вся інформація за схемами і розповідається більш-менш зрозуміло, тільки англійською. Ви можете використовувати перекладач.

  • відео по просторах імен, завжди корисно послухати іншу точку зору на будь-що, якщо перша не зрозуміла.

  • XML простору імен - гарний приклад використання просторів імен та досить укомплектована інформація.

  • Основи XML – простори імен – ще одна невелика стаття щодо просторів імен.

  • Основи використання XML Schema для визначення елементів - теж дуже корисне посилання за схемами, тільки читати потрібно повільно і уважно, вникаючи в матеріал.

На цьому вже точно все, сподіватимусь, що якщо ви захочете дізнатися щось глибше з цього, то посилання вам допоможуть. Я сам тинявся по всіх цих джерелах, вивчаючи весь матеріал, і, загалом, це були найкорисніші з усіх джерел, що я дивився, тому що кожен з них або покращував розуміння того, що я вже прочитав десь в іншому місці, або давав дізнатися про щось нове, проте багато було зроблено саме під час практики. Отже, тим, хто реально хоче розібратися у всьому цьому досить добре, моя порада: вивчіть простір імен, після чого те, як просто підключати схеми до XML файлів, а потім уже те, як прописувати структуру документа в схемах. А головне – практикуйтеся. Всім дякую за увагу та успіхів у програмуванні :) Попередня стаття: [Конкурс] Основи XML для Java програміста - Частина 1 з 3 [ Конкурс ] Основи XML для Java програміста - Частина 3.1 з 3 - SAX
Коментарі
  • популярні
  • нові
  • старі
Щоб залишити коментар, потрібно ввійти в систему
Для цієї сторінки немає коментарів.