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

1118 lines
31 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
<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`.
Пример:
```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 version="1.0" encoding="UTF-8"?>
```
Что делает:
- объявляет XML-документ;
- указывает версию XML;
- задаёт кодировку UTF-8.
Зачем нужна:
- чтобы парсер понимал, что это XML;
- чтобы русские буквы читались правильно.
### Строка 2
```xml
<objects type="array">
```
Что делает:
- открывает корневой контейнер;
- атрибут `type="array"` говорит, что внутри набор однотипных объектов.
Зачем нужна:
- у XML должен быть один корневой элемент;
- все записи нужно куда-то вложить.
### Строка 3
```xml
<object>
```
Что делает:
- открывает одну запись.
Зачем нужна:
- каждая специальность хранится как отдельный объект.
### Строка 4
```xml
<id type="integer">307</id>
```
Что делает:
- хранит идентификатор из исходного XML;
- атрибут `type="integer"` подсказывает, что значение числовое.
Зачем нужна:
- поле участвует в анализе структуры данных;
- по заданию его значение не вставляется в БД напрямую, но само поле всё равно существует в исходном файле.
### Строка 5
```xml
<name>Технологии разделения изотопов и ядерное топливо</name>
```
Что делает:
- хранит название специальности.
Зачем нужна:
- это основной текстовый атрибут записи;
- по нему определяется максимальная длина поля `name`.
### Строка 6
```xml
<code>14.05.03</code>
```
Что делает:
- хранит код специальности.
Зачем нужна:
- используется в таблице и в `INSERT`.
### Строка 7
```xml
<level>Специалитет</level>
```
Что делает:
- хранит уровень образования.
Зачем нужна:
- по этому полю видно, что допустимых значений немного;
- поэтому для него логично сформировать `CHECK`.
### Строка 8
```xml
<level-id type="integer">1</level-id>
```
Что делает:
- хранит числовой код уровня.
Зачем нужна:
- это более компактный числовой эквивалент поля `level`.
### Строка 9
```xml
<generation>ФГОС3+</generation>
```
Что делает:
- хранит поколение стандарта.
Зачем нужна:
- используется и в анализе, и в SQL.
### Строка 10
```xml
<generation-id type="integer">1</generation-id>
```
Что делает:
- хранит числовой код поколения.
### Строка 11
```xml
<type>специальность</type>
```
Что делает:
- хранит тип образовательной позиции.
### Строка 12
```xml
<type-id type="integer">1</type-id>
```
Что делает:
- хранит числовой код поля `type`.
### Строка 13
```xml
</object>
```
Что делает:
- закрывает одну запись.
### Строки 14 и далее
Дальше идёт следующий `object` с точно такой же структурой:
- открывается `<object>`;
- внутри девять полей;
- затем `</object>`.
То есть весь файл дальше — это просто повторение одной и той же схемы для разных специальностей.
### Последняя строка файла
```xml
</objects>
```
Что делает:
- закрывает корневой контейнер.
## Простое объяснение
XML-файл — это как большая таблица, только записанная не в строках Excel, а во вложенных тегах.
---
# 5.2. Файл `specialities.xsl`
## Что делает файл
Это главный логический файл работы.
Он:
1. читает XML;
2. выводит анализ полей;
3. собирает SQL-код создания таблицы;
4. выводит отдельные `INSERT` по всем объектам;
5. формирует итоговый HTML.
Ниже — подробный разбор по строкам и блокам.
## Разбор файла `specialities.xsl`
### Строка 1
```xml
<?xml version="1.0" encoding="UTF-8"?>
```
Это объявление XML для самого XSLT-файла.
### Строка 2
```xml
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
```
Что делает:
- открывает XSLT-документ;
- объявляет пространство имён `xsl`;
- указывает, что используется XSLT 1.0.
Зачем нужно:
- без этого процессор не поймёт, что перед ним XSLT.
### Строка 3
```xml
<xsl:output method="html" encoding="UTF-8" indent="yes"/>
```
Что делает:
- говорит, что результат преобразования будет HTML;
- кодировка UTF-8;
- `indent="yes"` просит красиво форматировать результат.
---
## Блок ключей: строки 5–11
```xml
<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
```xml
<xsl:template name="escape-sql">
```
Создаёт именованный шаблон.
### Строка 15
```xml
<xsl:param name="text"/>
```
Принимает входной текст.
### Строки 1627
Логика такая:
- если в тексте есть `'`,
- то она заменяется на `''`,
- потому что в SQL именно так экранируют одинарную кавычку.
Зачем это нужно:
- чтобы SQL не ломался на строковых значениях.
---
## Блоки `show-not-null-text` и `sql-not-null`: строки 3043
### `show-not-null-text`
Выводит на HTML строку:
```html
Нужен: NOT NULL
```
только если число пустых значений равно 0.
### `sql-not-null`
Добавляет в SQL-фрагмент текст:
```sql
NOT NULL
```
тоже только если пустых значений нет.
Это важно, потому что ограничение теперь не написано «по умолчанию», а выводится по фактическому анализу XML.
---
## Главный шаблон `match="/"`: строки 45118
Это входная точка преобразования.
Когда XSLT начинает работу, он сначала попадает именно сюда.
### Строки 4658
Создают обычную HTML-обёртку:
- `<html>`
- `<head>`
- `<meta>`
- `<title>`
- `<style>`
### Строки 5156
Простой CSS:
- задаёт шрифт;
- размер заголовков;
- отступы;
- стиль для SQL-блоков.
### Строки 5961
Начало `<body>` и заголовки страницы.
### Строки 6371
```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`: строки 96117
### Строка 96
```xml
<xsl:for-each select="objects/object">
```
Что делает:
- запускает цикл по всем объектам XML.
Это ключевая часть задания.
### Строка 97
```xml
<div class="sql">
```
Каждый `INSERT` выводится в отдельном HTML-блоке.
Зачем это хорошо:
- на странице визуально видно, что для каждого `object` создаётся отдельный запрос.
### Строки 97116
Печатают 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;
```
Что делает:
- удаляет последовательность, если она уже есть.
### Строки 46
```sql
CREATE SEQUENCE specialities_id_seq
START WITH 1
INCREMENT BY 1;
```
Что делают:
- создают последовательность;
- первый номер будет 1;
- дальше увеличение на 1.
### Строки 819
Создают таблицу `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 символов.
#### Строки 1217
Поля со встроенными ограничениями `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
```
Комментарий.
### Строки 1617
```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 получаются автоматически, а не пишутся вручную**.