XML - очень популярный и гибкий формат в наше время. Каждый программист должен понимать его, это просто must have. Многие технологии завязаны сегодня активно его используют, при чем современные в их числе.
Основы XML для Java программиста - Часть 1 из 3 - 1

Вступление

Здравствуйте, дорогие читатели моей статьи. Сразу хочу сказать, что это только первая статья в моём цикле из трёх статей. Основная цель всего цикла – посвятить каждого читателя в XML и дать, если не полное разъяснение и понимание, то, хотя бы, хороший такой толчок к нему, объяснив основные моменты и вещи. Весь цикл будет для одной номинации – «Внимание к деталям», а разделение на 3 статьи сделано для того, чтобы вмещаться в лимит символов в постах и разделить большое количество материала на более маленькие порции для большего понимания. Первая статья будет посвящена самому XML и что это такое, а так же одному из способов составления схемы для XML файлов – DTD. Для начала, хотелось бы высказать небольшое предисловие для тех, кто вообще еще не знаком с XML: не нужно пугаться. XML не очень сложный и с ним нужно разобраться любому программисту, так как это очень гибкий, эффективный и популярный формат файлов на сегодняшний день для хранения разнообразной информации, какой вы только захотите. XML используется в Ant, Maven, Spring. Любому программисту нужно знание XML. Теперь, когда вы собрались силами и мотивацией, давайте приступать к изучению. Весь материал я буду пытаться выложить максимально просто, собрав только самое важное и не вдаваться в дебри.

XML

Для более ясного объяснения, правильней будет визуализировать XML примером.

<?xml version="1.0" encoding="UTF-8"?>
<company>
    <name>IT-Heaven</name>
    <offices>
        <office floor="1" room="1">
            <employees>
                <employee>
                    <name>Maksim</name>
                    <job>Middle Software Developer</job>
                </employee>
                <employee>
                    <name>Ivan</name>
                    <job>Junior Software Developer</job>
                </employee>
                <employee>
                    <name>Franklin</name>
                    <job>Junior Software Developer</job>
                </employee>
            </employees>
        </office>
        <office floor="1" room="2">
            <employees>
                <employee>
                    <name>Herald</name>
                    <job>Middle Software Developer</job>
                </employee>
                <employee>
                    <name>Adam</name>
                    <job>Middle Software Developer</job>
                </employee>
                <employee>
                    <name>Leroy</name>
                    <job>Junior Software Developer</job>
                </employee>
            </employees>
        </office>
    </offices>
</company>
HTML и XML похожи синтаксисом, так как у них общий родитель – SGML. Однако, в HTML есть только фиксированные теги конкретного стандарта, в то время, как в XML вы можете создавать свои собственные теги, атрибуты и, в целом, делать все, что захотите, чтобы хранить данные так, как вам будет удобно. По сути, XML файлы может прочитать любой человек, знающий английский язык. Изобразить данный пример можно с помощью дерева. Основы XML для Java программиста - Часть 1 из 3 - 2Корень дерева – Company. Он же – корневой (рут) элемент, от которого идут все остальные элементы. В каждом XML файле может быть только один рут элемент. Он должен объявляться после декларации xml файла (первая строчка в примере) и вмещать в себе все другие элементы. Немного о декларации: она обязательная и нужна для идентификации документа как XML. У неё есть три псевдо-атрибуты (специальные предопределенные атрибуты): version (по стандарту 1.0), encoding (кодировка) и standalone (автономность: если yes и к документу подключаются внешние схемы, то будет ошибка, по умолчанию - no). Элементы – это сущности, которые хранят данные с помощью других элементов и атрибутов. Атрибуты – это дополнительная информация об элементе, которая указывается при добавлении элемента. Если перевести объяснение на ООП-поле, то можно привести такой пример: у нас есть машина, у каждой машины есть характеристики (цвет, вместимость, марка и другое) – это атрибуты, и есть сущности, которые внутри машины: двери, окна, двигатель, руль – это другие элементы. Хранить свойства можно как и отдельными элементами, так и атрибутами в зависимости от вашего желания. Как никак, XML – крайне гибкий формат хранения информации про что-либо. После объяснений, нам достаточно разобрать пример выше, чтобы все встало на свои места. В примере мы описали простую структуру компании: есть компания, у которой есть имя и офисы, а в офисах есть сотрудники. Элементы Employees и Offices – элементы-обертки – они служат для того, чтобы собрать в себе элементы одного вида, по сути, соединив их в одно множество для удобства их обработки. Отдельного внимания заслуживают floor и room. Это – атрибуты офиса (этаж и номер), другими словами – его свойства. Если бы у нас был элемент «картинка», то можно было бы передавать её размеры. Вы можете заметить, что у компании нет атрибута name, но есть элемент name. Просто вы можете описывать структуры так, как захотите. Никто не обязывает вас все свойства элементов записывать только в атрибуты, вы можете использовать и просто элементы и записывать внутри них какие-то данные. Например, мы можем записывать имя и должность наших работников, как атрибуты:

<?xml version="1.0" encoding="UTF-8"?>
<company>
    <name>IT-Heaven</name>
    <offices>
        <office floor="1" room="1">
            <employees>
                <employee name="Maksim" job="Middle Software Developer">

                </employee>
                <employee name="Ivan" job="Junior Software Developer">

                </employee>
                <employee name="Franklin" job="Junior Software Developer">

                </employee>
            </employees>
        </office>
        <office floor="1" room="2">
            <employees>
                <employee name="Herald" job="Middle Software Developer">

                </employee>
                <employee name="Adam" job="Middle Software Developer">

                </employee>
                <employee name="Leroy" job="Junior Software Developer">

                </employee>
            </employees>
        </office>
    </offices>
</company>
Как вы видите, теперь имя и должность каждого работника – это его атрибуты. И можно заметить, что внутри сущности (тега) employee ничего нет, все элементы employee – пустые. Тогда можно сделать employee пустым элементом – закрыть его сразу после объявления атрибутов. Это делается довольно просто, достаточно просто поставить слэш:

<?xml version="1.0" encoding="UTF-8"?>
<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>
Как вы можете заметить, закрыв пустые элементы мы сохранили всю целостность информации и намного сократили запись, сделав информацию более сжатой и читабельной. Для того, чтобы добавить комментарий (текст, который будет пропускаться при парсинге файла) в XML, есть следующий синтаксис:

<!-- Иван недавно уволился, только неделю отработать должен. Не забудьте потом удалить его из списка.-->
И последняя конструкция – это CDATA, означает «символьные данные». Благодаря данной конструкции, можно записывать текст, который не будет интерпретироваться как разметка XML. Это полезно, если внутри XML файла у вас есть сущность, которая хранит в информации XML разметку. Пример:

<?xml version="1.0" encoding="UTF-8" ?>
<bean>
    <information>
        <![CDATA[<name>Ivan</name><age>26</age>]]>
    </information>
</bean>
Особенность XML в том, что вы можете расширять его так, как захотите: использовать свои элементы, свои атрибуты и структурировать его по своему желанию. Вы можете использовать для хранения данных как атрибуты, так и элементы (как это было показано в примере ранее). Однако нужно понимать, что придумывать свои элементы и атрибуты на ходу и как вы захотите вы можете, но что, если вы будете работать на проекте, где другой программист захочет перенести элемент name в атрибуты, а у вас вся логика программы написана так, чтобы name был элементом? Как же создать свои собственные правила того, какие элементы должны быть, какие атрибуты у них есть и другие вещи, чтобы можно было проводить валидацию XML файлов и быть уверенным, что правила станут стандартными в вашем проекте и никто их нарушать не будет? Для того, чтобы написать все правила вашей собственной XML разметки, есть специальные средства. Самые известные: DTD и XML Schema. В этой статье будет только про первое.

DTD

DTD создан для того, чтобы описывать типы документов. DTD уже устаревает и сейчас от него активно отказываются в XML, однако еще много XML файлов используют именно DTD и, в целом, его полезно понимать. DTD – это технология валидации XML-документов. DTD объявляет конкретные правила для типа документа: его элементы, какие элементы могут быть внутри элемента, атрибуты, обязательные они или нет, количество их повторений, а так же сущности (Entity). По аналогии с XML, для более ясного объяснения DTD можно визуализировать примером.

 <!-- Объявление возможных элементов -->
<!ELEMENT employee EMPTY>
<!ELEMENT employees (employee+)>
<!ELEMENT office (employees)>
<!ELEMENT offices (office+)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT company (name, offices)>

<!-- Добавление атрибутов для элементов employee и office -->
<!ATTLIST employee
        name CDATA #REQUIRED
        job  CDATA #REQUIRED
>

<!ATTLIST office
        floor CDATA #REQUIRED
        room  CDATA #REQUIRED
>

<!-- Добавление сущностей -->
<!ENTITY M "Maksim">
<!ENTITY I "Ivan">
<!ENTITY F "Franklin">
Вот такой вот простой пример у нас есть. В данном примере, мы объявили всю нашу иерархию из XML примера: работник, работники, офис, офисы, имя, компания. Для создания DTD файлов служат 3 основные конструкции, чтобы описывать любые XML файлы: ELEMENT (для описания элементов), ATTLIST (для описания атрибутов для элементов) и ENTITY (для подстановки текста сокращенными формами). ELEMENT Служит для описания элемента. Элементы, которые можно использовать внутри описанного элемента, перечисляются в скобках в виде списка. Можно использовать квантификаторы для указания количества (они аналогичны с квантификаторами из регулярных выражений): + значит 1+ * значит 0+ ? значит 0 ИЛИ 1 Если квантификаторов не было добавлено, то считается, что должен быть только 1 элемент. Если бы нам нужен был один из группы элементов, можно было бы написать так:

<!ELEMENT company ((name | offices))>
Тогда выбирался бы один из элементов: name или offices, но если бы внутри company было сразу два их, то валидация бы не проходила. Так же можно заметить, что в employee есть слово EMPTY – это значит, что элемент должен быть пустым. Есть еще ANY – любые элементы. #PCDATA – текстовые данные. ATTLIST Служит для добавления атрибутов к элементам. После ATTLIST следует название нужного элемента, а после словарь вида «название атрибута – тип атрибута», а в конце можно добавить #IMPLIED (не обязателен) или #REQUIRED (обязателен). CDATA – текстовые данные. Есть и другие типы, однако все они строчные. ENTITY ENTITY служит для объявления сокращений и текста, который будет на них подстваляться. По сути, мы просто сможем использовать в XML вместо полного текста просто название сущности со знаком & перед и ; после. Например: чтобы отличать разметку в HTML и просто символы, левую угловую скобочку часто экранируют с помощью lt; , только нужно еще выставить & перед lt. Тогда мы будем использовать не разметку, а просто символ < . Как вы можете видеть, все довольно просто: объявляете элементы, объясняете, какие элементы объявленные элементы способны содержать, добавление атрибутов этим элементам и, по желанию, можете добавить сущности, чтобы сокращать какие-то записи. И тут вы должны были бы спросить: а как использовать наши правила в нашем XML файле? Ведь мы просто объявили правила, но мы не использовали их в XML. Есть два способа использовать их в XML: 1. Внедрение - написание DTD правил внутри самого XML файла, достаточно просто написать корневой элемент после ключевого слова DOCTYPE и заключить наш DTD файл внутри квадратных скобочек.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE company [
        <!-- Объявление возможных элементов -->
        <!ELEMENT employee EMPTY>
        <!ELEMENT employees (employee+)>
        <!ELEMENT office (employees)>
        <!ELEMENT offices (office+)>
        <!ELEMENT name (#PCDATA)>
        <!ELEMENT company (name, offices)>

        <!-- Добавление атрибутов для элементов employee и office -->
        <!ATTLIST employee
        name CDATA #REQUIRED
        job  CDATA #REQUIRED
        >

        <!ATTLIST office
        floor CDATA #REQUIRED
        room  CDATA #REQUIRED
        >

        <!-- Добавление сущностей -->
        <!ENTITY M "Maksim">
        <!ENTITY I "Ivan">
        <!ENTITY F "Franklin">
]>

<company>
    <name>IT-Heaven</name>
    <!-- Иван недавно уволился, только неделю отработать должен. Не забудьте потом удалить его из списка.-->
    <offices>
        <office floor="1" room="1">
            <employees>
                <employee name="&M;" job="Middle Software Developer" />
                <employee name="&I;" job="Junior Software Developer" />
                <employee name="&F;" 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>
2. Импорт - мы записываем все наши правила в отдельный DTD файл, после чего в XML файле используем DOCTYPE-конструкцию из первого способа, только вместо квадратных скобочек нужно написать SYSTEM и указать абсолютный или относительный до текущего местоположения файла путь.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE company SYSTEM "dtd_example1.dtd">

<company>
    <name>IT-Heaven</name>
    <!-- Иван недавно уволился, только неделю отработать должен. Не забудьте потом удалить его из списка.-->
    <offices>
        <office floor="1" room="1">
            <employees>
                <employee name="&M;" job="Middle Software Developer" />
                <employee name="&I;" job="Junior Software Developer" />
                <employee name="&F;" 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>
Так же можно использовать ключевое слово PUBLIC вместо SYSTEM, однако оно вряд ли вам пригодится. Если интересно, то почитать про него (и про SYSTEM тоже) можно подробно тут: ссылочка. Теперь мы не можем использовать другие элементы без их объявления в DTD, а весь XML подчиняется нашим правилам. Можете попробовать записать данный код в IntelliJ IDEA в отдельный файл с расширением .xml и попробовать добавить какие-то новые элементы или удалить элемент из нашего DTD и заметите, как IDE будет указывать вам на ошибку. Однако, у DTD есть свои минусы:
  • У него свой собственный синтаксис, отличный от синтаксиса xml.
  • В DTD нет проверки типов данных, а содержать он может только строки.
  • В DTD нет пространства имён.
О проблеме собственного синтаксиса: вы должны разбираться в двух синтаксисах сразу: в XML и в DTD синтаксисе. Они разные и это может заставлять вас путаться. Так же, из-за этого же сложней отслеживать ошибки в огромных XML файлах в соединении с такими же DTD схемами. Если у вас что-то не заработало, приходится проверять огромное количество текста разных синтаксисов. Это как читать одновременно две книжки: на русском и английском. И если знание у одного языка у вас хуже, то понимать текст будет так же сложней. О проблеме проверки типов данных: у атрибутов в DTD действительно есть разные типы, но все они, по сути своей, являются строковыми представлениями чего-либо, списками или ссылками. Однако, вы не можете требовать только числа, и, тем более, позитивные или негативные. А про объектные типы можете вообще забыть. Последняя проблема будет обсуждаться уже в следующей статье, которая будет посвящена пространствам имён и XML схемам, так как обсуждение её тут бессмысленно. Спасибо всем за внимание, я проделал большую работу и продолжаю её проделывать, чтобы вовремя закончить весь цикл статей. По сути, мне осталось разобраться с XML схемами и придумать их объяснение более ясными словами, чтобы закончить 2-ю статью. Её половина уже сделана, так что можете ожидать её в ближайшее время. Последняя статья будет полностью посвящена работе с XML файлами средствами Java. Удачи всем и успехов в программировании :) Следующая статья: [Конкурс] Основы XML для Java программиста - Часть 2 из 3