JDBC, обработка полученных результатов, интерфейсы ResultSet, ResultSetMetaData.




ResultSet

ResultSet содержит все строки, удовлетворяющие условиям в SQL-выражении и предоставляет доступ к данным в этих строках посредством набора get-методов, которые организуют доступ к колонкам текущей строки. Метод ResultSet.next используется для перемещения к следующей строке ResultSet, делая ее текущей.

Набор данных результата (result set) является таблицей с заголовками колонок и соответствующих значений, возвращенных запросом. Например, если мы имеем запрос SELECT a, b, c FROM Table1, то набор результата будет в следующей форме:

a b c

-------- --------- --------

12345 Cupertino CA

83472 Redmond WA

83492 Boston MA

Следующий фрагмент кода демонстрирует выполнение SQL-запроса, который возвращает коллекцию строк, в которой колонка 1 - это int, колонка 2 - String и колонка 3 – вещественное число:

java.sql.Statement stmt = conn.createStatement();

ResultSet r = stmt.executeQuery("SELECT a, b, c FROM Table1");

while (r.next())

{

// Напечатать значения в текущей строке.

int i = r.getInt("a");

String s = r.getString("b");

float f = r.getFloat("c");

System.out.println("ROW = " + i + " " + s + " " + f);

}

Строки и курсоры

ResultSet содержит т.н. курсор, который указывает на текущую строку данных. Каждый раз, когда выполняется метод next, курсор перемещается на одну строку вниз. Изначально курсор спозиционирован перед первой строкой, и первый вызов next премещает его на первую строку (она становится текущей). С каждым успешным вызовом next курсор перемещается вниз на одну строку, начиная с самой верхней в ResultSet.

Курсор сохраняется до тех пор, пока не закроется объект ResultSet или его родительский объект Statement.

В SQL курсор для результирующей таблицы имеет имя. Если БД поддерживает позиционированные обновления или позиционированные удаления, то командам обновления или удаления можно передать в качестве параметра имя курсора. Это имя может быть получено с помощью вызова getCursorName.

Заметим, что не все СУБД поддерживают позиционированные обновления или удаления. Чтобы узнать, поддерживает ли данное соединение эти операции или нет, можно вызвать методы DatabaseMetaData.supportsPositionedDelete и supportsPositionedUpdate.

Колонки

Методы getXXX предоставляют доступ к значениям в колонках в текущей строке. В пределах одной строки значения могут быть считаны в любом порядке, но ради обеспечения большей совместимости рекомендуется считывать их подряд слева направо и делать это только один раз.

Для указания колонки можно использовать либо ее имя, либо ее номер. Например, если вторая колонка объекта ResultSet rs называется "title" и хранит строковое значение, то извлечь его можно одним из двух способов:

String s = rs.getString("title");

String s = rs.getString(2);

Колонки нумеруются слева направо, начиная с 1. Имена колонок в вызове методов getXXX нечувствительны к регистру букв.

Информацию о колонках в ResultSet можно получить с помощью вызова ResultSet.getMetaData. Возвращаемый объект ResultSetMetaData содержит информацию о количестве, типах и свойствах колонок объекта ResultSet.

Если известно имя колонки, но не ее индекс, то для поиска номера колонки можно использовать метод findColumn.

Типы данных и их преобразование

Методы getXXX пытаются сконвертировать низкоуровневые данные в типы данных языка Java. Например, метод если метод getXXX - это getString и тип данных в БД - VARCHAR, драйвер JDBC сконвертирует VARCHAR в объект String. Возвращаемым из метода getString значением будет Java-объект String.

Использование потоков для очень больших значений

С помощью ResultSet возможно получать очень большие данные типа LONGVARBINARY или LONGVARCHAR. Методы getBytes и getString возвращают эти данные в виде одного большого куска (вплоть до пределов, которые можно узнать с помощью метода Statement.getMaxFieldSize). Тем не менее, может оказаться удобнее считывать очень большие данные небольшими кусками. Это делается с помощью потоков (java.io.InputStream), которые возвращаются некоторыми методами ResultSet. Обратите внимание на то, что к этим потокам надо обращаться сразу, так как они будут закрыты при следующем вызове getXXX объекта ResultSet. (Такое поведение диктуется низкоуровневой реализацией доступа к большим двоичным объектам)

Значения NULL в результатах

Для того, чтобы определить, равно ли значение колонки NULL или нет, надо сначала считать значение колонки, а затем использовать метод ResultSet.wasNull для выяснения этого факта. Значение true означает, что считанное значение равно NULL.

 

Нет никакой необходимости закрывать ResultSet; это делается автоматически родительским объектом Statement, когда последний закрывается, выполняется повторно или используется для извлечения следующего результата в последовательности нескольких результатов.


 

12. Объектно-реляционное отображение. Создание персистентных классов при помощи JPA

ORM берет на себя “превращение” таблицы в объект.

Технология JPA является абстракцией над JDBC и позволяет быть независимым от SQL. Все классы и интерфейсы JPA расположены в пакете javax.persistence, основными составляющими технологии являются:

· ORM (механизм объектно-реляционного отображения);

· Entity manager API — позволяет осуществлять базовые операции CRUD;

· JPQL и Criteria API — механизмы извлечения данных;

· Управление транзакциями и блокировками (как с использованием JTA, так и без);

· Механизмы обратных вызовов и listener-ов.

Hibernate - это механизм отображения в реляционной базе данных объектов java.

Hibernate не только решает задачу связи классов Java с таблицами базы данных (и типов данных Java с типами данных SQL), но также предоставляет средства для автоматической генерации и обновления набора таблиц, построения запросов и обработки полученных данных и может значительно уменьшить время разработки, которое обычно тратится на ручное написание SQL- и JDBC-кода.

Персистентные классы определяются в элементе class:

Часть элемента класс (Служит для определения как загружать и сохранять объекты персистентного класса):

<hibernate-mapping package="ru.topcode.hibertest.domain">

<class name="User" table="user_list">

<id name="id" column="UserId">

<generator class="native"/>

</id>

<property name="name" column="Login"/>

<property name="psw"/>

</class>

</hibernate-mapping>

(1) name: Полное наименование Java класса персистентного класса или интерфейса.
(2) table: Наименование таблицы БД.
Пример: @Entity // Указываем что класс является сущностью @Table(name = "user_list") // и хранится в таблице user_list

public class User {

@Id // уникальным ID записи у нас будет свойство “id”

private long id;

private String name;

private String psw;

public String GetName(){return name};

public void setName(string name){

this.name=name};

}

Далее создаем файл META-INF/persistence.xml. Основной конфигурационной единицей JPA является Persistence Unit – в нем описывается тип провайдера, который предоставляет “услуги” JPA а также список классов, за которые он “отвечает” – JPA-сущностей.
В блоке <properties> описываются параметры доступа к базе данных, её тип, настройки логирования etc.

 

<?xml version="1.0"?>

<persistence version="1.0"

xmlns="https://java.sun.com/xml/ns/persistence" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="https://java.sun.com/xml/ns/persistence

https://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">

<persistence-unit name="Наименование Persistence Unit-a" transaction-type="тип транзакции">

<provider>наименование провайдера, например оrg.apache.openjpa.persistence.PersistenceProviderImpl</provider>

<jta-data-source>наименование источника данных</jta-data-source>

<properties>

Тут определяются специфические для провайдера свойства, например

<property name="openjpa.ConnectionDriverName" value="oracle.jdbc.OracleDriver"/>

</properties>

</persistence-unit>

</persistence>

 

Наименование Persistence Unit-a - это именование экземпляра Unit-a на сервере приложения. По этому имени в дальнейшем нужно будет получать Enterprise Manager-ы. Enterprise Manager - это объект, который выполняет управление всеми процессами JPA для данного Unit-a.

Тип транзакции - Наименование типа транзакции. JPA технология поддерживает работу с транзакциями СУБД на разных уровнях. Для источников данных расположенных на сервере приложений необходимо использовать значение JPA для типа транзакции. В этом случае следить за своевременными выполнениями commit и rollback процедурами будет контейнер (он же сервер приложений). В этом случае, однако усложняется "ручное" влияние на эти процессы.

Наименование провайдера - это наименование класса-реализации JPA. Т.к. в J2EE используется только описание JPA, то конкретная реализация возлагается на плечи сторонних разработчиков. Тут выделяются Toplink, Hibernate, OpenJPA и т.д. Рекомендуется использовать Hibernate, т.к. это наиболее используемая технология. Однако в зависимости от сервера приложений такое предпочтение может меняться. Например, в состав сервера приложений уже входит некоторая реализация JPA.

Наименование источника данных - JNDI имя источника данных (Data Source), объявленного на сервере приложений. Существует возможность объявить набор источников данных на сервере приложений и возложить задачу манипулирования драйверами, пулами соединений и другими сопутствующими объектами на сервер приложений. Это существенно упрощает разработку. В таком случае, нам необходимо только лишь обратиться к заранее подготовленному источнику.

Свойства провайдера - эти свойства могут сильно отличаться в зависимости от используемого провайдера. Общие рекомендации указать нельзя, необходимо читать документацию конкретного выбранного провайдера. Для провайдера в примере мы указываем драйвер, с помощью которого тот должен общаться с СУБД.

 

А также JPA требует наличия у каждого класса-сущности конструктора по умолчанию:

public User() {}

Управление сущностями (записями) в JPA производится с помощью экземпляра EntityManager-а.
Для получения экземпляра EntityManager воспользуемя кодом:

import javax.persistence.EntityManager;

import javax.persistence.EntityManagerFactory;

import javax.persistence.Persistence;

//...

try {

EntityManagerFactory factory = Persistence.createEntityManagerFactory("Name");

EntityManager manager = factory.createEntityManager();

} finally {

if (manager!=null) manager.close();

if (factory!=null) factory.close();

}

где “Name” – имя нашего PersistenceUnit-а


 

13. Объектно-реляционное отображение. Подключаемы провайдеры персистенции.

ORM берет на себя “превращение” таблицы в объект.

Технология JPA является абстракцией над JDBC и позволяет быть независимым от SQL. Все классы и интерфейсы JPA расположены в пакете javax.persistence, основными составляющими технологии являются:

· ORM (механизм объектно-реляционного отображения);

· Entity manager API — позволяет осуществлять базовые операции CRUD;

· JPQL и Criteria API — механизмы извлечения данных;

· Управление транзакциями и блокировками (как с использованием JTA, так и без);

· Механизмы обратных вызовов и listener-ов.

 

<?xml version="1.0"?>

<persistence version="1.0"

xmlns="https://java.sun.com/xml/ns/persistence" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="https://java.sun.com/xml/ns/persistence

https://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">

<persistence-unit name="Наименование Persistence Unit-a" transaction-type="тип транзакции">

<provider>наименование провайдера, например оrg.apache.openjpa.persistence.PersistenceProviderImpl</provider>

<jta-data-source>наименование источника данных</jta-data-source>

<properties>

Тут определяются специфические для провайдера свойства, например

<property name="openjpa.ConnectionDriverName" value="oracle.jdbc.OracleDriver"/>

</properties>

</persistence-unit>

</persistence>

 

Наименование Persistence Unit-a - это именование экземпляра Unit-a на сервере приложения. По этому имени в дальнейшем нужно будет получать Enterprise Manager-ы. Enterprise Manager - это объект, который выполняет управление всеми процессами JPA для данного Unit-a.

Тип транзакции - Наименование типа транзакции. JPA технология поддерживает работу с транзакциями СУБД на разных уровнях. Для источников данных расположенных на сервере приложений необходимо использовать значение JPA для типа транзакции. В этом случае следить за своевременными выполнениями commit и rollback процедурами будет контейнер (он же сервер приложений). В этом случае, однако усложняется "ручное" влияние на эти процессы.

Наименование провайдера - это наименование класса-реализации JPA. Т.к. в J2EE используется только описание JPA, то конкретная реализация возлагается на плечи сторонних разработчиков. Тут выделяются Toplink, Hibernate, OpenJPA и т.д. Рекомендуется использовать Hibernate, т.к. это наиболее используемая технология. Однако в зависимости от сервера приложений такое предпочтение может меняться. Например, в состав сервера приложений уже входит некоторая реализация JPA.

Наименование источника данных - JNDI имя источника данных (Data Source), объявленного на сервере приложений. Существует возможность объявить набор источников данных на сервере приложений и возложить задачу манипулирования драйверами, пулами соединений и другими сопутствующими объектами на сервер приложений. Это существенно упрощает разработку. В таком случае, нам необходимо только лишь обратиться к заранее подготовленному источнику.

Свойства провайдера - эти свойства могут сильно отличаться в зависимости от используемого провайдера. Общие рекомендации указать нельзя, необходимо читать документацию конкретного выбранного провайдера. Для провайдера в примере мы указываем драйвер, с помощью которого тот должен общаться с СУБД.


 

14. Кастомизация мэппинга персистентных классов на поля и таблички БД.

Мэппинг пишется в виде xml-файла следующей структуры

<class name="logic.Bus" table="busses">

<id column="bus_id" name="id" type="java.lang.Long">

<generator class="increment"/>

</id>

<property column="number" name="number" type="java.lang.String"/>

<set name="drivers" table="busDriver" lazy="false">

<key column="bus_id"/>

<many-to-many column="driver_id" class="logic.Driver"/>

</set>

</class>

Для того, чтобы не писать полное имя класса, можно указать используемый пакет.

name: Полное наименование Java класса персистентного класса или интерфейса.
table: Наименование таблицы БД. Id: описывает идентификатор. Параметр column указывает на какую колонку в таблице будет ссылаться поле id нашего объекта, так же указываем класс и указываем generator, который отвечает за генерацию id.
Property: описывает простое поле нашего объекта, в качестве параметров указываем имя поля, его класс и имя колонки в таблице.
Set: описывает поле в котором содержится некий набор(коллекция) объектов. Тег содержит параметр name - имя поля нашего объекта, параметр table - имя таблицы связи(в случае отношения многие ко многим) и параметр lazy. Так называемые ленивые коллекци. Когда мы в параметре lazy указываем значечение false, то у нас при получении объекта Route из базы вместе с объектом достается и коллекция объектов Bus, так как busses это поле объекта Route. А если в качестве параметра мы указываем значение true, то коллекция объектов Bus не вытаскивается, для ее получения надо явно вызывать метод route.getBusses().
Тег key имеет параметр column, который говорит, на какую колонку в таблице связи будет ссылаться поле нашего объекта.
Тег many-to-many описывает связь типа многие ко многим, в качестве параметров тег использует column - имя колонки второй колонки в таблице связи и параметр class, указывающий какого класса будут объеты на той стороне.

 


 

15. Объектно-реляционное отображение. Отображение реляционных связей many-to-many, one-to-many, one-to-one.

Many-to-many

<many-to-many column="column_name" (1) class="ClassName" (2) outer-join="true|false|auto" (3) />
(1) column (необязательно): Имя колонки.
(2) class (необязательно - по умолчанию определяется рефлексией исходя из типа поля): Имя ассоциированного класса.
(3) outer-join (optional - defaults to auto): enables outer-join fetching for this association when hibernate.use_outer_join is set.

 

One-to-many

<one-to-many column="column_name" (1) class="ClassName" (2) outer-join="true|false|auto" (3) />
(1) column (необязательно): Имя колонки.
(2) class (необязательно - по умолчанию определяется рефлексией исходя из типа поля): Имя ассоциированного класса.
(3) outer-join (optional - defaults to auto): enables outer-join fetching for this association when hibernate.use_outer_join is set.

 

Many-to-one

Обычная связь с другим персистентным классов объявляется используя элемент many-to-one. В реляционных терминах это ассоциация многих к одному. В действительности это просто ссылка на объект.

<many-to-one

name="propertyName" (1)

column="column_name" (2)

class="ClassName" (3)

cascade="all|none|save-update|delete" (4)

outer-join="true|false|auto" (5)

update="true|false" (6)

insert="true|false" (6)

property-ref="propertyNameFromAssociatedClass" (7)

access="field|property|ClassName" (8)

/>

(1)   name: Имя свойства.
(2)   column (необязательно): Имя колонки.
(3) class (необязательно - по умолчанию тип поля определяется через рефлексию): Имя ассоциированного класса.
(4) cascade (необязательно): Определяет, какая операция будет выполняться каскадом от родительского объекта к ассоциированному.
(5) outer-join (необязательно - по умолчанию auto): Задействует извлечение ассоциированных объектов, используя объединения outer-join если опция hibernate.use_outer_join конфигурационного файла включена.
(6) update, insert (необязательно - по умолчанию true) определяет то, что отображаемые колонки будут включены в SQL-запросы UPDATE и/или INSERT. Установка обоих свойств в false позволяет задавать значение этого свойства либо из другого свойства, которое отображено в той же колонке/колонках, либо посредством триггера, либо другим приложением.
(7) property-ref: (необязательно) Имя ключевого свойства ассоциированного класса. По этому свойству будет происходить связывание (join). Если не указано, то используется первичный ключ ассоциированного класса.
(8) access (необязательно - по умолчанию property): Стратегия, которую использует Hibernate для доступа к значению данного поля.

Атрибут cascade может принимать следующие значения: all, save-update, delete, none. Установка значения отличного от none повлечет определенные операции над ассоциированным (дочерним) объектом. Атрибут outer-join может принимать три следующих значения:

· auto (по умолчанию) извлекает ассоциированные объекты используя outer join если ассоциированный класс не имеет прокси.

· true Всегда извлекать ассоциированные объекты используя outer join.

· false Никогда не извлекать ассоциированные объекты используя outer join.

Типичное объявление ассоциации many-to-one выглядит так

<many-to-one name="product" class="Product" column="PRODUCT_ID"/>

 

One-to-one

Ассоциация "один к одному" с другим персистентным классом можно объявить, используя элемент one-to-one.

<one-to-one

name="propertyName" (1)

class="ClassName" (2)

cascade="all|none|save-update|delete" (3)

constrained="true|false" (4)

outer-join="true|false|auto" (5)

property-ref="propertyNameFromAssociatedClass" (6)

access="field|property|ClassName" (7)

/>

(1) name: Имя свойства.
(2) class (необязательно - по умолчанию определяется рефлексией исходя из типа поля): Имя ассоциированного класса.
(3) cascade (необязательно) определяет какая операция будет выполняться каскадом от родительского объекта к ассоциированному.
(4) constrained (необязательно) определяет то, что внешний ключ, ссылающийся на таблицу ассоциированного класса, ограничен первичным ключом этой таблицы. Эта опция влияет на порядок, в котором выполняются каскадные операции save() и delete() (а так же используется утилитой экспортирующей схему - schema export tool).
(5) outer-join (необязательно - по умолчанию auto): Задействует извлечение ассоциированных объектов, используя объединения outer-join если опция hibernate.use_outer_join конфигурационного файла включена.
(6) property-ref: (необязательно) Имя свойства ассоциированного класса, которое входит в первичный ключ данного класса. Если не указано, то используется первичный ключ ассоциированного класса.
(7) access (необязательно, по умолчанию property): Стратегия, которую должен использовать Hibernate для доступа к данному полю.

 


 

16. Объектно-реляционное отображение. Жизненный цикл персистентных объектов (entity lifecycle)

EntityManager

• Управляет жизненным циклом Entity объектов

> persist() - помещает объект в БД

> remove() - удаляет объект из БД

> merge() - синхронизирует с БД состояние отсоединенного объекта

> refresh() - обновляет из БД состояние объекта

Persist

public Order createNewOrder(Customer customer) {

// Создаем новый объект

Order order = new Order(customer);

// После вызова метода persist() объект меняет свой

// статус на управляемый. Во время очередной

// операции записи в БД обект будет помещен в БД.

entityManager.persist(order);

return order;

}

Find и Remove

public void removeOrder(Long orderId) {

Order order =

entityManager.find(Order.class, orderId);

// Объект будет удален из БД при очередной

// операции записи в БД. Доступ к удаленному

// объекту приводит к непредсказуемым

// результатам.

entityManager.remove(order);

}

Merge

public OrderLine updateOrderLine(OrderLine orderLine) {

// Метод merge возвращает управляемую копию

// переданного отсодиненного объекта. Если состояние

// отсоединного объекта было изменено, то изменения

// будут отражены в возвращаемой копии.

return entityManager.merge(orderLine);

}


Жизненный цикл Entity


17. Объектно-реляционное отображение. Интерфейс EntityManager.

Интерфейс Entity Manager используется для взаимодействия с persistence context.

Entity Manager обладает возможностями:

  • Записывать объекты в хранилище
  • Сохранять как простые, так и композитные (вложенные) объекты
  • Получать объекты из хранилища по имени класса или идентификатору объекта
  • Синхронизируется с модулем поиска
  • Хранит историю изменений
  • Хранит связи между объектами

Естественно, существуют аналогичные модулю Entity Manager разработки, наиболее известной свободно-распространяемой из которых является библиотека Hibernate

Плюсы

  • Модуль EM представляет собой web-сервис, что предаёт ему автономность и возможность использования несколькими клиентами одновременно
  • Более лёгкая настройка при подготовке к работе по сравнению с Hibernate
  • Основное отличие, более высокая скорость работы

Минусы

  • В EM при подключении к базе данных нет возможности управлять форматом сохранения, нельзя напрямую работать с базой данных
  • Hibernate поддерживает больше типов коллекций (Map, Set и т. д.), в EM реализована поддержка только типа List

Следующий пример показывает, как создать менеджер сущностей и как сохранить сущность Book:

EntityManagerFactory emf = Persistence.createEntityManagerFactory("chapter02PU");
EntityManager em = emf.createEntityManager();
em.persist(book);



 

18. Объектно-реляционное отображение. Создание запросов на JPQL, SQL

Подобно JDBC, технология JPA позволяет нам выполнять запросы к БД с использованием

языков запросов SQL и JPQL (Java Persistence Query Language).

Методы интерфейса EntityManager, предназначенные для создания запросов.

Query createQuery(String jpaQuery) Создает запрос к БД на языке JPQL.

Query createNativeQuery(String sqlQuery) Создает SQL -запрос в диалекте, специфичном для

конкретной СУБД.

Query createNamedQuery(String queryName) Создает именованный запрос.

По своим синтаксическим конструкциям JPQL очень похож на SQL. Однако, если SQL предназначен для работы с реляционной моделью данных, то в JPQL вся работа производится с Java -объектами.

JPQL обладает одним важнейшим свойством — переносимостью. Как известно, имеющиеся СУБД используют различные диалекты SQL, в общем случае несовместимые между собой. Синтаксис JPQL не привязан к диалекту SQL какой-либо СУБД. Все методы возвращают объект класса JPA -провайдера, реализующего интерфейс javax.persistence.Query, который является объектным представлением запроса к БД. Query похож на java.sql.Statement в JDBC и предназначен для контроля выполнения запроса и получения результатов.

Пример:

private Customer findCustomerByPhoneNumber(String phoneNumber) {

Customer customer = null;

String queryStr = "SELECT OBJECT(c) "

+ "FROM Customer AS c, IN(c.phones) p "

+ "WHERE p.phoneNumber =:phoneNumber";

Query query = manager.createQuery(queryStr);

query.setParameter("phoneNumber", phoneNumber);

EntityTransaction t = null;

try {

t = manager.getTransaction();

t.begin();

customer = (Customer) query.getSingleResult();

t.commit();

} catch (Exception e) {

// Откат транзакции и обработка возникшего исключения

...

}

return customer;

}

Результатом выполнения нашего запроса является единственное значение, поэтому для

получения объекта класса Customer мы используем метод getSingleResult. Если

результатом запроса будет набор значений, метод getSingleResult сгенерирует

исключение javax.persistence.NonUniqueResultException. В случае, если не будет

выбрано ни одной строки, метод сгенерирует javax.persistence.NoResultException.

Для получения списка объектов следует вызвать метод getResultList.

SQL запросы преставляются через тот же Query интерфейс, который используется для JPQL запросов. Единствоенное различие заключается в том, что для SQL используется метод Session.createSQLQuery().

Query sqlQuery = sess.createSQLQuery("select * from cats ", Cat);sqlQuery.setMaxResults(50);List cats = sqlQuery.list();

Три параметра используемые при вызове createSQLQuery():

· строка SQL запроса

· возвращаемый запросом персистентный класс

Именованные SQL запросы могут быть определены в документе маппинга и вызваны в точности так же, как это осуществляется для HQL запросов.

List people = sess.getNamedQuery("mySqlQuery").setMaxResults(50).list(); <sql-query name="mySqlQuery"> <return alias="person" class="eg.Person"/> SELECT {person}.NAME AS {person.name}, {person}.AGE AS {person.age}, {person}.SEX AS {person.sex} FROM PERSON {person} WHERE {person}.NAME LIKE 'Hiber%'

</sql-query>


 

19. Работа с XML в Java. Правильно сформированные (well-formed) и корректные (valid) XML документы

Поскольку сейчас очень часто информация хранится и передается в виде XML-документов, для разработки Web-приложений большое значение имеют средства работы с XML. Основными элементами, необходимыми для облегчения работы с XML-документами, являются их разбор и внутреннее представление XML-данных.

Библиотеки для работы с XML-документами находятся в пакетах javax.xml, org.w3c.dom и org.xml.sax, a также во вложенных в них пакетах.

Понятие корректно сформированных (well-formed) XML-документов

Документ называется корректно сформированным, если он соответствует минимальному набору правил для XML-документов:

1. XML-документ должен иметь только один корневой элемент (элемент "Документ"). Все другие элементы должны быть вложены в корневой элемент.

2. Элементы должны быть вложены упорядоченным образом. Если элемент начинается внутри другого элемента, он должен и заканчиваться внутри этого элемента.

3. Каждый элемент должен иметь начальный и конечный теги. В отличие от HTML, в XML не разрешается опускать конечный тег - даже в том случае, когда браузер в состоянии определить, где заканчивается элемент.

4. Название элемента в начальном теге должно в точности соответствовать (с учетом регистра) названию в соответствующем конечном теге.

5. Название элемента должно начинаться с буквы или с символа подчеркивания (_), после чего могут идти буквы, цифры, символы точки (.), тире (-) или подчеркивания.

Это базовые критерии корректного формирования. Для других понятий языка XML (атрибутов, примитивов, связей) действуют свои правила, которые необходимо соблюдать. Можно сказать, что если документ создан правильно, верно и при его отображении и использовании не возникает никаких ошибок, то это и есть корректно сформированный документ. Если вы ошибетесь в каком-либо теге HTML-страницы, браузер просто проигнорирует соответствующий тег, а ошибка в теге XML сделает невозможным отображение страницы. В этом смысле написание XML похоже на программирование на C# - компилятор не запустит программу при наличии синтаксических ошибок.

Создание действительных (valid) XML-документов. Определение типа документа (DTD)

Любой XML-документ должен отвечать минимальным требованиям по составлению, т.е. быть корректно сформированным. Если документ содержит ошибки, он не может считаться XML-документом.

Корректно сформированный XML-документ также может быть действительным (valid). Действительным называется корректно сформированный (well-formed) документ, отвечающий двум дополнительным требованиям1):

1. Пролог документа должен содержать специальное объявление типа документа, которое включает определение типа документа (Data Type Definition, DTD), задающее структуру документа.

2. Корневой элемент должен отвечать структуре, заданной в DTD.

Использование критерия действительности необходимо для включения XML-документа в группу схожих документов, отвечающих определенной структуре или набору стандартов. Достаточно один раз выработать схему DTD и затем просто подключать ее к создаваемым документам. Стандарт XML определяет DTD как "грамматику для определенного класса документов".

Объявление типа документа представляет собой блок XML-разметки, который располагается в любом месте пролога корректно сформированного документа. Оно имеет следующую обобщенную форму записи:

<!DOCTYPE Название_корневого_элемента DTD>

DTD представляет собой определение типа документа. Оно состоит из символа левой квадратной скобки ([), после которой следует ряд объявлений разметки, заканчивающихся правой квадратной скобкой (]). Объявления разметки описывают логическую структуру документа, т.е. задают элементы документа, атрибуты и другие компоненты. Действительный XML-документ, содержащий DTD с единственным объявлением разметки, которое определяет один тип элемента в документе, TABLE, выглядит так (рис).


Рис. Простейший документ с DTD

В этом примере DTD документа указывает, что он может содержать только элементы типа TABLE (это единственный заданный тип элемента) и что элемент TABLE может иметь любое допустимое для данного типа содержимое (ключевое слово ANY).

DTD может содержать различные типы объявлений разметки: Объявления типов элементов – Они определяют типы элементов, которые может содержать документ, а также содержимое и порядок следования элементов, Объявления списков атрибутов – Каждое объявление списков атрибутов задает имена атрибутов, которые могут быть использованы с определенным типом элемента, а также типы данных и устанавливаемые по умолчанию значения этих атрибутов, Объявления примитивов – Вы можете использовать примитивы для хранения часто используемых фрагментов текста или для встраивания не относящихся к XML данных в ваш документ, Объявления нотаций – Нотация описывает формат данных или идентифицирует программу, используемую для обработки определенного формата, Инструкции по обработке, Комментарии, Ссылки на параметрические примитивы.

Объявление типа элемента имеет следующую обобщенную форму:

<!ELEMENT Название_элемента описание_содержимого>


 



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2016-02-16 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: