1118 lines
31 KiB
Markdown
1118 lines
31 KiB
Markdown
# 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`: строки 13–28
|
||
|
||
Это шаблон для экранирования одинарных кавычек в SQL.
|
||
|
||
### Строка 14
|
||
|
||
```xml
|
||
<xsl:template name="escape-sql">
|
||
```
|
||
|
||
Создаёт именованный шаблон.
|
||
|
||
### Строка 15
|
||
|
||
```xml
|
||
<xsl:param name="text"/>
|
||
```
|
||
|
||
Принимает входной текст.
|
||
|
||
### Строки 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-обёртку:
|
||
- `<html>`
|
||
- `<head>`
|
||
- `<meta>`
|
||
- `<title>`
|
||
- `<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 получаются автоматически, а не пишутся вручную**.
|