Преобразование результата
На текущий момент мы изменили только способ получения приложением информации о сервисе. Приложение продолжает запрашивать информацию тем же образом и обрабатывать данные, поступающие от сервиса. Следующий шаг состоит в преобразовании информации, характерной для определенного сервиса, в стандартную онтологическую информацию.
Входная информация
Давайте начнем с рассмотрения данных, которые приходят в ответ на отправленный запрос. На самом деле Web-сервисы Amazon дают вам возможность выбора, сколько именно данных вы хотите получить; указывая в параметре ResponseGroup значение Small, мы получим только базовую информацию, обрабатывать которую значительно легче, чем полный результат. К сожалению, Чтобы получить данные о цене, необходимо установить параметру ResponseGroup запроса значение Large
. Данные, возвращаемые сервисом, будут выглядеть следующим образом (см. листинг 21):
Листинг 21. Входная информация
<?xml version="1.0" encoding="UTF-8"?>
<ItemSearchResponse xmlns=
"http://webservices.amazon.com/AWSECommerceService/2005-10-05">
<OperationRequest>
...
</OperationRequest>
<Items>
<Request>
...
</Request>
<TotalResults>17717</TotalResults>
<TotalPages>1772</TotalPages>
<Item>
<ASIN>0307337332</ASIN>
<DetailPageURL>http://www.amazon.com/gp/redirect.html%3FASIN=03
07337332%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o
/ASIN/0307337332%253FSubscriptionId=000000000000000
</DetailPageURL>
<SalesRank>16</SalesRank>
<SmallImage>...</SmallImage>
<MediumImage>...</MediumImage>
<LargeImage>...</Width></LargeImage>
<ImageSets>...</ImageSets>
<ItemAttributes>
<Author>Cesar Millan</Author>
<Binding>Hardcover</Binding>
<Creator Role="Adapter">Asdf</Creator>
<Creator Role="Editor">Melissa Jo Peltier</Creator>
<DeweyDecimalNumber>636.70887</DeweyDecimalNumber>
<EAN>9780307337337</EAN>
<Edition>RAO</Edition>
<ISBN>0307337332</ISBN>
<Label>Harmony</Label>
<ListPrice>
<Amount>2495</Amount>
<CurrencyCode>USD</CurrencyCode>
<FormattedPrice>$24.95</FormattedPrice>
</ListPrice>
<Manufacturer>Harmony</Manufacturer>
<NumberOfItems>1</NumberOfItems>
<NumberOfPages>234</NumberOfPages>
<Title>Cesar's Way: The Natural, Everyday Guide
to Understanding and Correcting Common Dog Problems</Title>
...
</Item>
<Item>
<ASIN>0060817089</ASIN>
...
|
Конечно же, мы можем добавить все эти данные к онтологии, но для удобства работы с этим руководством мы остановимся на простом варианте.
Выходные данные
Конечная цель состоит в том, чтобы получить эту информацию и преобразовать ее в форму, соответствующую онтологии. В этом случае она должна выглядеть примерно следующим образом (см. листинг 22):
Листинг 22. Выходные данные
<rdf:RDF xmlns:res=
"http://webservices.amazon.com/AWSECommerceService/2005-10-05"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<Author rdf:ID="0307337332Cesar_Millan">Cesar Millan</Author>
<Book rdf:ID="0307337332">
<writtenBy rdf:resource="0307337332Cesar_Millan"/>
</Book>
<StockItem rdf:ID="AMAZON_0307337332">
<stockedProduct rdf:resource="#0307337332"/>
<itemDescription>Cesar's Way: The Natural, Everyday Guide to
Understanding and Correcting Common Dog Problems</itemDescription>
<itemPrice rdf:datatype=
"http://www.w3.org/2001/XMLSchema#double">24.95</itemPrice>
<itemDetailURL>http://www.amazon.com/gp/redirect.html%3FASIN=03
07337332%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o
/ASIN/0307337332%253FSubscriptionId=000000000000000
</itemDetailURL>
</StockItem>
<Author rdf:ID="0060817089John_Grogan">John Grogan</Author>
...
</rdf:RDF>
|
Здесь стоит отметить несколько моментов. Во-первых, в Book
содержится идентификатор, представляющий номер ISBN. Он должен быть уникальным во всех сервисах. В рабочем приложении, прежде чем создавать новый элемент, нужно проверить, не создан ли он уже; существует возможность того, что та же книга могла быть запрошена в другом сервисе или даже в другом запросе этого же сервиса.
В нашем коде мы избегаем дублирования элементов Author, добавляя спереди в идентификаторе к номеру ISBN имя автора. Также нужно учитывать тот факт, что в значении идентификатора не может быть пробелов. Товарная позиция StockItem ссылается на книгу
Book посредством свойства stockProduct, указывающего на соответствующий ресурс.
После того как мы привели данные к этой форме, мы можем сохранить их в базе данных и проанализировать с помощью онтологических инструментов. Мы выполним конвертацию с помощью преобразования XSLT.
Таблица стилей
Используемая таблица стилей - это обычная таблица стилей, которая, однако, содержит несколько функций XPath для выполнения некоторых более сложных задач (см. листинг 23):
Листинг 23. Таблица стилей
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:res=
"http://webservices.amazon.com/AWSECommerceService/2005-10-05"
xmlns:rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<rdf:RDF>
<xsl:apply-templates select=
"/res:ItemSearchResponse/res:Items/res:Item" />
</rdf:RDF>
</xsl:template>
<xsl:template match="res:Item">
<xsl:element name="Author">
<xsl:attribute name="rdf:ID">
<xsl:value-of select="res:ASIN"/><xsl:value-of select=
"translate(res:ItemAttributes/res:Author, ' ', '_' )"/>
</xsl:attribute>
<xsl:value-of select="res:ItemAttributes/res:Author"/>
</xsl:element>
<xsl:element name="Book">
<xsl:attribute name="rdf:ID">
<xsl:value-of select="res:ASIN"/>
</xsl:attribute>
<xsl:element name="writtenBy">
<xsl:attribute name="rdf:resource"><xsl:value-of
select="res:ASIN"/><xsl:value-of select=
"translate(res:ItemAttributes/res:Author, ' ', '_' )"/>
</xsl:attribute>
</xsl:element>
</xsl:element>
<xsl:element name="StockItem">
<xsl:attribute name="rdf:ID">AMAZON_<xsl:value-of select=
"res:ASIN"/></xsl:attribute>
<xsl:element name="stockedProduct">
<xsl:attribute name="rdf:resource">#<xsl:value-of select=
"res:ASIN"/></xsl:attribute>
</xsl:element>
<itemPrice rdf:datatype=
"http://www.w3.org/2001/XMLSchema#double"><xsl:value-of
select="translate(res:ItemAttributes/res:ListPrice/res:FormattedPrice, '$', '')"/>
</itemPrice>
<itemDetailURL><xsl:value-of select="res:DetailPageURL"/>
</itemDetailURL>
<itemDescription><xsl:value-of select=
"res:ItemAttributes/res:Title"/>
</itemDescription>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
|
Сначала создается основной элемент RDF, который служит корнем документа. После этого организуется цикл по всем элементам Item и создаются элементы Author,
Book и StockItem. При необходимости пробелы в имени автора с помощью функции translate() заменяются знаками подчеркивания.
Обратите внимание на использование литеральных строк, таких как AMAZON_. Поскольку эта информация зависит от сервиса, мы можем оставить ее без изменений.
Создание тестового приложения
Теперь мы почти готовы начать преобразование, но поскольку увидеть происходящее изнутри сервлета практически невозможно, мы создадим тестовый класс, чтобы запустить преобразование и убедиться в правильности его работы (см. листинг 24):
Листинг 24. Создание тестового класса
import java.io.IOException;
import java.io.StringReader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import java.io.PrintStream;
public class DoThis {
public static void main (String args[]){
String transString=
"<xsl:stylesheet version=\"1.0\" "+
...
try {
}
catch (Exception e){
e.printStackTrace();
}
}
}
|
Это обычный класс, но поскольку обычно таблица стилей будет использоваться как строка (как свойство класса Service), имеет смысл смоделировать это здесь.
Формирование исходного документа
Чтобы начать преобразование, создадим DOMSource, обработав результат реального запроса (см. листинг 25):
Листинг 25. Создание DOMSource
...
try {
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(
"http://webservices.amazon.com/onca/xml?Service=AWSECommerceService&A
WSAccessKeyId=000000000000000&SearchIndex=Books&Operation=ItemSe
arch&ResponseGroup=Large&Title=Dogs");
Source xmlSource = new DOMSource(document);
}
catch (Exception e){
e.printStackTrace();
}
}
|
Обрабатываемая ссылка - это URL, сформированный методом getRESTRequest()
, но для правильной работы нам нужно убедиться, что DocumentBuilderFactory
создает DocumentBuilder, понимающий пространства имен. В противном случае парсер не сможет понять, какие элементы таблицы стилей следует обрабатывать как таблицу стилей.
Создание таблицы стилей
Нам нужно создать DOMSource, представляющий таблицу стилей(см. листинг 26):
Листинг 26. Создание объекта таблицы стилей
...
Source xmlSource = new DOMSource(document);
Document xslDoc = builder.parse(
new InputSource(new StringReader(transString)));
DOMSource xslSource = new DOMSource(xslDoc);
TransformerFactory transFactory =
TransformerFactory.newInstance();
Transformer transformer =
transFactory.newTransformer(xslSource);
}
catch (Exception e){
e.printStackTrace();
}
}
|
Конечно же, в реальном приложении нужно будет заменить transString
на xsltTransformationString из Service.
Преобразование документа
Теперь мы можем выполнить собственно преобразование (см. листинг 27):
Листинг 27. Выполнение преобразования
...
TransformerFactory transFactory =
TransformerFactory.newInstance();
Transformer transformer =
transFactory.newTransformer(xslSource);
StreamResult result = new StreamResult(System.out);
transformer.transform(xmlSource, result);
}
catch (Exception e){
e.printStackTrace();
}
}
|
Результат будем выводить в System.out, поэтому индивидные концепты онтологии будут выводиться в командную строку или окно консоли, как видно из рисунка 3.
Рисунок 3. Результат преобразования
|