Продолжается подписка на наши издания! Вы не забыли подписаться?

Использование XQuery в качестве уровня представления данных

Автор: Брайан M. Кэри, Triangle Information Solutions, консультант по информационным системам
Источник: developerWorks Россия
Опубликовано: 07.07.2010
Версия текста: 1.1
Преимущества использования XQuery для представления данных
XQuery – супруг XML
XQuery предотвращает "жульничество"
XQuery не привязывает приложение к определенному языку
Создание MVC-приложения на базе XQuery
Реализация
Бизнес-требования
Модель
Контроллер
Представление
Страница каталога
Собираем все вместе
Заключение

Преимущества использования XQuery для представления данных

Сегодня почти все сообщество Web-разработчиков понимает преимущества подхода MVC. Этот подход отделяет модель (информационное содержание) от представления (того, что пользователь видит на экране) и от контроллера (того, что происходит в ответ на действия пользователя или обращения браузера по URL)

Большинство разработчиков, выбирая тот или иной вариант подхода MVC, обычно предпочитают технологию Java Platform, Enterprise Edition 5 (Java EE). Это безусловно эффективное решение, так как язык программирования Java представляет собой самую современную технологию. Кроме того, такие популярные структуры, как Spring и Struts, облегчают реализацию подхода MVC в распределенных объектных приложениях.

Однако непреложный закон разработки программного обеспечения гласит, что лучшие подходы постоянно развиваются. В противном случае Twitter был бы написан на языке Pascal. Стандарты совершенствуются, и прежние лучшие подходы модернизируются, а иногда и полностью вытесняются новейшими технологиями и решениями. Коротко говоря, несмотря на популярность технологии Java Enterprise, это все же вчерашний день. То же можно сказать и о других реализациях MVC, отличных от языка программирования Java.

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

XQuery – супруг XML

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

Сегодня XML — общепринятое средство обмена информацией в сообществе разработчиков программного обеспечения. Это особенно справедливо, когда требуется независимость от платформы и языка, например, в Web-сервисах. Он применяется и для каналов связи на базе Web, так как и RSS, и Atom опираются на XML. Результаты вызовов процедур Representational State Transfer (REST) также часто передаются в формате XML. Он часто используется даже в процессах конфигурирования ПО.

Учитывая повсеместное распространение XML, его имеет смысл использовать в качестве модели при подходе MVC. А так как превалирующим стандартом для XML-запросов служит XQuery, для создания представлений разумно использовать именно эту технологию. В этом качестве XQuery дает дополнительные преимущества, так как обеспечивает еще и преобразование. Разработчик может извлечь из XML-документа необходимую информацию и представить ее в том виде, который отвечает требованиям приложения.

XQuery предотвращает "жульничество"

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

Разработчики MVC часто "жульничают", вставляя код бизнес-логики прямо в уровень представления, а не в уровень служб, где ему положено находиться. Самый распространенный пример – использование скриптлетов в коде JSP. Большинство разработчиков JSP время от времени поддаются этому искушению.

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

XQuery не привязывает приложение к определенному языку

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

Напротив, компонент Java, который часто используется в качестве модели в приложении Java Enterprise, не может легко читаться приложением PHP. Аналогично, Java-приложение не может читать массив PHP, который отображает имена атрибутов на их значения. В этих случаях модель непосредственно привязана к языку программирования, что препятствует обмену данными.

XML устроен не так. Почти каждый язык (а может, и каждый) признает важность чтения, анализа и создания XML-документов для представления данных. Документы можно передавать от приложения к приложению, не заботясь о языке, на котором написано каждое из них.

Как уже говорилось в предыдущем разделе, лучшие методики разработки ПО постоянно развиваются. Вероятно, XML переживет все главенствующие сегодня языки программирования, а, значит, приложения, использующие в качестве модели XML (в отличие от моделей, ориентированных на конкретный язык), можно будет с минимальными усилиями модернизировать с применением технологии следующего года. Например, если ваша модель написана на Java beans, а в будущем году вам придется перевести свое приложение на .NET, вам придется модернизировать и модель в соответствии с новым языком. Однако если вы применяете модель XML, не потребуется вообще никакой модернизации, так как .NET может читать XML-документы.

Создание MVC-приложения на базе XQuery

Однажды утром, просмотрев электронную почту и выпив свой ежедневный утренний кофе, ваш начальник выходит и сообщает вам, что корпоративный Web-сайт fishinhole.com нужно сделать не зависящим от языка программирования. И с нескрываемым удовольствием добавляет, что при этом вы должны сохранить подход MVC. Затем он с сочувствием поворачивается и удаляется.

Большую часть из того, что он сказал, вы прослушали, так как рассматривали пятно от кетчупа на его кармане, но смысл его слов до вас дошел. Вам нужно, используя популярный подход к программированию (MVC), переписать код корпоративного Web-сайта так, чтобы модель и представление не были привязаны к определенному языку программирования. Тут вы беретесь за голову и начинаете обдумывать реализацию.

Реализация

Вы понимаете, что ни одно приложение не является полностью независимым от языка (пока), так как любую программу нужно писать на каком-то языке. Но если воспользоваться подходящими технологиями, реальная возможность повести fishinhole.com в нужном направлении все же есть.

С учетом этого вы сохраняете контроллер на языке программирования Java. Это код, который, по сути, переадресует запрос URL к нужному ресурсу. Вы также сохраняете среду Spring, написанную на языке программирования Java. Spring добавляет к простому MVC многие дополнительные возможности, такие как доступ к промежуточному уровню, управление транзакциями, аспектно-ориентированное программирование (AOP), ввод зависимостей и т.п.

Для достижения независимости от языка вы принимаете в качестве модели XML. Причины выбора XML, по совпадению, те же, что и причины использования XQuery для уровня представления, которые вы вычитали в статье на Web-сайте IBM developerWorks.

XQuery кажется естественным выбором для представления данных. Опять же, XQuery обеспечивает средства не только для обращения к XML-документам, но и для их чтения. Таким образом, полученный запрос не только возвращает нужные результаты, но и преобразует их в формат HTML, доступный любому браузеру.

Теперь вам нужна реализация XQuery. Оптимальным выбором является библиотека XQuery API for Java (XQJ) от DataDirect. Библиотека XQJ, как и ваш контроллер, написана на Java. И это самая популярная и мощная реализация XQuery, написанная на этом языке.

А как быть с платформой? Web-сайт (fishinhole.com) уже развернут на сервере приложений Apache Tomcat. Так как Apache Tomcat поддерживает все задуманное вами по части переработки кода, вы решаете, что и следующую итерацию приложения можно развернуть на этом же сервере.

Бизнес-требования

К счастью, бизнес-требования ваш начальник не изменил. Он поручил поменять лишь нижележащую реализацию. Так что все, что вам нужно, - это точное соблюдение все тех же требований, но с использованием MVC и XQuery.

Требования эти довольно просты. Web-сайт позволяет просматривать каталог наживок по способу применения и конфигурации. Способов применения может быть два (кастинг и блеснение). Конфигураций тоже может быть две ("ложка" и "малек"). Идея в том, что когда пользователь выбирает способ применения и конфигурацию, а затем нажимает кнопку Поиск, на экране отображается список наживок, соответствующих выбранным критериям.

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

Модель

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

<casting>
  <minnows brand="Yohuri" style="deep" size="3">
   <minnow color="midnight blue">
    <international-prices>
     <price denomination="dollar">3.25</price>
     <price denomination="euro">4.25</price>
     <price denomination="canadian-dollar">4</price>
     <price denomination="peso">100</price>
    </international-prices>
    <availability>
     <shipping>
      <delay>0</delay>
     </shipping>
     <regions>
      <shipping-region>United States</shipping-region>
      <shipping-region>European Union</shipping-region>
      <shipping-region>Canada</shipping-region>
      <shipping-region>Mexico</shipping-region>
     </regions>
    </availability>
   </minnow>
...
</lures>

Собственно этот документ XML должен быть понятен без объяснения. Каждый элемент и атрибут имеет интуитивно понятное имя, так что даже случайный читатель, знакомый со спецификацией XML, сможет визуально проанализировать этот документ.

Контроллер

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

Упомянутая выше функция Ajax вызывается нажатием пользователем кнопки Поиск. Эта функция опирается на простой сервлет для получения фрагмента HTML (который преобразуется в XML) и динамически заменяет содержание тега DIV фрагментом HTML. Здесь важно отметить, что эта реализация Ajax для обработки запроса использует метод POST, а не GET.

Так как реализация Ajax использует метод POST, наш простой сервлет должен реализовывать метод doPost, а не doGet. Такая реализация показана в листинге 2.

public void doPost(HttpServletRequest request, HttpServletResponse response) 
  throws ServletException, IOException {
 try {
  PrintWriter out = response.getWriter();
    
  String usage = request.getParameter("usage");
  String configuration = request.getParameter("configuration");
        
  if (usage != null && !usage.equals("") && !usage.equals("0")) {
    if (configuration != null && 
     !configuration.equals("") && !configuration.equals("0")) {
      String xqFile = "c:/fishinhole/searchResults.xq";
      String lures = fetchLuresByUsageAndConfiguration
       (usage, configuration, xqFile);
      System.out.println(lures);
      out.write(lures);
    }
  }
 } catch (Exception e) {
  e.printStackTrace();
 }

Вкратце, этот метод считывает два переданных методом POST параметра (конфигурацию и способ применения), запрашивает документ XML с учетом значений этих параметров и возвращает преобразованный документ XML. Содержание этого ответа, как уже говорилось, заменяется содержанием тега DIV с первоначальной страницы.

Во-первых, метод получает метод записи объекта HttpServletResponse. Здесь-то и записываются ваши выходные данные.

Затем, код получает значения двух параметров: usage и configuration. Эти параметры передаются в метод POST, который Ajax вызывает на главной странице каталога.

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

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

Метод fetchLuresByUsageAndConfiguration в листинге 3 представляет собой локальный метод, который, опираясь на XQJ, исполняет запрос и преобразование фрагмента кода.

private String fetchLuresByUsageAndConfiguration(String usage, 
  String configuration, String xqFile) throws Exception {
    
  // Data source for querying
  DDXQDataSource dataSource = new DDXQDataSource();

  // Connection for querying
  XQConnection conn = dataSource.getConnection();
    
  XQExpression expression = getGenericExpression(conn); 
    
  expression.bindString(new QName("configuration"), configuration, 
    conn.createAtomicType(XQItemType.XQBASETYPE_STRING));

  expression.bindString(new QName("usage"), usage, 
    conn.createAtomicType(XQItemType.XQBASETYPE_STRING));

  FileReader fileReader = new FileReader(xqFile);
  XQSequence results = expression.executeQuery(fileReader);

  return results.getSequenceAsString(new Properties());
}

private XQExpression getGenericExpression(XQConnection conn) throws XQException {
  XQExpression expression = conn.createExpression();
    
  expression.bindString(new QName("docName"), "c:/fishinhole/fishinhole.xml",
    conn.createAtomicType(XQItemType.XQBASETYPE_STRING));

  return expression;
}

Детали этого метода мы разберем ниже.Пока обратите внимание на то, что он возвращает объект String, который представляет собой просто фрагмент HTML, соответствующий преобразованному XML. Наконец, в ответ записывается символьная строка, возвращенная в предыдущей строке листинга.

Метод fetchLuresByUsageAndConfiguration использует три параметра. Первый, это способ применения наживки. Второй – это конфигурация наживки. Третий параметр – местонахождение вышеупомянутого файла XQuery.

Сначала код создает объект DDXQDataSource (с пустым конструктором). Класс DDXQDataSource, как и большинство классов данного метода, взят из библиотеки XQJ.

Затем объект источника данных используется для получения объекта XQConnection. Этот объект передается в объект getGenericExpression. В этом методе имя параметра docName связывается с местонахождением строки документа XML, который определяет модель. Объект XQExpression с присоединенным значением возвращается методу fetchLuresByUsageAndConfiguration.

Затем к объекту XQExpression присоединяются еще две строки. Естественно, это значения конфигурации и способа применения.

Стандартный объект FileReader создается в конструкторе со строкой, указывающей местонахождения файла XQuery. Благодаря этому объекту FileReader объект XQExpression получает возможность исполнить запрос в файле с использованием предварительно переданных ему значений.

Результаты этого запроса возвращаются в виде объекта String. Это тот самый объект String, который представляет собой фрагмент HTML.

Представление

Несмотря на то, что модель новой, усовершенствованной версии fishinhole.com имеет формат XML, представление определяется в XQuery. XQuery позволяет не только запрашивать документы XML, но и преобразовывать их. В данном случае осуществляется преобразование из XML в HTML, поэтому результат легко читается любым Web-браузером. Листинг 4 иллюстрирует выполнение запроса и преобразования XQuery.

declare variable $docName as xs:string external;
declare variable $configuration as xs:string external;
declare variable $usage as xs:string external;

<table width="100%" class="searchResultsTable">
  <tr>
    <th>Brand</th>
    <th>Color</th>
    <th>Configuration</th>
    <th>Size</th>
    <th>Usage</th>
  </tr>

{
if ($configuration = 'minnow' and $usage = 'casting') then
for $minnows in doc($docName)//casting/minnows
return
<div>
  {
  for $minnow in $minnows/minnow
  return
    <tr>
      <td>{data($minnows/@brand)}</td>
      <td>{data($minnow/@color)}</td>
      <td>{$configuration}</td>
      <td>{data($minnows/@size)}</td>
      <td>{$usage}</td>
    </tr>
  }
</div>
...

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

Затем следует первая часть преобразования. В данном случае оно начинается с элемента TABLE и соответствующих ему заголовков.

Затем следует некоторый фактический код XQuery. Этот код выполняет запросы таким образом, что возвращаются только результаты, соответствующие указанным пользователем параметрам конфигурации и способа применения. В данном случае, если значение конфигурации minnow, а значение способа применения casting, выполняется запрос, соответствующий этим двум значениям, и возвращаются его результаты. Заметим, что ради экономии места в листинге 4 рассмотрены не все возможные случаи.

Представленный здесь запрос ищет все элементы minnows для каждого элемента casting. Затем в каждом элементе minnows ищутся все элементы minnow и выбираются нужные значения. Нужные значения – это бренд (атрибут), цвет (атрибут), конфигурация (связанное значение), размер (атрибут) и способ применения (второе связанное значение).

ЗЗаметьте также, что все результаты возвращаются внутри HTML-элементов TD-ячеек таблицы. Все ячейки таблицы находятся в строке таблицы (TR), которая, в свою очередь, находится внутри элемента DIV. Эта часть преобразования помещает результаты запроса в таблицу HTML.

Страница каталога

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

Большая часть этой страницы написана на HTML. Однако требуется и Ajax — чтобы не обновлять страницу при нажатии пользователем кнопки Поиск. Буква j в названии Ajax означает JavaScript, так что на нашей странице присутствует и код JavaScript. Этот код представлен в листинге 5.

function search() {
  var usageElement = document.getElementById("usageSelect");
  var configurationElement = document.getElementById("configurationSelect");
  
  var usage = usageElement.options[usageElement.selectedIndex].value;
  var configuration = 
   configurationElement.options[configurationElement.selectedIndex].value;
  
  if (usage == "0") {
    alert("Please select a usage!");
    return;
  }
  
  if (configuration == "0") {
    alert("Please select a configuration!");
    return;
  }
  
  var parameters = {};
  parameters["usage"] = usage;
  parameters["configuration"] = configuration;
  
  var resultsDiv = document.getElementById("searchResults");
  
  ajax("./updateResults",parameters,function(success,response) {
    resultsDiv.innerHTML = response;
  });
}

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

Затем создается пустой массив. Этот массив заполняется значениями, которые были выбраны пользователем из раскрывающихся списков. В данном случае массив JavaScript работает как хеш-таблица. Иными словами, значения связываются не со значениями числового индекса самого массива, а с действительными строковыми переменными. Не удивительно, что эти строковые переменные называются usage и configuration.

Далее переменная JavaScript связывается с элементом DIV, в котором отображаются результаты.

Наконец, активизируется код Ajax. При этом используется URL ./updateResults, который отображается на контроллер сервлета, рассмотренный выше (в листинге 2). Передается массив параметров, чтобы сервлет мог обработать значения, выбранные пользователем. После успешного ответа свойство innerHTML элемента DIV заполняется преобразованными данными XML (или HTML), возвращенными контроллером сервлета.

Собираем все вместе

Здесь важно обратить внимание на конфигурацию. В данном случае и модель, и файл XQuery расположены в каталоге c:/fishinhole. В рассматриваемом примере кода и в загружаемом коде, который прилагается к этой статье, предполагается, что эти два файла расположены именно в этом месте. К счастью, если такое расположение невозможно, его легко изменить.

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

За информацией о способе получения этих файлов обращайтесь к разделу Ресурсы.

Включив вышеперечисленные файлы JAR в каталог WEB-INF/lib приложенного файла WAR, вы можете приступать к развертыванию. Подробное рассмотрение процесса развертывания файла WAR выходит за рамки данной статьи, но это простая административная задача, которую можно решить с помощью программы менеджера в составе Tomcat.

После развертывания приложения откройте в браузере следующий URL:

http://<server>:<port>/FishinHole/catalog.htm  

где <server> — это IP-адрес сервера Web-приложений, а <port> — его порт. Для большинства локальных установок можно использовать http://localhost:8080/Fishin­Hole/catalog.htm.

Открывшаяся страница каталога не будет содержать никаких товаров. Это связано с тем, что вы еще не выбрали критериев для наживки. В развертывающихся списках выберите: Casting в списке Usage и Minnow в списке Configuration. Затем нажмите кнопку Поиск. На первый раз это может занять несколько секунд, но в конечном итоге вы должны увидеть то, что изображено на рисунке 1.


Рисунок 1. Результаты

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

Заключение

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

Ресурсы
?


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

Copyright © 1994-2016 ООО "К-Пресс"