31 KiB
README по лабораторной работе: XML → XSLT → HTML + SQL
1. Что это за работа
В этой работе берётся XML-файл со списком специальностей НИЯУ МИФИ, затем:
- анализируется структура данных;
- определяется, какие поля есть у сущности
object; - для каждого поля определяется тип данных;
- для текстовых полей вычисляется максимальная длина значения;
- определяются ограничения целостности:
NOT NULL, если поле всегда заполнено;CHECK, если поле принимает от 2 до 5 разных значений;
- формируется SQL-скрипт для PostgreSQL;
- пишется XSLT-преобразование;
- при открытии XML или при запуске Python-скрипта автоматически генерируется HTML-страница с анализом и SQL-кодом.
Идея работы простая:
- XML хранит исходные данные;
- XSLT описывает, как из XML сделать человекочитаемую HTML-страницу;
- SQL — это уже результат проектирования таблицы и генерации команд вставки;
- Python нужен как запасной способ генерации HTML, если браузер неудобно применяет XSLT.
2. Короткая теория
2.1. Что такое XML
XML — это язык разметки для хранения структурированных данных.
Пример:
<object>
<id type="integer">307</id>
<name>Технологии разделения изотопов и ядерное топливо</name>
<code>14.05.03</code>
</object>
Здесь:
object— одна запись;id,name,code— поля этой записи;- текст внутри тега — само значение;
- атрибут
type="integer"— дополнительная информация о значении.
В этой работе XML используется как источник данных.
2.2. Что такое XSLT
XSLT — это язык преобразования XML.
Он позволяет сказать:
- какие теги брать из XML;
- как их выводить;
- в каком порядке показывать;
- как на основе XML сгенерировать HTML, текст или другой XML.
В нашей работе XSLT делает сразу две вещи:
- показывает анализ данных;
- генерирует SQL-код.
То есть XSLT здесь — это «шаблон», который читает XML и печатает из него понятный результат.
2.3. Что такое HTML в этой работе
HTML здесь не пишется вручную как обычная страница сайта.
Он генерируется автоматически из XML через XSLT.
Это важный смысл задания: показать именно преобразование, а не ручную вёрстку.
2.4. Что такое SQL в этой работе
SQL-файл нужен для базы данных PostgreSQL.
Он содержит:
- удаление старых объектов, если они уже есть;
- создание последовательности;
- создание таблицы;
- отдельные
INSERT-запросы для каждой записи из XML.
2.5. Что такое NOT NULL
NOT NULL означает: значение в этом столбце обязательно должно быть.
Если в XML поле ни разу не пустое, значит для таблицы логично поставить NOT NULL.
Пример:
name VARCHAR(102) NOT NULL
Это значит, что у записи не может быть пустого name.
2.6. Что такое CHECK
CHECK — это ограничение, которое разрешает только некоторые значения.
Пример:
CHECK (level IN ('Специалитет', 'Магистратура', 'Бакалавриат', 'Аспирантура'))
Это значит: в поле level можно записать только одно из этих значений.
Такое ограничение удобно, когда уникальных вариантов мало и они заранее известны.
2.7. Что такое последовательность SEQUENCE
Последовательность — это объект БД, который выдаёт новые числа по порядку.
В PostgreSQL значение берётся так:
nextval('specialities_id_seq')
В задании сказано, что id при вставке нужно брать не из XML, а из последовательности.
То есть XML-значение id анализируется, но при вставке в таблицу мы используем новый номер из sequence.
2.8. Почему HTML не читает .sql напрямую
HTML-страница в этой работе строится не из SQL-файла, а из XML через XSLT.
Схема такая:
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 есть поля:
idnamecodelevellevel-idgenerationgeneration-idtypetype-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 version="1.0" encoding="UTF-8"?>
Что делает:
- объявляет XML-документ;
- указывает версию XML;
- задаёт кодировку UTF-8.
Зачем нужна:
- чтобы парсер понимал, что это XML;
- чтобы русские буквы читались правильно.
Строка 2
<objects type="array">
Что делает:
- открывает корневой контейнер;
- атрибут
type="array"говорит, что внутри набор однотипных объектов.
Зачем нужна:
- у XML должен быть один корневой элемент;
- все записи нужно куда-то вложить.
Строка 3
<object>
Что делает:
- открывает одну запись.
Зачем нужна:
- каждая специальность хранится как отдельный объект.
Строка 4
<id type="integer">307</id>
Что делает:
- хранит идентификатор из исходного XML;
- атрибут
type="integer"подсказывает, что значение числовое.
Зачем нужна:
- поле участвует в анализе структуры данных;
- по заданию его значение не вставляется в БД напрямую, но само поле всё равно существует в исходном файле.
Строка 5
<name>Технологии разделения изотопов и ядерное топливо</name>
Что делает:
- хранит название специальности.
Зачем нужна:
- это основной текстовый атрибут записи;
- по нему определяется максимальная длина поля
name.
Строка 6
<code>14.05.03</code>
Что делает:
- хранит код специальности.
Зачем нужна:
- используется в таблице и в
INSERT.
Строка 7
<level>Специалитет</level>
Что делает:
- хранит уровень образования.
Зачем нужна:
- по этому полю видно, что допустимых значений немного;
- поэтому для него логично сформировать
CHECK.
Строка 8
<level-id type="integer">1</level-id>
Что делает:
- хранит числовой код уровня.
Зачем нужна:
- это более компактный числовой эквивалент поля
level.
Строка 9
<generation>ФГОС3+</generation>
Что делает:
- хранит поколение стандарта.
Зачем нужна:
- используется и в анализе, и в SQL.
Строка 10
<generation-id type="integer">1</generation-id>
Что делает:
- хранит числовой код поколения.
Строка 11
<type>специальность</type>
Что делает:
- хранит тип образовательной позиции.
Строка 12
<type-id type="integer">1</type-id>
Что делает:
- хранит числовой код поля
type.
Строка 13
</object>
Что делает:
- закрывает одну запись.
Строки 14 и далее
Дальше идёт следующий object с точно такой же структурой:
- открывается
<object>; - внутри девять полей;
- затем
</object>.
То есть весь файл дальше — это просто повторение одной и той же схемы для разных специальностей.
Последняя строка файла
</objects>
Что делает:
- закрывает корневой контейнер.
Простое объяснение
XML-файл — это как большая таблица, только записанная не в строках Excel, а во вложенных тегах.
5.2. Файл specialities.xsl
Что делает файл
Это главный логический файл работы.
Он:
- читает XML;
- выводит анализ полей;
- собирает SQL-код создания таблицы;
- выводит отдельные
INSERTпо всем объектам; - формирует итоговый HTML.
Ниже — подробный разбор по строкам и блокам.
Разбор файла specialities.xsl
Строка 1
<?xml version="1.0" encoding="UTF-8"?>
Это объявление XML для самого XSLT-файла.
Строка 2
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
Что делает:
- открывает XSLT-документ;
- объявляет пространство имён
xsl; - указывает, что используется XSLT 1.0.
Зачем нужно:
- без этого процессор не поймёт, что перед ним XSLT.
Строка 3
<xsl:output method="html" encoding="UTF-8" indent="yes"/>
Что делает:
- говорит, что результат преобразования будет HTML;
- кодировка UTF-8;
indent="yes"просит красиво форматировать результат.
Блок ключей: строки 5–11
<xsl:key name="k-level" match="object/level" use="."/>
...
Что делают ключи:
- помогают находить уникальные значения;
- используются для формирования
CHECK.
Простыми словами:
- если в XML много раз встречается
Специалитет, ключ позволяет взять это значение один раз, а не печатать его сто раз.
Используемые ключи:
k-levelk-level-idk-generationk-generation-idk-typek-type-id
Блок escape-sql: строки 13–28
Это шаблон для экранирования одинарных кавычек в SQL.
Строка 14
<xsl:template name="escape-sql">
Создаёт именованный шаблон.
Строка 15
<xsl:param name="text"/>
Принимает входной текст.
Строки 16–27
Логика такая:
- если в тексте есть
', - то она заменяется на
'', - потому что в SQL именно так экранируют одинарную кавычку.
Зачем это нужно:
- чтобы SQL не ломался на строковых значениях.
Блоки show-not-null-text и sql-not-null: строки 30–43
show-not-null-text
Выводит на HTML строку:
Нужен: NOT NULL
только если число пустых значений равно 0.
sql-not-null
Добавляет в SQL-фрагмент текст:
NOT NULL
тоже только если пустых значений нет.
Это важно, потому что ограничение теперь не написано «по умолчанию», а выводится по фактическому анализу XML.
Главный шаблон match="/": строки 45–118
Это входная точка преобразования.
Когда XSLT начинает работу, он сначала попадает именно сюда.
Строки 46–58
Создают обычную HTML-обёртку:
<html><head><meta><title><style>
Строки 51–56
Простой CSS:
- задаёт шрифт;
- размер заголовков;
- отступы;
- стиль для SQL-блоков.
Строки 59–61
Начало <body> и заголовки страницы.
Строки 63–71
<xsl:call-template name="field-id"/>
...
Что делают:
- вызывают отдельные шаблоны анализа для каждого поля.
Это удобно, потому что код разбит по частям.
Блок создания SQL-структуры: строки 73–94
Этот блок выводит в HTML SQL для:
DROP TABLEDROP SEQUENCECREATE SEQUENCECREATE TABLE
Внутри используется <xsl:text>, потому что SQL нужно печатать как обычный текст.
Почему в середине идут вызовы sql-not-null
Например:
id INTEGER</xsl:text><xsl:call-template name="sql-not-null">...
Это сделано так, чтобы:
- сначала вывести тип поля;
- потом, если надо, дописать
NOT NULL.
То есть SQL формируется динамически.
Блок генерации INSERT: строки 96–117
Строка 96
<xsl:for-each select="objects/object">
Что делает:
- запускает цикл по всем объектам XML.
Это ключевая часть задания.
Строка 97
<div class="sql">
Каждый INSERT выводится в отдельном HTML-блоке.
Зачем это хорошо:
- на странице визуально видно, что для каждого
objectсоздаётся отдельный запрос.
Строки 97–116
Печатают SQL вида:
INSERT INTO specialities (...) VALUES (...);
Что важно:
idберётся какnextval('specialities_id_seq');- остальные значения берутся из XML;
- текстовые поля проходят через
escape-sql; - числовые поля выводятся напрямую через
xsl:value-of.
Шаблоны анализа полей
Ниже в файле идут шаблоны:
field-idfield-namefield-codefield-levelfield-level-idfield-generationfield-generation-idfield-typefield-type-id
У них одна и та же идея:
- посчитать число пустых значений;
- вывести тип данных;
- если поле текстовое — найти самый длинный элемент;
- если пустых нет — вывести
NOT NULL; - если значений мало — вывести
CHECK.
Как считается число пустых
Например:
count(objects/object/name[not(normalize-space())])
Что это значит:
- берём все
name; normalize-space()убирает лишние пробелы;not(...)выбирает пустые;count(...)считает их.
Как находится самый длинный элемент
Например для name:
<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:
<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.
Поэтому подробно разбираем:
- заголовок SQL-файла;
- структуру таблицы;
- один типовой
INSERT.
Дальше все остальные INSERT устроены точно так же.
Разбор начала файла
Строка 1
DROP TABLE IF EXISTS specialities;
Что делает:
- удаляет таблицу
specialities, если она уже существует.
Зачем нужна:
- чтобы скрипт можно было запускать повторно.
Строка 2
DROP SEQUENCE IF EXISTS specialities_id_seq;
Что делает:
- удаляет последовательность, если она уже есть.
Строки 4–6
CREATE SEQUENCE specialities_id_seq
START WITH 1
INCREMENT BY 1;
Что делают:
- создают последовательность;
- первый номер будет 1;
- дальше увеличение на 1.
Строки 8–19
Создают таблицу specialities.
Строка 9
id INTEGER NOT NULL,
Числовой идентификатор, обязательный.
Строка 10
name VARCHAR(102) NOT NULL,
Текстовое поле длиной до 102 символов.
Почему 102:
- это максимальная длина, найденная в XML.
Строка 11
code VARCHAR(8) NOT NULL,
Поле кода длиной до 8 символов.
Строки 12–17
Поля со встроенными ограничениями CHECK.
Пример:
level VARCHAR(12) NOT NULL CHECK (...)
Это значит:
- хранится текст до 12 символов;
- поле обязательно;
- допустимы только перечисленные значения.
Строка 18
CONSTRAINT pk_specialities PRIMARY KEY (id)
Создаёт первичный ключ по полю id.
Строка 19
);
Закрывает определение таблицы.
Разбор типового INSERT
Пример:
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
from lxml import etree
Что делает:
- импортирует библиотеку
lxml; - модуль
etreeумеет работать с XML и XSLT.
Строка 3
# загружаем XML
Комментарий для пояснения.
Строка 4
xml = etree.parse("specialities_variant1.xml")
Что делает:
- читает XML-файл с диска;
- превращает его в дерево XML.
Если у тебя рабочий файл называется specialities.xml, здесь нужно подставить именно это имя.
Строка 6
# загружаем XSLT
Комментарий.
Строка 7
xslt = etree.parse("specialities_report.xsl")
Что делает:
- читает XSLT-файл.
Если твой файл называется specialities.xsl, здесь тоже нужно использовать актуальное имя.
Строка 9
# создаем трансформацию
Комментарий.
Строка 10
transform = etree.XSLT(xslt)
Что делает:
- превращает XSLT-документ в исполняемое преобразование.
Строка 12
# применяем
Комментарий.
Строка 13
result = transform(xml)
Что делает:
- применяет XSLT к XML;
- получает результат в виде HTML-документа.
Строка 15
# сохраняем HTML
Комментарий.
Строки 16–17
with open("specialities_variant1.html", "wb") as f:
f.write(etree.tostring(result, pretty_print=True, encoding="UTF-8"))
Что делают:
- открывают файл для записи в бинарном режиме;
- сохраняют туда результат преобразования.
Опять же: имя файла нужно согласовать с твоими текущими названиями.
Строка 19
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
Запустить:
python transform.py
После этого появится HTML-файл.
Важно
Имена файлов в transform.py должны совпадать с реальными именами файлов в папке.
9. Что можно коротко сказать преподавателю
specialities.xml— это исходные данные по специальностям.specialities.xsl— это XSLT-преобразование, которое автоматически строит HTML и SQL по XML.specialities.sql— итоговый SQL-скрипт под PostgreSQL: sequence, table и отдельные insert-запросы.specialities.html— уже сгенерированный результат.transform.py— вспомогательный скрипт для автоматической генерации HTML, если не хочется зависеть от браузера.
Главная идея работы: данные берутся из XML, а HTML и SQL получаются автоматически, а не пишутся вручную.