# README по лабораторной работе: XML → XSLT → HTML + SQL ## 1. Что это за работа В этой работе берётся XML-файл со списком специальностей НИЯУ МИФИ, затем: 1. анализируется структура данных; 2. определяется, какие поля есть у сущности `object`; 3. для каждого поля определяется тип данных; 4. для текстовых полей вычисляется максимальная длина значения; 5. определяются ограничения целостности: - `NOT NULL`, если поле всегда заполнено; - `CHECK`, если поле принимает от 2 до 5 разных значений; 6. формируется SQL-скрипт для PostgreSQL; 7. пишется XSLT-преобразование; 8. при открытии XML или при запуске Python-скрипта автоматически генерируется HTML-страница с анализом и SQL-кодом. Идея работы простая: - **XML** хранит исходные данные; - **XSLT** описывает, как из XML сделать человекочитаемую HTML-страницу; - **SQL** — это уже результат проектирования таблицы и генерации команд вставки; - **Python** нужен как запасной способ генерации HTML, если браузер неудобно применяет XSLT. --- ## 2. Короткая теория ### 2.1. Что такое XML XML — это язык разметки для хранения структурированных данных. Пример: ```xml 307 Технологии разделения изотопов и ядерное топливо 14.05.03 ``` Здесь: - `object` — одна запись; - `id`, `name`, `code` — поля этой записи; - текст внутри тега — само значение; - атрибут `type="integer"` — дополнительная информация о значении. В этой работе XML используется как **источник данных**. --- ### 2.2. Что такое XSLT XSLT — это язык преобразования XML. Он позволяет сказать: - какие теги брать из XML; - как их выводить; - в каком порядке показывать; - как на основе XML сгенерировать HTML, текст или другой XML. В нашей работе XSLT делает сразу две вещи: 1. показывает **анализ данных**; 2. генерирует **SQL-код**. То есть XSLT здесь — это «шаблон», который читает XML и печатает из него понятный результат. --- ### 2.3. Что такое HTML в этой работе HTML здесь не пишется вручную как обычная страница сайта. Он **генерируется автоматически** из XML через XSLT. Это важный смысл задания: показать именно преобразование, а не ручную вёрстку. --- ### 2.4. Что такое SQL в этой работе SQL-файл нужен для базы данных PostgreSQL. Он содержит: 1. удаление старых объектов, если они уже есть; 2. создание последовательности; 3. создание таблицы; 4. отдельные `INSERT`-запросы для каждой записи из XML. --- ### 2.5. Что такое `NOT NULL` `NOT NULL` означает: значение в этом столбце обязательно должно быть. Если в XML поле ни разу не пустое, значит для таблицы логично поставить `NOT NULL`. Пример: ```sql name VARCHAR(102) NOT NULL ``` Это значит, что у записи не может быть пустого `name`. --- ### 2.6. Что такое `CHECK` `CHECK` — это ограничение, которое разрешает только некоторые значения. Пример: ```sql CHECK (level IN ('Специалитет', 'Магистратура', 'Бакалавриат', 'Аспирантура')) ``` Это значит: в поле `level` можно записать только одно из этих значений. Такое ограничение удобно, когда уникальных вариантов мало и они заранее известны. --- ### 2.7. Что такое последовательность `SEQUENCE` Последовательность — это объект БД, который выдаёт новые числа по порядку. В PostgreSQL значение берётся так: ```sql nextval('specialities_id_seq') ``` В задании сказано, что `id` при вставке нужно брать **не из XML**, а из последовательности. То есть XML-значение `id` анализируется, но при вставке в таблицу мы используем новый номер из sequence. --- ### 2.8. Почему HTML не читает `.sql` напрямую HTML-страница в этой работе строится не из SQL-файла, а из XML через XSLT. Схема такая: ```text specialities.xml + specialities.xsl -> HTML ``` Поэтому если изменить только `.sql`, страница сама не поменяется. Нужно менять XSLT или заново сгенерировать HTML через XML + XSLT. --- ## 3. Какие файлы есть в работе ### Основные файлы - `specialities.xml` — исходные данные в XML; - `specialities.xsl` — XSLT-преобразование; - `specialities.sql` — SQL-скрипт для PostgreSQL; - `specialities.html` — готовый результат преобразования; - `transform.py` — Python-скрипт для генерации HTML. --- ## 4. Общая логика работы по шагам ### Шаг 1. Берём XML В XML есть корневой тег `objects`, а внутри него много тегов `object`. Каждый `object` — одна специальность. ### Шаг 2. Анализируем поля У каждого `object` есть поля: - `id` - `name` - `code` - `level` - `level-id` - `generation` - `generation-id` - `type` - `type-id` ### Шаг 3. Для каждого поля определяем свойства - тип данных; - число пустых значений; - для текста — максимальную длину; - нужен ли `NOT NULL`; - нужен ли `CHECK`. ### Шаг 4. Генерируем SQL-структуру таблицы На основе анализа создаются: - последовательность `specialities_id_seq`; - таблица `specialities`; - ограничения `NOT NULL` и `CHECK`. ### Шаг 5. Генерируем SQL-вставки Для каждого `object` создаётся **отдельный** `INSERT`. ### Шаг 6. Генерируем HTML XSLT выводит на страницу: - анализ полей; - SQL для создания таблицы и sequence; - SQL `INSERT` для каждого объекта. ### Шаг 7. При необходимости запускаем Python Python-скрипт берёт XML и XSLT и сохраняет готовый HTML-файл. --- ## 5. Подробно по каждому файлу # 5.1. Файл `specialities.xml` ## Что делает файл Это исходный набор данных. Он ничего сам не вычисляет. Он только хранит записи. ## Как устроен файл У файла повторяющаяся структура. Поэтому подробно важно понять **первые строки и один типовой блок `object`**. Дальше всё повторяется по той же схеме. ## Разбор структуры по строкам ### Строка 1 ```xml ``` Что делает: - объявляет XML-документ; - указывает версию XML; - задаёт кодировку UTF-8. Зачем нужна: - чтобы парсер понимал, что это XML; - чтобы русские буквы читались правильно. ### Строка 2 ```xml ``` Что делает: - открывает корневой контейнер; - атрибут `type="array"` говорит, что внутри набор однотипных объектов. Зачем нужна: - у XML должен быть один корневой элемент; - все записи нужно куда-то вложить. ### Строка 3 ```xml ``` Что делает: - открывает одну запись. Зачем нужна: - каждая специальность хранится как отдельный объект. ### Строка 4 ```xml 307 ``` Что делает: - хранит идентификатор из исходного XML; - атрибут `type="integer"` подсказывает, что значение числовое. Зачем нужна: - поле участвует в анализе структуры данных; - по заданию его значение не вставляется в БД напрямую, но само поле всё равно существует в исходном файле. ### Строка 5 ```xml Технологии разделения изотопов и ядерное топливо ``` Что делает: - хранит название специальности. Зачем нужна: - это основной текстовый атрибут записи; - по нему определяется максимальная длина поля `name`. ### Строка 6 ```xml 14.05.03 ``` Что делает: - хранит код специальности. Зачем нужна: - используется в таблице и в `INSERT`. ### Строка 7 ```xml Специалитет ``` Что делает: - хранит уровень образования. Зачем нужна: - по этому полю видно, что допустимых значений немного; - поэтому для него логично сформировать `CHECK`. ### Строка 8 ```xml 1 ``` Что делает: - хранит числовой код уровня. Зачем нужна: - это более компактный числовой эквивалент поля `level`. ### Строка 9 ```xml ФГОС3+ ``` Что делает: - хранит поколение стандарта. Зачем нужна: - используется и в анализе, и в SQL. ### Строка 10 ```xml 1 ``` Что делает: - хранит числовой код поколения. ### Строка 11 ```xml специальность ``` Что делает: - хранит тип образовательной позиции. ### Строка 12 ```xml 1 ``` Что делает: - хранит числовой код поля `type`. ### Строка 13 ```xml ``` Что делает: - закрывает одну запись. ### Строки 14 и далее Дальше идёт следующий `object` с точно такой же структурой: - открывается ``; - внутри девять полей; - затем ``. То есть весь файл дальше — это просто повторение одной и той же схемы для разных специальностей. ### Последняя строка файла ```xml ``` Что делает: - закрывает корневой контейнер. ## Простое объяснение XML-файл — это как большая таблица, только записанная не в строках Excel, а во вложенных тегах. --- # 5.2. Файл `specialities.xsl` ## Что делает файл Это главный логический файл работы. Он: 1. читает XML; 2. выводит анализ полей; 3. собирает SQL-код создания таблицы; 4. выводит отдельные `INSERT` по всем объектам; 5. формирует итоговый HTML. Ниже — подробный разбор по строкам и блокам. ## Разбор файла `specialities.xsl` ### Строка 1 ```xml ``` Это объявление XML для самого XSLT-файла. ### Строка 2 ```xml ``` Что делает: - открывает XSLT-документ; - объявляет пространство имён `xsl`; - указывает, что используется XSLT 1.0. Зачем нужно: - без этого процессор не поймёт, что перед ним XSLT. ### Строка 3 ```xml ``` Что делает: - говорит, что результат преобразования будет HTML; - кодировка UTF-8; - `indent="yes"` просит красиво форматировать результат. --- ## Блок ключей: строки 5–11 ```xml ... ``` Что делают ключи: - помогают находить уникальные значения; - используются для формирования `CHECK`. Простыми словами: - если в XML много раз встречается `Специалитет`, ключ позволяет взять это значение один раз, а не печатать его сто раз. Используемые ключи: - `k-level` - `k-level-id` - `k-generation` - `k-generation-id` - `k-type` - `k-type-id` --- ## Блок `escape-sql`: строки 13–28 Это шаблон для экранирования одинарных кавычек в SQL. ### Строка 14 ```xml ``` Создаёт именованный шаблон. ### Строка 15 ```xml ``` Принимает входной текст. ### Строки 16–27 Логика такая: - если в тексте есть `'`, - то она заменяется на `''`, - потому что в SQL именно так экранируют одинарную кавычку. Зачем это нужно: - чтобы SQL не ломался на строковых значениях. --- ## Блоки `show-not-null-text` и `sql-not-null`: строки 30–43 ### `show-not-null-text` Выводит на HTML строку: ```html Нужен: NOT NULL ``` только если число пустых значений равно 0. ### `sql-not-null` Добавляет в SQL-фрагмент текст: ```sql NOT NULL ``` тоже только если пустых значений нет. Это важно, потому что ограничение теперь не написано «по умолчанию», а выводится по фактическому анализу XML. --- ## Главный шаблон `match="/"`: строки 45–118 Это входная точка преобразования. Когда XSLT начинает работу, он сначала попадает именно сюда. ### Строки 46–58 Создают обычную HTML-обёртку: - `` - `` - `` - `` - `<style>` ### Строки 51–56 Простой CSS: - задаёт шрифт; - размер заголовков; - отступы; - стиль для SQL-блоков. ### Строки 59–61 Начало `<body>` и заголовки страницы. ### Строки 63–71 ```xml <xsl:call-template name="field-id"/> ... ``` Что делают: - вызывают отдельные шаблоны анализа для каждого поля. Это удобно, потому что код разбит по частям. --- ## Блок создания SQL-структуры: строки 73–94 Этот блок выводит в HTML SQL для: - `DROP TABLE` - `DROP SEQUENCE` - `CREATE SEQUENCE` - `CREATE TABLE` Внутри используется `<xsl:text>`, потому что SQL нужно печатать как обычный текст. ### Почему в середине идут вызовы `sql-not-null` Например: ```xml id INTEGER</xsl:text><xsl:call-template name="sql-not-null">... ``` Это сделано так, чтобы: - сначала вывести тип поля; - потом, если надо, дописать `NOT NULL`. То есть SQL формируется динамически. --- ## Блок генерации `INSERT`: строки 96–117 ### Строка 96 ```xml <xsl:for-each select="objects/object"> ``` Что делает: - запускает цикл по всем объектам XML. Это ключевая часть задания. ### Строка 97 ```xml <div class="sql"> ``` Каждый `INSERT` выводится в отдельном HTML-блоке. Зачем это хорошо: - на странице визуально видно, что для каждого `object` создаётся отдельный запрос. ### Строки 97–116 Печатают SQL вида: ```sql INSERT INTO specialities (...) VALUES (...); ``` Что важно: - `id` берётся как `nextval('specialities_id_seq')`; - остальные значения берутся из XML; - текстовые поля проходят через `escape-sql`; - числовые поля выводятся напрямую через `xsl:value-of`. --- ## Шаблоны анализа полей Ниже в файле идут шаблоны: - `field-id` - `field-name` - `field-code` - `field-level` - `field-level-id` - `field-generation` - `field-generation-id` - `field-type` - `field-type-id` У них одна и та же идея: 1. посчитать число пустых значений; 2. вывести тип данных; 3. если поле текстовое — найти самый длинный элемент; 4. если пустых нет — вывести `NOT NULL`; 5. если значений мало — вывести `CHECK`. ### Как считается число пустых Например: ```xml count(objects/object/name[not(normalize-space())]) ``` Что это значит: - берём все `name`; - `normalize-space()` убирает лишние пробелы; - `not(...)` выбирает пустые; - `count(...)` считает их. ### Как находится самый длинный элемент Например для `name`: ```xml <xsl:for-each select="objects/object/name"> <xsl:sort select="string-length(.)" data-type="number" order="descending"/> <xsl:if test="position() = 1"> ... </xsl:if> </xsl:for-each> ``` Логика: - перебираем все значения; - сортируем по длине по убыванию; - берём первое, то есть самое длинное. ### Как строится `CHECK` Например для `level`: ```xml <xsl:for-each select="objects/object/level[generate-id() = generate-id(key('k-level', .)[1])]"> ``` Логика: - ключ `k-level` находит группы одинаковых значений; - `generate-id() = generate-id(...[1])` оставляет только первое вхождение каждого значения; - в результате выводятся только уникальные варианты. Простыми словами: - если в XML 100 раз встречается `Бакалавриат`, в `CHECK` он попадёт один раз. --- # 5.3. Файл `specialities.sql` ## Что делает файл Это итоговый SQL-скрипт для PostgreSQL. Он нужен, чтобы: - создать таблицу; - создать последовательность; - заполнить таблицу данными. ## Логика структуры Файл очень длинный, потому что содержит много отдельных `INSERT`. Поэтому подробно разбираем: 1. заголовок SQL-файла; 2. структуру таблицы; 3. один типовой `INSERT`. Дальше все остальные `INSERT` устроены точно так же. ## Разбор начала файла ### Строка 1 ```sql DROP TABLE IF EXISTS specialities; ``` Что делает: - удаляет таблицу `specialities`, если она уже существует. Зачем нужна: - чтобы скрипт можно было запускать повторно. ### Строка 2 ```sql DROP SEQUENCE IF EXISTS specialities_id_seq; ``` Что делает: - удаляет последовательность, если она уже есть. ### Строки 4–6 ```sql CREATE SEQUENCE specialities_id_seq START WITH 1 INCREMENT BY 1; ``` Что делают: - создают последовательность; - первый номер будет 1; - дальше увеличение на 1. ### Строки 8–19 Создают таблицу `specialities`. #### Строка 9 ```sql id INTEGER NOT NULL, ``` Числовой идентификатор, обязательный. #### Строка 10 ```sql name VARCHAR(102) NOT NULL, ``` Текстовое поле длиной до 102 символов. Почему 102: - это максимальная длина, найденная в XML. #### Строка 11 ```sql code VARCHAR(8) NOT NULL, ``` Поле кода длиной до 8 символов. #### Строки 12–17 Поля со встроенными ограничениями `CHECK`. Пример: ```sql level VARCHAR(12) NOT NULL CHECK (...) ``` Это значит: - хранится текст до 12 символов; - поле обязательно; - допустимы только перечисленные значения. #### Строка 18 ```sql CONSTRAINT pk_specialities PRIMARY KEY (id) ``` Создаёт первичный ключ по полю `id`. #### Строка 19 ```sql ); ``` Закрывает определение таблицы. --- ## Разбор типового `INSERT` Пример: ```sql INSERT INTO specialities (id, name, code, level, level_id, generation, generation_id, type, type_id) VALUES ( nextval('specialities_id_seq'), 'Технологии разделения изотопов и ядерное топливо', '14.05.03', 'Специалитет', 1, 'ФГОС3+', 1, 'специальность', 1 ); ``` ### Что здесь происходит - указывается таблица `specialities`; - перечисляются столбцы; - `id` берётся из sequence, а не из XML; - остальные поля берутся из XML; - запрос заканчивается `;`. ### Почему каждый `INSERT` отдельный Потому что задание прямо требует: - для каждой сущности `object` должен быть отдельный `INSERT`. Значит один `object` XML = один `INSERT` SQL. --- # 5.4. Файл `specialities.html` ## Что делает файл Это уже готовый результат преобразования. Если открыть его в браузере, будет видно: - анализ полей; - нужные ограничения; - SQL для создания структуры; - отдельные SQL-вставки. ## Важный смысл Этот файл не основной источник логики. Он нужен как **результат**. Источник логики — это `specialities.xsl`. Если ты меняешь XSLT, то нужно заново генерировать HTML. --- # 5.5. Файл `transform.py` ## Что делает файл Этот скрипт применяет XSLT к XML и сохраняет HTML. Это запасной и очень удобный способ показать на паре, что HTML генерируется автоматически. ## Разбор по строкам ### Строка 1 ```python from lxml import etree ``` Что делает: - импортирует библиотеку `lxml`; - модуль `etree` умеет работать с XML и XSLT. ### Строка 3 ```python # загружаем XML ``` Комментарий для пояснения. ### Строка 4 ```python xml = etree.parse("specialities_variant1.xml") ``` Что делает: - читает XML-файл с диска; - превращает его в дерево XML. Если у тебя рабочий файл называется `specialities.xml`, здесь нужно подставить именно это имя. ### Строка 6 ```python # загружаем XSLT ``` Комментарий. ### Строка 7 ```python xslt = etree.parse("specialities_report.xsl") ``` Что делает: - читает XSLT-файл. Если твой файл называется `specialities.xsl`, здесь тоже нужно использовать актуальное имя. ### Строка 9 ```python # создаем трансформацию ``` Комментарий. ### Строка 10 ```python transform = etree.XSLT(xslt) ``` Что делает: - превращает XSLT-документ в исполняемое преобразование. ### Строка 12 ```python # применяем ``` Комментарий. ### Строка 13 ```python result = transform(xml) ``` Что делает: - применяет XSLT к XML; - получает результат в виде HTML-документа. ### Строка 15 ```python # сохраняем HTML ``` Комментарий. ### Строки 16–17 ```python with open("specialities_variant1.html", "wb") as f: f.write(etree.tostring(result, pretty_print=True, encoding="UTF-8")) ``` Что делают: - открывают файл для записи в бинарном режиме; - сохраняют туда результат преобразования. Опять же: имя файла нужно согласовать с твоими текущими названиями. ### Строка 19 ```python print("HTML успешно создан: specialities_variant1.html") ``` Что делает: - печатает сообщение об успехе. --- ## 6. Что в этой работе важно понимать для защиты ### 1. XML — это источник данных Он не создаёт HTML сам по себе и не создаёт SQL сам по себе. Он только хранит данные. ### 2. XSLT — это логика преобразования Именно XSLT решает: - что показать на странице; - как вычислить длины; - как посчитать пустые; - как вывести `CHECK`; - как собрать SQL. ### 3. HTML — это результат HTML уже готовая страница, которую видит пользователь. ### 4. SQL — это отдельный результат для БД SQL-файл можно выполнить в PostgreSQL и получить таблицу с данными. ### 5. Python — это технический помощник Он нужен, когда браузер неудобно применяет XSLT напрямую. --- ## 7. Почему решение считается корректным Потому что оно выполняет все ключевые требования задания: - используются данные из `specialities.xml`; - определены поля сущности `object`; - для каждого поля выполнен анализ; - для текстовых полей найдена максимальная длина; - `NOT NULL` ставится по условию «пустых нет»; - `CHECK` формируется для полей с малым количеством значений; - создан SQL для PostgreSQL; - создана последовательность для `id`; - для каждого `object` генерируется отдельный `INSERT`; - `id` в `INSERT` берётся из sequence, а не из XML; - HTML генерируется автоматически через XSLT. --- ## 8. Как запускать ### Вариант 1. Через браузер Если браузер корректно применяет XSLT, можно открыть XML-файл. ### Вариант 2. Через Python Запустить: ```bash python transform.py ``` После этого появится HTML-файл. ### Важно Имена файлов в `transform.py` должны совпадать с реальными именами файлов в папке. --- ## 9. Что можно коротко сказать преподавателю 1. `specialities.xml` — это исходные данные по специальностям. 2. `specialities.xsl` — это XSLT-преобразование, которое автоматически строит HTML и SQL по XML. 3. `specialities.sql` — итоговый SQL-скрипт под PostgreSQL: sequence, table и отдельные insert-запросы. 4. `specialities.html` — уже сгенерированный результат. 5. `transform.py` — вспомогательный скрипт для автоматической генерации HTML, если не хочется зависеть от браузера. Главная идея работы: **данные берутся из XML, а HTML и SQL получаются автоматически, а не пишутся вручную**.