Files
files_mephi/Работы/ИРФМ/L1/README_specialities.md
T
2026-03-18 17:54:53 +03:00

31 KiB
Raw Blame History

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 — это язык разметки для хранения структурированных данных.

Пример:

<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 делает сразу две вещи:

  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.

Пример:

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 есть поля:

  • 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 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

Что делает файл

Это главный логический файл работы.

Он:

  1. читает XML;
  2. выводит анализ полей;
  3. собирает SQL-код создания таблицы;
  4. выводит отдельные INSERT по всем объектам;
  5. формирует итоговый 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-level
  • k-level-id
  • k-generation
  • k-generation-id
  • k-type
  • k-type-id

Блок escape-sql: строки 1328

Это шаблон для экранирования одинарных кавычек в SQL.

Строка 14

<xsl:template name="escape-sql">

Создаёт именованный шаблон.

Строка 15

<xsl:param name="text"/>

Принимает входной текст.

Строки 1627

Логика такая:

  • если в тексте есть ',
  • то она заменяется на '',
  • потому что в SQL именно так экранируют одинарную кавычку.

Зачем это нужно:

  • чтобы SQL не ломался на строковых значениях.

Блоки show-not-null-text и sql-not-null: строки 3043

show-not-null-text

Выводит на HTML строку:

Нужен: NOT NULL

только если число пустых значений равно 0.

sql-not-null

Добавляет в SQL-фрагмент текст:

NOT NULL

тоже только если пустых значений нет.

Это важно, потому что ограничение теперь не написано «по умолчанию», а выводится по фактическому анализу XML.


Главный шаблон match="/": строки 45118

Это входная точка преобразования.

Когда XSLT начинает работу, он сначала попадает именно сюда.

Строки 4658

Создают обычную HTML-обёртку:

  • <html>
  • <head>
  • <meta>
  • <title>
  • <style>

Строки 5156

Простой CSS:

  • задаёт шрифт;
  • размер заголовков;
  • отступы;
  • стиль для SQL-блоков.

Строки 5961

Начало <body> и заголовки страницы.

Строки 6371

<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

Например:

id INTEGER</xsl:text><xsl:call-template name="sql-not-null">...

Это сделано так, чтобы:

  • сначала вывести тип поля;
  • потом, если надо, дописать NOT NULL.

То есть SQL формируется динамически.


Блок генерации INSERT: строки 96117

Строка 96

<xsl:for-each select="objects/object">

Что делает:

  • запускает цикл по всем объектам XML.

Это ключевая часть задания.

Строка 97

<div class="sql">

Каждый INSERT выводится в отдельном HTML-блоке.

Зачем это хорошо:

  • на странице визуально видно, что для каждого object создаётся отдельный запрос.

Строки 97116

Печатают 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.

Как считается число пустых

Например:

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. Поэтому подробно разбираем:

  1. заголовок SQL-файла;
  2. структуру таблицы;
  3. один типовой INSERT.

Дальше все остальные INSERT устроены точно так же.

Разбор начала файла

Строка 1

DROP TABLE IF EXISTS specialities;

Что делает:

  • удаляет таблицу specialities, если она уже существует.

Зачем нужна:

  • чтобы скрипт можно было запускать повторно.

Строка 2

DROP SEQUENCE IF EXISTS specialities_id_seq;

Что делает:

  • удаляет последовательность, если она уже есть.

Строки 46

CREATE SEQUENCE specialities_id_seq
    START WITH 1
    INCREMENT BY 1;

Что делают:

  • создают последовательность;
  • первый номер будет 1;
  • дальше увеличение на 1.

Строки 819

Создают таблицу specialities.

Строка 9

id INTEGER NOT NULL,

Числовой идентификатор, обязательный.

Строка 10

name VARCHAR(102) NOT NULL,

Текстовое поле длиной до 102 символов.

Почему 102:

  • это максимальная длина, найденная в XML.

Строка 11

code VARCHAR(8) NOT NULL,

Поле кода длиной до 8 символов.

Строки 1217

Поля со встроенными ограничениями 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

Комментарий.

Строки 1617

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. Что можно коротко сказать преподавателю

  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 получаются автоматически, а не пишутся вручную.