Алексей Валиков - Технология XSLT
-- Получаем CLOB-значение соответствующего преобразования
SELECT STYLESHEET.CONTENT
INTO stylesheetCLOB
FROM STYLESHEET, SOURCE
WHERE SOURCE.ID = sourceID AND SOURCE.STYLESHEETID = STYLESHEET.ID;
-- Если хотя бы одно из значений - NULL, прерываем обработку
-- и возвращаем NULL
IF sourceCLOB IS NULL OR stylesheetCLOB IS NULL THEN
RETURN NULL;
END IF;
-- Разбираем CLOB-значение входящего документа
XMLPARSER.parseCLOB(parser, sourceCLOB);
sourceXML := XMLPARSER.getDocument(parser);
-- Разбираем CLOB-значение документа преобразования
XMLPARSER.parseCLOB(parser, stylesheetCLOB);
stylesheetXML := XMLPARSER.getDocument(parser);
-- Инициализируем объект преобразования
stylesheet := XSLPROCESSOR.newStylesheet(stylesheetXML, NULL);
-- Выполняем преобразование
XSLPROCESSOR.processXSL(processor, stylesheet, sourceXML, result);
-- Освобождаем ресурсы
XSLPROCESSOR.freeProcessor(processor);
XMLPARSER.freeParser(parser);
XMLDOM.freeDocument(sourceXML);
XMLDOM.freeDocument(stylesheetXML);
RETURN result;
-- Обработка исключений
EXCEPTION
-- Если возникла исключительная ситуация
WHEN OTHERS THEN
-- Освобождаем ресурсы
XSLPROCESSOR.freeProcessor(processor);
XMLPARSER.freeParser(parser);
XMLDOM.freeDocument(sourceXML);
XMLDOM.freeDocument(stylesheetXML);
-- Передаем исключение дальше
RAISE;
END;
Представление обработанных документов теперь может быть описано совершенно элементарно.
Листинг 9.20. Представление PROCESSED_SOURCECREATE OR REPLACE VIEW PROCESSED_SOURCE AS
SELECT ID, PROCESS(ID) AS CONTENT
FROM SOURCE;
Продемонстрируем работу функции PROCESS и представления PROCESS_SOURCE на примере двух запросов.
Листинг 9.21. Запросы к таблице SOURCE и представлению PROCESSED_SOURCESQL> SELECT * FROM SOURCE;
ID CONTENT STYLESHEETID
-- ------------ ------------
1 <A>value</A> 1
SQL> SELECT * FROM PROCESSED_SOURCE;
ID CONTENT
-- -------------------------------------------------------
1 <?xml version = '1.0' encoding = 'UTF-8'?> <B>value</B>
Выполнение XSLT-преобразований в Java
Язык Java традиционно широко поддерживает XML-технологии: большинство передовых разработок в этой области реализуется, как правило, сначала на Java и уж затем переносится на другие платформы разработки.
Не стал исключением и XSLT. Можно смело сказать, что количество XSLT-средств, написанных на Java, превосходит половину вообще всех существующих в настоящее время XSLT-пакетов.
Для того чтобы продемонстрировать использование XSLT в Java, мы приведем два варианта одной и той же программы — серверного приложения (сервлета), которое по запросу клиента будет возвращать информацию о текущем HTTP-сеансе в формате HTML.
Первый вариант сервлета можно назвать "традиционным". В нем HTML-документ создается серией инструкций out.println(...), которые выводят в выходящий поток размеченную HTML-тегами информацию о текущем сеансе.
Листинг 9.22. Традиционный вариант сервлетаimport javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
public class example extends HttpServlet {
/**
* Инициализация.
*/
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
/**
* Основной метод сервлета
*/
public void service(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// Выставляем тип содержимого
response.setContentType("text/html");
// Инициализируем выходящий поток
OutputStreamWriter osw =
new OutputStreamWriter(response.getOutputStream());
PrintWriter out = new PrintWriter (response.getOutputStream());
// Выполняем вывод HTML-страницы
out.println("<html>");
// Выводим головную часть HTML-документа
out.println(" <head>");
out.println(" <title>Request information</title>");
out.println(" </head>");
// Выводим тело документа
out.println(" <body>");
// Выводим общую информацию о запросе
out.println(" <h1>General information</h1>");
out.println(" <table>");
// Выводим имя сервера
out.println(" <tr>");
out.println(" <td>Server name</td>");
out.println(" <td>" + request.getServerName() + "</td>");
out.println(" </tr>");
// Выводим порт сервера
out.println(" <tr>");
out.println(" <td>Server port</td>");
out.println(" <td>" + request.getServerPort() + "</td>");
out.println(" </tr>");
// Выводим адрес запрашивающей стороны
out.println(" <tr>");
out.println(" <td>Remote address</td>") ;
out.println(" <td>" + request.getRemoteAddr() + "</td>");
out.println(" </tr>");
// Выводим название протокола запроса
out.println(" <tr>");
out.println(" <td>Protocol</td>");
out.println(" <td>" + request.getProtocol() + "</td>");
out.println(" </tr>");
// Выводим метод запроса
out.println(" <tr>") ;
out.println(" <td>Method</td>");
out.println(" <td>" + request.getMethod() + "</td>");
out.println(" </tr>");
// Выводим URI запроса
out.println(" <tr>");
out.println(" <td>Request URI</td>");
out.println(" <td>" + request.getRequestURI() + "</td>");
out.println(" </tr>");
// Выводим строку запроса
out.println(" <tr>");
out.println(" <td>Query String</td>");
out.println(" <td>" + request.getQueryString() + "</td>");
out.println(" </tr>");
out.println(" </table>");
// Выводим параметры запроса
out.println(" <h1>Request parameters</h1>");
out.println(" <table>");
for (Enumeration e = request.getParameterNames();
e.hasMoreElements();) {
String name = e.nextElement().toString();
String[] values = request.getParameterValues(name);
for (int i=0; i < values.length; i++) {
out.println(" <tr>");
out.println(" <td>" + name + "</td>");
out.println(" <td>" + values[i] + "</td>");
out.println(" </tr>");
}
}
out.println(" </table>");
// Выводим параметры HTTP-сессии
out.println(" <h1>Session parameters</h1>");
out.println(" <table>");
HttpSession session = request.getSession(true);
String[] names = session.getValueNames();
for (int i=0; i < names.length; i++) {
String name = session.getValueNames()[i];
out.println(" <tr>");
out.println(" <td>" + name + "</td>");
out.println(" <td>" +
session.getValue(name).toString() + "</td>");
out.println(" </tr>");
}
out.println(" </table>");
// Выводим cookies
response.addCookie(new Cookie("content", "apple jam"));
out.println(" <h1>Cookies</h1>");
out.println(" <table>");
Cookie[] cookies = request.getCookies();
for (int i=0; i < cookies.length; i++) {
out.println(" <tr>");
out.println(" <td>" + cookies[i].getName() + "</td>");
out.println(" <td>" + cookies[i].getValue() + "</td>");
out.println(" </tr>");
}
out.println(" </table>");
out.println(" </body>");
out.println("</html>");
// Закрываем выходящий поток
out.close();
}
}
Результатом обращения к этому сервлету по URL вида
http://localhost/servlet/example?x=1&y=2&z=3&x=4&y=5&z=6
будет документ, аналогичный представленному на рис. 9.13.
Рис. 9.13. Результат обращения к сервлету
Несложно видеть, насколько жестко в этом сервлете закодирована презентация данных: для минимального изменения генерируемого документа придется в обязательном порядке изменять сам сервлет, что в современных системах может быть непозволительной роскошью, — все равно, что перебирать мотор для того, чтобы перекрасить автомобиль.
Второй вариант того же самого сервлета, который мы предложим ниже, демонстрирует, как в данном случае при помощи XSLT можно разделить данные и их презентацию. Идея очень проста: вместо того, чтобы в жестко заданном виде выводить информацию в выходящий поток, можно создать XML-документ в виде DOM-объекта и затем применить к нему XSLT-преобразование, которое создаст для него требуемое HTML-представление.
В этом варианте сервлета мы будем использовать Java-версию XML-библиотеки Oracle XDK (Oracle XML SDK, платформа разработки XML-приложений, созданная в Oracle Corp.). В данном примере из этой библиотеки мы будем использовать только XSLT-процессор (класс XSLProcessor) и реализацию DOM-модели XML-документа (класс XMLDocument). Во всем остальном мы будем полагаться на Java-реализацию стандартных интерфейсов объектной модели документа DOM, разработанной Консорциумом W3. DOM-интерфейсы позволят нам манипулировать XML-документом на уровне модели: создавать и включать друг в друга узлы элементов, текстовые узлы и так далее.