Программирование на XML для DB2: Часть 1. Понимание модели данных XML (исходники)

Хардип Сингх (Hardeep Singh)

Введение

Как указано в рекомендациях w3, некоторые цели создания XML имеют отношение к разработке приложений:

  • "XML будет поддерживать широкий спектр приложений".
  • "Писать программы, которые обрабатывают XML-документы, будет просто".

Пока много внимания уделялось читаемости, сериализации и транспортировке, задача разработки приложений не наделала столько шуму.

Данная статья является первой в серии статей, показывающей влияние, которое оказал XML на разработку приложений, на трех уровнях:

  • В части 1 сформулированы предпосылки для применения XML в разработке приложений, чтобы сделать этот процесс простым, дешевым, переносимым и высококачественным. XML-программирование произвело почти такой же радикальный сдвиг в принцип разработки приложений в этом десятилетии, какой произвели объектные методологии в предыдущие десять лет.
  • В Части 2 мы сосредоточимся на роли базы данных. В данной статье мы уделим внимание функциональности и DB2 9 (изначально под кодовым названием Viper), и Viper 2. Вы узнаете:
    • Как новая среда хранения XML и запросов встраиваются в модель данных XML уровня приложений.
    • Почему схемы вашей базы данных становятся проще и естественнее, когда вы адаптируетесь к новой основанной на XML архитектуре разработки приложений.
    • Почему запросы XML-данных в базе данных не отличаются от запросов данных в приложении.
    • И, наконец, как сочетать реляционные данные с XML-данными, чтобы объединить сильные стороны обеих технологий.
  • В Части 3 мы поговорим о клиенте, обратив внимание на XML-технологии, используемые в Web-браузерах и Web-серверах: Ajax, XSLT, SVG, Comet, XML-каналы и mashup-приложения. Вы узнаете, как создавать каналы и Web-сервисы в базе данных, запрашивать и объединять их на уровне приложения и затем отображать в браузерах клиента.
  • Четвертая статья объединяет все эти технологии и предоставляет работающий пример из практики.

Основы модели данных в XML

Традиционно XML использовали для определения метаданных бизнес-документов. Для управления этими метаданными в приложении используется объектная модель документа (document object model, DOM). Если мы посмотрим на DOM, то увидим, что она обеспечивает объектный интерфейс для иерархической структуры данных XML, а программный интерфейс DOM управляет этой иерархией. Другими словами, DOM можно использовать как объектную оболочку для управления любой структурой данных, которая может быть представлена с помощью XML.

В XML-модели данных многие объекты данных приложения определяются на XML. Так как XML имеет иерархическую структуру, легко понять взаимосвязь между объектами данных в естественном, удобном для чтения формате.

 
Замечание:
Если ваши данные уже представлены в XML-формате, то оставшийся процесс будет естественным и очень простым. Даже если данные представлены в реляционном формате, вы все равно можете использовать предложенную методику, но потребуется взаимно однозначное преобразование реляционных данных в XML. Для этого можно использовать SQL/XML-функции публикации и нарезки. Большинство реляционных баз данных поддерживают эти функции наряду с другими технологиями преобразования. Для большинства разработчиков преобразование реляционных данных в иерархические (XML) только ради использования модели данных XML в разработке приложений может показаться ненужным. Но, будучи разработчиками, мы все время это делаем, когда преобразуем реляционные данные к объектным. Возможно, преимущества модели данных XML побудят многих разработчиков задуматься над использованием этой технологии в разработке приложений, даже если в бизнес-модели не нужны XML-данные.
 

Когда модель данных XML определена, DOM-парсер может ее обработать в приложении. Чтобы изолировать код приложения от API DOM, который используется для навигации и управления XML-моделью, вы можете создать оболочку вокруг реализаций DOM и XPath. Эта оболочка также сделает ваш код более переносимым.

Я приложил к данной статье пример Java-оболочки. Вы можете использовать его как готовый вариант или как шаблон для своей собственной оболочки. Бизнес-логика приложения напрямую управляет моделью XML с помощью API-оболочки. Измененные XML-данные можно легко сериализовать и передавать между различными объектами или различными уровнями в многоуровневых средах (SOA).

Сравнение модели данных XML и объектной модели

Большинство приложений состоит из бизнес-объектов, управляемых иерархиями объектов данных. В общем случае объекты данных - это тонкие оболочки бизнес-данных. Их главная цель состоит в том, чтобы управлять представлением упакованных данных бизнес-объектам. Еще одно преимущество оболочек для объектов заключается в том, что они позволяют представлять данные, хранящиеся в реляционных таблицах, в естественной иерархии объектов, где можно зафиксировать взаимосвязь между данными. Большая часть усилий, затрачиваемых на написание кода, уходит на создание таких объектных оболочек для приложений с бизнес-данными.

Так как XML по своей сути поддерживает взаимосвязь структур данных, то не имеет смысла создавать отдельную иерархию объектов, чтобы зафиксировать взаимосвязь между отдельными структурами данных. Кроме того, у XML есть стандартная объектная модель - DOM (объектная модель документов). Реализации этой модели применяются для конструирования, изменения и сериализации XML-данных. Грамотное использование языка XPath совместно с программными интерфейсами DOM делает задачу загрузки, изменения и сохранения XML-данных в бизнес-приложениях тривиальной.

Наглядный пример

Чтобы лучше понять разницу этих двух моделей, давайте посмотрим, как каждая модель влияет на разработку и реализацию приложения.

На примерах кода я покажу два подхода, используя простой сценарий с заказчиком и информацией о заказе.

Объектная модель данных

В подходе с объектной моделью данных нам сначала надо создать оболочку объектов, чтобы инкапсулировать заказчика (customer) и данные заказа (order data), см. листинги 1, 2 и 3.

Листинг 1. Создание заказчика

                
public class Customer
{
int customerid;
String firstname;
String lastname;
Items itemspurchased ;

Public Customer (int custid, Connection conn)
{
Statement dbstmt= conn.createStatement();
ResultSet dbResult = dbstmt.executeQuery("select fname, lname from
customer_table where customerid=custid");
customerid=custid;
SetFirstName(dbResult.getString(1));
SetLastName(dbResult.getString(2));
}
public String GetFirstName {return firstname;}
public Void SetFirstName (fname) {firstname=fname;}
public String GetLastName {return lastname ;}
public Void SetLastName (lname) {lastname=lname;}
public Items GetItemsList {return itemspurchased; }
public SetItemsList (list) { itemspurchased =list;}
}

Листинг 2. Создание класса items (покупки)

                
public class Items
{
Hashtable list=new Hashtable();

Public Items(int custid,Connection conn)
{
Statement dbstmt= conn.createStatement();
ResultSet dbResult = dbstmt.executeQuery("select itemid, description,
price, date from purchase_table where customerid=custid")
While (dbResult.rs.next ())
{
tempitem = new Item();
tempitem.SetID(dbResult. getString(1));
tempitem. SetDescription (dbResult. getString(2));
tempitem. Setprice (dbResult. getFloat(3));
tempitem. SetpurchaseDate (dbResult. getString(4));
Additem (tempitem);
}
}

public void AddItem (item oneitem) {list.put(oneitem.GetID(),oneitem);}
public Item GetItem (ItemID) {return list.get(String itemID);}
public Hashtable GetItems(){return list;}
public Items FindItemByPrice (flaot min, float max)
{
Items retList=new Items();
for (Enumeration e=list.elements () ; e.hasMoreElements() ; )
{
item tmpItem=(item)e.nextElement();
float price= tmpItem .GetPrice();
if(price >= min && price <=max)
{
retList.AddItem(tmpItem);
}
}
}
public Items FindItemByDate (purchaseDate) { }
}

Листинг 3. Создание определения item (покупка)

                
public class Item
{
String id;
String description;
String purchaseDate;
Float price;

Public void SetID (String ItemID) {id= ItemID;}
Public void SetDescription (String desc) { description = desc;}
Public void SetpurchaseDate (String pDate) { purchaseDate = pDate ;}
Public void Setprice (float pprice { price = pprice ;}
Public String GetID (){return id;}
Public String GetDescription(){return description;}
Public float GetPrice(){return price;}
}

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

Листинг 4. Управление объектами данных в приложении

                			
Customer customer = new Customer (custid,dbConnection)
customer.SetItemList (new Items(custid , dbConnection)) ;
Items list=customer.GetItemsList(). FindItemByPrice(15.0,25.50);
for (Enumeration e=list.elements () ; e.hasMoreElements() ; )
{
System.out.println(((item)e.nextElement()).GetDescription());
}

Из представленных примеров мы видим, что код для объектов данных экспоненциально больше, чем код, описывающий бизнес-логику. Так как оболочка объектов скрывает взаимосвязи между заключенными в ней бизнес-данными, необходимо, чтобы API оболочки объекта были хорошо задокументированы, чтобы разработчики приложений понимали, как правильно их использовать.

Простое перемещение между иерархиями объектов встроено в объектную модель данных, но расширенные средства поиска и перемещения приходится реализовывать для каждого критерия поиска (например, FindItemByPrice) отдельно.

Модель данных XML

Поскольку главным мотивом к использованию оболочек объектов была инкапсуляция бизнес-данных, их можно заменить моделью данных XML.

Листинг 5. Модель данных XML

                
<Customer customerid ="" firstname="" lastname="" >
<Items>
<Item ID="" description="" purchaseDate="" price="" />
</Items>
</Customer>

Теперь, если данные в базе данных уже хранятся в формате XML следующим образом:

  • данные покупателя (customer) в виде <Customer customerid ="" firstname="" lastname="" />
  • данные покупки (item) в виде <Item ID="" description="" purchaseDate="" price="" />

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

Давайте перепишем код приложения с использованием модели XML для хранения информации о покупателе и покупках. Чтобы создать экземпляр этой модели данных XML и управлять им, мы будем использовать класс DOM-оболочки XMLParser. Его можно загрузить в разделе "файлы для загрузки".

Первый случай - Данные хранятся в базе данных в формате XML

Листинг 6. Переписывание приложения с использованием модели XML

                
1. Statement dbstmt= conn.createStatement();
2. ResultSet dbResult = dbstmt.executeQuery("select custXML from
customer_table where customerid=custid");

3. XMLParse customerXML = new XMLParse(dbResult. getString(1));
4. customerXML.appendNode("/Customer", customerXML.createNode ("<Items/>"))

5. dbResult = dbstmt.executeQuery("select itemXML from purchase_table
where customerid=custid");
6. While (dbResult.rs.next ()) {
7. Node itemnode= customerXML.createNode (dbResult. getString(1));
8. customerXML.appendNode(itemnode ,"/Customer/Items",false);
}
9. customerXML.find("/Customer/Items/item[@price>15.0 and @price <25.5]",true);
10. for(int i=0;i < customerXML.currentFind.getLength();i++) {
11. System.out.println(customerXML.getValue("@description",i));
}

Первый запрос (вторая строка) возвращает XML-данные в столбце custXML для заданного покупателя. Эта XML-строка посылается в конструктор DOM-оболочки (третья строка), который, в свою очередь, с помощью XML-парсера обрабатывает иерархию объектов, представленную XML-данными.

Замечание: Так как у покупателя (customerXML) нет ни одной покупки, т.е. ни одного элемента Items (потому что мы так определили в XML- схеме для нашей модели), мы создаем новый элемент Items (четвертая строка) и присоединяем его как дочерний элемент к Customer.

Результат второго запроса (пятая строка) возвращает из базы данных список покупок, приобретенных покупателем (в XML-формате). Каждая покупка в списке (седьмая строка) прикрепляется (восьмая строка) к иерархии объектов в DOM с путем Customer/items.

Наконец, с помощью XPath мы ищем все покупки в заданной ценовой категории (девятая строка) в иерархии объектов DOM и выводим описание каждой найденной покупки (десятая строка).

Второй случай - Все данные хранятся в реляционной базе данных

Так как данные хранятся не в XML-формате, нам надо будет сделать внутри запроса преобразование с использованием SQL/XML-функций публикации.

Листинг 7. Преобразование с использованием SQL/XML-функций публикации

                
1. Statement dbstmt= conn.createStatement();
2. ResultSet dbResult = dbstmt.executeQuery("select xmlelement( name \"Customer\" ,
xmlattributes(customerid as \"customerid\" ),
xmlattributes(fname as \"firstname\" ),
xmlattributes(lname as \"lastname\" )
) from customer_table where customerid=custid");

3. XMLParse customerXML = new XMLParse(dbResult. getString(1));

5. dbResult = dbstmt.executeQuery("select xmlelement( name \"items\" ,
xmlelement( name \"item\" ,
xmlattributes(itemid as \"id\" ),
xmlattributes(description as \"description\" ),
xmlattributes(price as \"price\" ),
xmlattributes(date as \"purchaseDate\" )
)
) from purchase_table where customerid=custid");
6. if (dbResult.rs.next ()) {
7. Node itemsnode= customerXML.createNode (dbResult. getString(1));
8. customerXML.appendNode(itemsnode ,"/Customer",false);
}

9. customerXML.find("/Customer/Items/item[@price>15.0 and @price <25.5]",true);
10. for(int i=0;i < customerXML.currentFind.getLength();i++) {
11. System.out.println(customerXML.getValue("@description",i));
}

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

Преимущества использования модели XML перед "чистой" объектной моделью

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

  • дополнительные траты;
  • больше ошибок;
  • более длинный цикл разработки приложения;
  • менее гибкий и переносимый код;
  • необходимость изменять или заново создавать иерархию объектов каждый раз, когда возникают изменения в схеме данных;
  • сложность поддержки кода;
  • отсутствие встроенной проверки данных;
  • больший объем документации для объяснения оболочки объектов;
  • более сложную логику реализации для осуществления таких возможностей, как расширенные поиск и навигация по иерархии объектов;
  • необходимость обработки сериализации данных для каждого бизнес-объекта;
  • привязку приложения к инструментарию, применяемому для преобразования (если таковой используется);

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

  • уменьшает объем кода, что приводит к лучшему качеству, более низким затратам и большей гибкости;
  • содействует RAD-разработке;
  • усовершенствованные возможности поиска и навигации уже встроены в XPath-парсер;
  • в XML-модели уже встроены проверки ограничений и проверка по схеме;
  • модель обладает свойством персистентности. В любой момент вы можете перевести иерархию XML-данных в файл, строку или поток;
  • не нужны дополнительные инструменты;
  • эта методология открывает взаимосвязи и иерархию данных для бизнес-логики. Из кода бизнес-объектов сложно понять формат структуры бизнес-данных, которыми вы управляете (т.е. модель данных скрыта от бизнес-кода). В реляционном мире это необходимость, в мире XML это может оказаться недостатком;
  • код бизнес-логики легко читать, потому что XPath описывает точную природу данных и их взаимосвязи с бизнес-структурой.

Проблемы и решения при адаптации к XML-модели

Если реляционные данные не хранятся в XML, то их необходимо преобразовать в этот формат. Процесс преобразования является громоздким, несмотря на то, что многие поставщики позаботились о необходимом инструментарии. Однако с введением поддержки "чистого" XML в такие серверы баз данных, как DB2 и Microsoft SQL Server, отпала необходимость в преобразовании и нарезке XML-данных для хранения в реляционных таблицах. Данные, которые хранятся в XML, с помощью и XQuery и XML-индексов можно находить и возвращать в целости в приложение таким же образом, как вы могли бы вернуть из базы данных большой символьный объект.

Если данные хранятся в базе данных как чистый XML, для создания XML-запросов надо понимать назначение функций SQL/XML и xQuery. Чтобы уменьшить затраты на переход на XML-запросы, начните с простого XPath вместо сложных запросов XQuery.

Процесс изучения и профессионального освоения интерфейсов DOM и их реализаций, а также навигации и поиска в иерархии XML с использованием XPath может оказаться сложной задачей. Используйте вспомогательный класс (helper class), прикрепленный к данной статье, чтобы уменьшить необходимость напрямую вызывать интерфейсы DOM. Этот вспомогательный класс обволакивает интерфейсы DOM и представляет более естественные API, чем содержащиеся в коде. Он обладает необходимой функциональностью для обработки и сериализации XML-модели и для поиска и изменения данных или метаданных в экземпляре XML. Этот класс-оболочка также реализует XSL-преобразования, пространства имен и проверку на соответствие схеме, если это необходимо.

Прямое встраивание вызовов DOM API в бизнес-логику приложения нерационально, так как любое изменение в XML-схеме требует больших изменений в коде приложения. Многие вызовы API используются для перемещения по иерархии, и это снижает читаемость кода. Данные объекта, по которому осуществляются навигация и поиск, не такие явные, как в оболочке объекта, определенной пользователем. Наш класс-оболочка исключает необходимость встраивать вызовы DOM API в бизнес-логику. Поскольку класс-оболочка перемещается по DOM с помощью XPath, любые изменения в схеме, влияющие на код приложения, требуют изменения только в строках XPath API-вызовов оболочки из приложения. Благодаря тому, что XPath показывает место положения рассматриваемого узла в иерархии XML, читаемость кода приложения оказывается очень высокой.

Заключение

Прямое встраивание вызовов DOM API в бизнес-логику приложения нерационально, так как любое изменение в XML-схеме требует больших изменений в коде приложения. Многие вызовы API используются для перемещения по иерархии, и это снижает читаемость кода. Данные объекта, по которому осуществляются навигация и поиск, не такие явные, как в оболочке объекта, определенной пользователем. Наш класс-оболочка исключает необходимость встраивать вызовы DOM API в бизнес-логику. Поскольку класс-оболочка перемещается по DOM с помощью XPath, любые изменения в схеме, влияющие на код приложения, требуют изменения только в строках XPath API-вызовов оболочки из приложения. Благодаря тому, что XPath показывает место положения рассматриваемого узла в иерархии XML, читаемость кода приложения оказывается очень высокой.

Применяя модель данных XML, можно исключить всю иерархию объектных оболочек данных, чтобы программисты могли сосредоточиться на бизнес-логике, а не на управлении бизнес-данными. С помощью класса-оболочки DOM код приложения изолируется от интерфейса DOM. Применение XPath для навигации делает код приложения понятнее, поскольку отображает связи с рассматриваемыми бизнес-данными.

В идеале данные должны храниться в базе данных как чистый XML, но даже если данные находятся в реляционных таблицах, все равно во многих случаях стоит сразу преобразовать их в XML, чтобы затем работать с ними в приложении.

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

Во второй части данной серии вы научитесь адаптировать архитектуру XML-приложений к своим приложениям в DB2.


Страница сайта http://test.interface.ru
Оригинал находится по адресу http://test.interface.ru/home.asp?artId=18016