Ultimate mashup – Các dịch vụ Web và Web ngữ nghĩa, Phần 5: Thay đổi các dịch vụ Web

Tạo cho người sử dụng mashup cơ hội lựa chọn các dịch vụ trong ứng dụng của bạn

Loạt bài viết này trình bày chi tiết việc tạo ra một ứng dụng Mashup cho phép kiểm soát các dữ liệu được hiển thị với người sử dụng. Bây giờ bạn biết làm thế nào để tạo một bản thể luận (ontology) để xác định khái niệm đại diện của một dịch vụ, bạn có thể cho phép người dùng lựa chọn dịch vụ mà họ muốn sử dụng

Nicholas Chase, Tác giả tự do, Site Dynamics Interactive Communications

Nicholas Chase đã phát triển trang web cho các công ty lớn như Lucent Technologies, Sun Microsystems, Oracle, và Tampa Bay Buccaneers. Nick đã từng là một giáo viên vật lý ở trường phổ thông, một nhà quản lý thiết bị phóng xạ mức thấp, một nhà biên tập tạp chí khoa học viễn tưởng trực tuyến, một kỹ sư đa phương tiện, một hướng dẫn của Oracle, và một trưởng phòng công nghệ của một công ty tương tác truyền thông. Nick là tác giả của một số sách



08 03 2007 (Xuất bản lần đầu tiên vào ngày 21 05 2009)

Trước khi bắt đầu

Đây là bài viết cho các nhà phát triển, những người muốn tìm hiểu làm thế nào để sử dụng một bản thể luận dùng API - cụ thể, trong trường hợp này, là Jena API - cũng như những người chỉ muốn xem làm thế nào các bản thể luận và các xử lý ngữ nghĩa khái niệm khác có thể hữu dụng trong một thế giới ứng dụng thực sự. Nó sử dụng các bản thể luận của bạn trong phần 3 và 4 và tích hợp vào Mashup bạn xây dựng trong phần 1, nhằm cung cấp cho người dùng một sự lựa chọn về các dịch vụ sử dụng

Bài viết này giả định rằng bạn đã quen với khái niệm về XML, khung mô tả tài nguyên (Resource Description Framework - RDF), các bản thể luận, và ngôn ngữ bản thể luận Web (Web Ontology Language - OWL). Nó cũng sử dụng các ngôn ngữ lập trình Java, nhưng nếu bạn chỉ tìm kiếm một khái niệm hoặc chỉ tìm hiểu nó làm việc như thế nào, điều đó là không quan trọng. Nếu bạn cần một bất cứ điều gì trong các khái niệm này (trừ Java, tất nhiên) hãy xem các phần trước. Bạn có thể tìm thấy các liên kết với chúng (và các nguồn cho Java) trong Tài nguyên.

Về loạt bài viết này

Ngày nay, có vẻ như bạn không thể lướt trên Web mà không sử dụng một trang Web mà trang đó hoặc có thể cung cấp quyền truy cập vào dữ liệu của nó thông qua một dịch vụ dựa trên API hoặc sử dụng dữ liệu từ một trang web khác lấy được thông qua một dịch vụ dựa trên API. Khi bạn xem xét các lợi thế của việc sử dụng các thông tin hiện có trong các ứng dụng của riêng bạn, có lẽ không đáng ngạc nhiên lắm. Nó cũng chỉ là vấn đề ở thời gian trước khi một người bắt đầu kết hợp dữ liệu từ các hệ thống riêng biệt để tạo ra những gì hoàn toàn mới. Những ứng dụng, được gọi là mashup, là khu vực mới nhất trên Web, từ các trang web dựa trên cộng đồng đến các trang web chuyên tìm kiếm, thậm chí các ánh xạ mashup hiện nay.

Chúng hầu hết đều hữu dụng, nhưng có một điểm chung là được phát triển cho các thiết lập dịch vụ cụ thể. Nếu ưu tiên cho một loại dịch vụ cụ thể thay đổi, bạn sẽ có rất nhiều việc phải làm.

Mục đích của các bài viết này là tạo ra các ứng dụng mashup đủ thông minh để người dùng có thể bổ sung hoặc loại bỏ các tiện ích nếu muốn, và hệ thống sẽ biết phải làm gì với chúng. Được tiến hành như sau:

Phần 1 giới thiệu các khái niệm về các mashup, trình bày cách hoạt động của chúng và xây dụng các phiên bản đơn giản

Phần 2 giải quyết một phần của vấn đề bằng cách sử dụng các khả năng pureXML™ mới của IBM® DB2® để xây dựng một vùng nhớ đệm XML, cái cho phép bạn lưu các yêu cầu trước đó đồng thời cho phép truy hồi các thông tin cụ thể.

Sau cùng, bạn cần sử dụng các bản thể luận hoặc các từ định nghĩa cho các khái niệm hoặc thuộc tính liên quan, nên ở Phần 3 quy trình bắt đầu bằng việc tìm hiểu về RDF và RDFS, hai thành phần chính của OWL, sẽ được đề cập ở phần 4. Ở phần 5, bạn sẽ dùng đến các bản thể luận đã tạo ở phần 4 và dùng chúng để cho phép người dùng thay đổi nguồn thông tin.

Phần 6, thực sự thú vị. Ở đây, bạn cung cấp cho người sử dụng quyền kiểm soát, và cho phép họ sắp xếp các dịch vụ mới vào bản thể luận và lựa chọn các dữ liệu được sử dụng để tùy chỉnh một Mashup.

Về bài viết này

Các phần trước đã giải thích thế nào là mashup, và bạn làm thế nào để sử dụng chúng cho việc tổ hợp dữ liệu từ nhiều nguồn. Mục đích là cung cấp một hệ thống thông minh, chẳng hạn như khả năng chuyển đổi từ dịch vụ này ra dịch vụ khác mà không cần phải biết chính xác thông tin được thể hiện như thế nào trước đó. Để làm điều đó, bạn sẽ cần phải định nghĩa các khái niệm như "hiệu sách", "DVD", "giá cả", v.v...

Trong các phần trước, bạn đã xây dựng một ứng dụng mashup cho phép người dùng đưa ra yêu cầu về thông tin trên các chủ đề cụ thể hoặc từ khóa. Tại bài viết này, bạn sẽ biết cách cho phép người dùng lựa chọn dịch vụ để sử dụng cho dữ liệu.

Trong bài viết này, bạn sẽ được học:

  • Tải về và thao tác trên một bản thể luận
  • Trích dẫn các cá thể từ một bản thể luận bằng cách lập trình
  • Tiếp cận các đặc tính và các giá trị từ một bản thể luận hoặc một tài liệu RDF
  • Chuyển đổi một kết quả dạng bắc cầu REST sang một cá thể dạng bản thể luận tổng quát
  • Hiển thị thông tin bản thể luận ở dạng HTML

Trong bài viết này, bạn sẽ mã hóa thông tin về các dịch vụ cá nhân trong một tập tin Owl. Sau đó, bạn sẽ sử dụng Jena API để trích xuất thông tin đó và sử dụng nó để thực hiện một yêu cầu REST. Cuối cùng, bạn chuyển đổi phản hồi REST vào hình thức chung, và hiển thị nó trên trang HTML như trước.

Các điều kiện tiên quyết

Bạn sẽ phải thực hiện việc cài đặt phần mềm dưới đây và kiểm tra nó nhằm theo kịp với mã trong bài bài viết này.

  • IBM® DB2® 9 (Trước đây thường được biết là "Viper"): Cơ sở dữ liệu liên quan này cũng có các nhiều khả năng quan trọng của XML, thứ bạn sẽ cần cho bài học này. Bạn có thể tải về một phiên bản dùng thử của DB2: DB2 Enterprise 9 hoặc DB2 Express-C 9, một bản miễn phí dữ liệu máy chủ DB2 Express 9.
  • Apache Tomcat hoặc các máy chủ servlet: bài viết này giả định rằng bạn sẽ xây dựng các ứng dụng web bằng cách sử dụng các servlet, do đó, bạn sẽ cần một động cơ như là servlet Apache Tomcat. Nếu bạn chọn để xây dựng ứng dụng này bằng cách sử dụng môi trường khác, chỉ cần đảm bảo rằng bạn phải có sẵn phần mềm thích hợp. Tải về apache-tomcat-5.5.17.zip và cài đặt vào một thư mục mà không có dấu cách trong tên của thư mục.
  • Java: Apache Tomcat 5.5, cùng với nó thì bài viết này được xây dựng, nó yêu cầu bản Java 1.5 hoặc cao hơn. Tải từ J2SE SDK.
  • The Jena API: Jena API là Java API được thiết kế để làm việc với dữ liệu RDF và OWL. Có thể tải về từ http://jena.sourceforge.net/.
  • Để thuận tiện hơn, có thể dùng một IDE như Eclipse hoặc IBM Rational™ Web Developer đối với phát triển của bạn. Có thể tải Eclipse từ Eclipse.org tải bản thử nghiệm Rational Web Developer, hoặc dùng môi trường phát triển bạn yêu thích. Bạn không nên đi quá những gì mà lĩnh vực về biên soạn và triển khai yêu cầu.

Tổng quan

Trước khi bạn bắt tay vào mã mới, bạn cần phải nhớ lại những gì loạt bài viết này đã đề cập đến.

Bài viết trước: Xác định các dịch vụ

Tại thời điểm này, bạn có một ít mã chứa một ứng dụng làm việc, và có rất nhiều khái niệm. Trong Phần 1, bạn đã tạo một ứng dụng bao gồm một Mashup cơ bản. Người dùng nhập vào một từ khóa và một mẫu để gửi vào một servlet. Servlet cấp từ khóa đó cho bất kỳ các dịch vụ đã được định nghĩa trong một lớp Service bất kỳ. Đối với mỗi dịch vụ nói trên, bạn cần xử lý kết quả dựa vào các thông tin được cung cấp trong khai báo tự xác định của dịch vụ. Ví dụ lớp Service xác định các dịch vụ tin tức Yahoo trông sẽ như sau (xem ví dụ 1).

Ví dụ 1. Xác định một dịch vụ
...
    Service thisService = new Service();
    Service subService = new Service();
            
    subService.name = "Technorati";
    subService.baseURL = 
       "http://api.technorati.com/cosmos?key=mydeveloperskey&url=";
    subService.template = "<span><value/></span>";
    subService.elementValues[0] = "inboundlinks";
    subService.elementValues[1] = "bogus";
    subService.attributeValues[0] = "thumbnail_url";
    subService.recordExp = "/tapi/document/result";

      
    thisService.name = "Yahoo! Search";
    thisService.baseURL =  "http://api.search.yahoo.com/NewsSear"+
      "chService/V1/newsSearch?appid=mashupid&type=all&query=";
    thisService.template = "<p><b><a 
value='href'><value/></a>"+
            "</b>: <value/> (Linked <subService/> 
times)</p>";
    thisService.elementValues[0] = "Title";
    thisService.elementValues[1] = "Summary";
    thisService.attributeValues[0] = "ClickUrl";
    thisService.recordExp = "/ResultSet/Result";
      
    thisService.subSvc = subService;
    thisService.filterExp = "ClickUrl";
...

Lớp dịch vụ Service định nghĩa một cái tên và URL làm cơ sở cho các yêu cầu REST. Khi bạn thực hiện các yêu cầu trong thực tế, bạn chỉ cần thêm từ khóa vào phần cuối. Dịch vụ cũng xác định biểu thức XPath là đại diện cho vị trí của từng cá thể bản ghi dữ liệu trong các kết quả. Trong ví dụ ở đây, /ResultSet/Result biểu diễn cho mỗi một phần mới. Cuối cùng, dịch vụ bao gồm các thông tin cho biết làm thế nào để hiển thị các kết quả dữ liệu. Các mẫu đại diện HTML cho đầu ra, với các yếu tố giá trị và các thuộc tính phục vụ như phần giữ chỗ (placeholder) để sẽ được thay thế bởi các dữ liệu được tìm thấy trong các biểu thức XPath trong các mảng elementValues và các giá trị thuộc tính attributeValues.

Trong trường hợp này, bạn cũng có thể thấy phần gắn thêm của một dịch vụ thứ hai và được thể hiện bởi thành tố dịch vụ con subservice.

Các bài viết trước: các tính năng tiên tiến

Trong Phần 2, bạn phát triển phần ứng dụng hơn là tạo ra một yêu cầu Web cho tất các các yêu cầu dịch vụ - đây là một quá trình có thể kéo dài đến vài phút nếu phần mashup tạo ra nhiều yêu cầu - bạn bắt đầu lưu giữ các kết quả yêu cầu trong cơ sở dữ liệu XML có sử dụng khả năng pureXML mới của DB2. Điều này cho phép bạn kiểm tra một cơ sở dữ liệu cho một yêu cầu cụ thể trước khi chạy Mashup và tạo một cái mới.

Nhưng mục tiêu tổng quát là tạo ra một dịch vụ thông minh – với nó người sử dụng có thể yêu cầu một kiểu dữ liệu cụ thể - như sách, giá...- và mashup sẽ hiểu làm thế nào để tìm được cho dù vấn đề không phải là bạn sử dụng dịch vụ nào.

Để làm được điều này, ở Phần 3 và 4, bạn sẽ học cách tạo bản thể luận hoặc phân loại các khái niệm. Bằng cách này, bạn có thể định nghĩa các khái niệm như cuốn sách, giá cả,… để cung cấp một hình thức chung và sắp xếp từ đó bạn có thể xử lý từng kiểu dịch vụ chứ không phải chỉ là từng dịch vụ.

Ở phần 4, bạn đã tạo ra một bản thể luận của hiệu sách có rất nhiều các khái niệm, định nghĩa mà bạn có thể tìm thấy trong các hiệu sách điện tử, như sách, DVD, cho rất nhiều khái niệm có thể được tìm kiếm từ các lưu trữ điện tử như sách, DVD, tác giả...ở phần hướng dẫn bạn có thể bắt đầu thêm vào các dữ liệu thực tế cho bản thể luận này.

Bản thể luận cơ sở

Bản thể luận cở sở trông tương tự như sau (xem ví dụ 2).

Ví dụ 2. Bản thể luận cơ sở
<?xml version="1.0"?>
<!DOCTYPE rdf:RDF [
     <!ENTITY store  "http://example.com/stores#" >
     <!ENTITY owl  "http://www.w3.org/2002/07/owl#" >
     <!ENTITY xsd  "http://www.w3.org/2001/XMLSchema#" >
]>

<rdf:RDF
  xmlns     = "http://example.com/store#"
  xmlns:store = "http://example.com/store#"
  xml:base  = "http://example.com/store#"
  xmlns:owl = "http://www.w3.org/2002/07/owl#"
  xmlns:rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  xmlns:rdfs= "http://www.w3.org/2000/01/rdf-schema#"
  xmlns:xsd = "http://www.w3.org/2001/XMLSchema#"
>

<owl:Ontology rdf:about=">
  <rdfs:comment>An example OWL ontology for Online Bookstores (The 
Ultimate Mashup: Part #4)</rdfs:comment>
  <rdfs:label>BookStore Ontology</rdfs:label>
</owl:Ontology>
  
<owl:Class rdf:ID="Service">
   <rdfs:label>Web Service</rdfs:label>
   <rdfs:subClassOf>
     <owl:Restriction>
       <owl:onProperty rdf:resource="#endpoint" />
       <owl:minCardinality 
rdf:datatype="&xsd;nonNegativeInteger">1</owl:minCardinality>
     </owl:Restriction>
   </rdfs:subClassOf>
</owl:Class>
<owl:DatatypeProperty  rdf:ID="endpoint">
   <rdfs:domain rdf:resource="#Service"/>
   <rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#anyURI"/>
</owl:DatatypeProperty>

<owl:Class rdf:ID="Store">
   <rdfs:subClassOf rdf:resource="#Service"/>
   <rdfs:label>Online Store</rdfs:label>
</owl:Class>

<owl:Class rdf:ID="Bookstore">
   <rdfs:subClassOf rdf:resource="#Store"/>
   <rdfs:label>Bookstore</rdfs:label>
</owl:Class>

<owl:Class rdf:ID="Product">
   <rdfs:label>Product sold at online store</rdfs:label>
</owl:Class>

<owl:Class rdf:ID="Book">
   <rdfs:subClassOf rdf:resource="#Product"/>
   <rdfs:label>Book</rdfs:label>
   <rdfs:subClassOf>
     <owl:Restriction>
       <owl:onProperty rdf:resource="#writtenBy" />
       <owl:minCardinality 
rdf:datatype="&xsd;nonNegativeInteger">1</owl:minCardinality>
     </owl:Restriction>
   </rdfs:subClassOf>
</owl:Class>

<owl:DatatypeProperty rdf:ID="title"> 
  <rdfs:domain rdf:resource="#Book"/>
  <rdfs:range rdf:resource="&xsd;string"/> 
</owl:DatatypeProperty>

<owl:Class rdf:ID="ISBN">
</owl:Class>
<owl:InverseFunctionalProperty  rdf:ID="isbn">
   <rdfs:domain rdf:resource="#ISBN"/>
   <rdfs:range rdf:resource="#Book"/>
</owl:InverseFunctionalProperty>

<owl:Class rdf:ID="Movie">
   <rdfs:subClassOf rdf:resource="#Product"/>
   <rdfs:label>Movie</rdfs:label>
</owl:Class>

<owl:Class rdf:ID="Person">
   <rdfs:label>Person</rdfs:label>
</owl:Class>
<owl:DatatypeProperty rdf:ID="name"> 
  <rdfs:domain rdf:resource="#Person"/>
  <rdfs:range rdf:resource="&xsd;string"/> 
</owl:DatatypeProperty>

<owl:Class rdf:ID="Author">
   <rdfs:subClassOf rdf:resource="#Person"/>
   <rdfs:label>Author</rdfs:label>
   <rdfs:subClassOf>
     <owl:Restriction>
       <owl:onProperty rdf:resource="#writerOf" />
       <owl:minCardinality 
rdf:datatype="&xsd;nonNegativeInteger">1</owl:minCardinality>
     </owl:Restriction>
   </rdfs:subClassOf>
</owl:Class>
<owl:Class rdf:ID="Writer">
   <owl:equivalentClass rdf:resource="#Author"/>
</owl:Class>


<owl:ObjectProperty rdf:ID="writtenBy"> 
  <rdfs:domain rdf:resource="#Book"/>
  <rdfs:range rdf:resource="#Author"/> 
</owl:ObjectProperty>
<owl:ObjectProperty rdf:ID="writerOf">
  <owl:inverseOf rdf:resource="#writtenBy"/>
</owl:ObjectProperty>
<owl:ObjectProperty rdf:ID="authorOf">
  <owl:equivalentProperty rdf:resource="#writerOf"/>
</owl:ObjectProperty>

<owl:Class rdf:ID="Director">
   <rdfs:subClassOf rdf:resource="#Person"/>
   <rdfs:label>Director</rdfs:label>
</owl:Class>

<owl:Class rdf:ID="GenreList" />
<owl:Class rdf:ID="Genre" />
<Genre rdf:ID="Fiction"/>
<Genre rdf:ID="Nonfiction"/>
<Genre rdf:ID="History"/>
<Genre rdf:ID="Philosophy"/>
<Genre rdf:ID="Memoir"/>

<owl:Class rdf:ID="BookGenre">
   <rdfs:subClassOf>
     <owl:AllDifferent rdf:about="#GenreList">
      <owl:distinctMembers rdf:parseType="Collection">
        <Genre rdf:about="#Fiction" />
        <Genre rdf:about="#Nonfiction" />
        <Genre rdf:about="#History" />
        <Genre rdf:about="#Philosophy" />
        <Genre rdf:about="#Memoir" />
      </owl:distinctMembers>
     </owl:AllDifferent>
   </rdfs:subClassOf>
</owl:Class>

<owl:SymmetricProperty rdf:ID="bundledWith">
  <rdfs:domain rdf:resource="#Product"/>
  <rdfs:range rdf:resource="#Product"/> 
</owl:SymmetricProperty>

<owl:TransitiveProperty rdf:ID="genreOf"> 
  <rdfs:domain rdf:resource="#Book"/>
  <rdfs:range rdf:resource="#BookGenre"/> 
</owl:TransitiveProperty>

<owl:Class rdf:ID="FictionBook">
   <owl:equivalentClass>
     <owl:Restriction>
       <owl:onProperty rdf:resource="#genreOf" />
     <owl:hasValue rdf:resource="#Fiction" />
     </owl:Restriction>
   </owl:equivalentClass>
</owl:Class>

<owl:Class rdf:ID="StockItem">
</owl:Class>
<owl:DatatypeProperty rdf:ID="itemPrice"> 
  <rdfs:domain rdf:resource="#StockItem"/>
  <rdfs:range rdf:resource="&xsd;double"/> 
</owl:DatatypeProperty>
<owl:DatatypeProperty rdf:ID="itemDescription"> 
  <rdfs:domain rdf:resource="#StockItem"/>
  <rdfs:range rdf:resource="&xsd;string"/> 
</owl:DatatypeProperty>
<owl:DatatypeProperty rdf:ID="itemDetailURL"> 
  <rdfs:domain rdf:resource="#StockItem"/>
  <rdfs:range rdf:resource="&xsd;string"/> 
</owl:DatatypeProperty>

<owl:ObjectProperty  rdf:ID="stockedProduct">
   <rdfs:domain rdf:resource="#StockItem"/>
   <rdfs:range rdf:resource="#Product"/>
</owl:ObjectProperty>

<owl:ObjectProperty  rdf:ID="stocks">
   <rdfs:domain rdf:resource="#Store"/>
   <rdfs:range rdf:resource="#StockItem"/>
</owl:ObjectProperty>
</rdf:RDF>

Bạn sẽ không sử dụng tất cả các định nghĩa này trong phần hướng dẫn, nhưng điều quan trọng cần nhận biết là cấu trúc, một kho Store chứa StockItems có thể ví dụ là Book, Movie và vân vân. Theo cách này bạn có thể xác định một Book một cách khái quát, các thiết lập thuộc tính về tác giả, nhà xuất bản,…nhưng vẫn còn sự khác biệt về giá cả và thông tin giao hàng phụ thuộc vào các kho hàng mà từ đó khách hàng mua sách.

Nhớ là chúng chỉ là các định nghĩa. Dữ liệu thực tế bao gồm các cá thể hoặc những ví dụ cho mỗi lớp. Ví dụ (xem ví dụ 3).

Ví dụ 3. Các cá thể của bản thể luận
...
<Bookstore rdf:ID="Amazon.com">
    <endpoint>http://webservices.amazon.com/onca/xml</endpoint>
</Bookstore>

<Bookstore rdf:ID="BarnesAndNoble.com"/>

<Author rdf:ID="J_K_Rowling"/>

<Author rdf:ID="Joanne_Rowling">
    <owl:sameAs rdf:resource="#J_K_Rowling" />
</Author>
<Author rdf:ID="Fyodor_Dostoevsky"/>

<Book rdf:ID="Harry_Potter_and_the_Sorcerers_Stone">
    <writtenBy rdf:resource="#J_K_Rowling"/>
</Book>

<StockItem rdf:ID="Harry_Potter_and_the_Sorcerers_Stone_amazon">
   <itemPrice rdf:datatype="http://www.w3.org/2001/XMLSchema#double"
                                                >29.99</itemPrice>
   <itemDescription>Harry Potter and the Sorcerers 
                                       Stone</itemDescription>
   <itemDetailURL>http://www.amazonurlforbook</itemDetailURL>
   <stockedProduct 
            rdf:resource="#Harry_Potter_and_the_Sorcerers_Stone" />
</StockItem>

<Book rdf:ID="Crime_and_Punishment">
    <writtenBy rdf:resource="#Fyodor_Dostoevsky"/>
      <bundledWith 
          rdf:resource="#Harry_Potter_and_the_Sorcerers_Stone"/>
</Book>
...

Bạn có thể đặt những cá thể này trong tệp riêng của chúng hoặc trong cùng một tệp của các định nghĩa; điều quan trọng là các không gian tên phải phù hợp với nhau.

Trong bài viết này, bạn sẽ tạo các cá thể từ dữ liệu chiết xuất được từ các dịch vụ Web cụ thể.

Cài đặt

Bài viết này giả định rằng bạn đã có một hệ thống mashup được cài đặt và đang làm việc, đồng thời có hoặc không có bộ nhớ cơ sở dữ liệu DB2. Để biết thêm thông tin về việc thiết lập Tomcat và các thành phần khác, xem Phần 1 và Phần 2 của loạt bài viết (xem Tài nguyên).

Bạn cũng có thể cần đến Jena API để hoàn thành các đoạn mã trong bài viết này. Có thể tải Jena từ http://jena.sourceforge.net/. Để cài đặt, đơn giản chỉ cần thêm các tệp Jena *.jar vào đường dẫn lớp (class path).

bài viết này sử dụng các dịch vụ giao diện của Amazon Web làm ví dụ. Để thực hiện việc mã hóa, bạn cần có các biểu tượng phát triển (developers token), và thay thế chuỗi các số 0 (000000000000000) trong mã bằng công cụ đó. Để có biểu tượng phát triển, xem http://www.amazon.com/aws.


Tạo cho người sử dụng sự lựa chọn: giao diện

Mục đích của bài viết này là cung cấp một phương thức cho người dùng thay thế một dịch vụ bằng một dịch vụ khác dựa trên thông tin trong bản thể luận. Hãy bắt đầu bằng việc cho người dùng một lựa chọn.

Tạo ra các cá thể

Bước đầu tiên là tạo một cá thể từ đó khách hàng sẽ lựa chọn. Bạn sẽ phải tạo ra các trường hợp cá biệt của các lớp Bookstore. Ví dụ, tệp bản thể luận hiện nay nhìn giống như ví dụ 4.

Ví dụ 4. Tạo ra các cá thể
<Bookstore rdf:ID="BarnesAndNoble.com"/>
<Bookstore rdf:ID="Amazon.com"/>
<Bookstore rdf:ID="Buy.com"/>

<Author rdf:ID="J_K_Rowling"/>
<Author rdf:ID="Joanne_Rowling">
    <owl:sameAs rdf:resource="#J_K_Rowling" />
</Author>
<Author rdf:ID="Fyodor_Dostoevsky"/>

<Book rdf:ID="Harry_Potter_and_the_Sorcerers_Stone">
	<writtenBy rdf:resource="#J_K_Rowling"/>
</Book>

Nhưng tất nhiên chúng hiện chỉ đơn thuần là Bookstores. Sau đó, bạn phải thêm thuộc tính cho chúng

Ghi nhớ là bạn có vài cá thể ở đây và có nhiều loại khác nhau. Bạn phải sử dụng API để kiểm tra các đối tượng này.

Tạo ra mô hình

Để trông gọn gàng hơn một chút, bạn sẽ phải điều chỉnh tất cả các chức năng bản thể luận ở trong một lớp mới, MashupOntologyReader. Bắt đầu bằng việc tạo ra lớp cơ bản (xem ví dụ 5):

Ví dụ 5. Lớp cơ bản
import com.hp.hpl.jena.ontology.*;
import java.util.Iterator;
import com.hp.hpl.jena.rdf.model.ModelFactory;

public class MashupOntologyReader {

    private OntModel bookStoreOntModel;
    
    public MashupOntologyReader(){
      
       // create an ontology model 
       bookStoreOntModel = 
            ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM, null);
       
    }

    public static void main(String[] args) {

        MashupOntologyReader reader = new MashupOntologyReader();
    }

}

Ở đây bạn sử dụng ModelFactory để tạo một mô hình bản thể luận. Lưu ý là Jena API đồng thời cũng là một RDF API, cho nên nó cho phép bạn tạo ra rất nhiều kiểu mô hình khác nhau. Bình thường, trong trường hợp này, bạn cần một mô hình bản thể luận, và thông qua các dữ liệu cố định được cung cấp, bạn phải xác định rõ là bạn muốn nó nằm bên trong bộ nhớ.

Tải bản thể luận

Jena API cho phép bạn tạo các bản thể luận từ đầu và bao gồm các phương thức cần thiết để thực hiện, trong trường hợp này, bạn đã có sẵn một tệp bản thể luận để đọc, cho nên bước tiếp theo là tải nó từ mô hình bạn vừa tạo ra (xem ví dụ 6):

Ví dụ 6. Tải bản thể luận
...
public class MashupOntologyReader {

    private OntModel bookStoreOntModel;
    
    public MashupOntologyReader(){
       String source = "http://example.com/store";
       
       // create an ontology model 
       bookStoreOntModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM, null);
       
       // you have a local copy of the bookstore ontology
       bookStoreOntModel.getDocumentManager().addAltEntry( source, "file:c:/sw/stores.owl" ); // 
read the source document bookStoreOntModel.read( source );

   }

    public static void main(String[] args) {

        MashupOntologyReader reader = new MashupOntologyReader();
    }

}

Đầu tiên, hãy dành chỗ ghi tên cho đối tượng bạn vừa tải. Với bản thể luận bạn đã xây dựng ở phần 4, không gian tên là http://www.example.com/store Từ đó bạn sử dụng của mô hình DocumentManager để thêm vào các đầu mục. Lưu ý rằng bạn chỉ rõ không gian tên và tập tin mà từ đó cho phép thâm nhập, nhưng các mô hình không thực sự đọc các định nghĩa trừ khi bạn gọi hàm read().

Duyệt qua các cá thể

Mục tiêu là có được danh sách các cá thể Bookstore trong bản thể luận, vì thế bắt đầu bằng việc đi qua chuỗi tất cả các cá thể có mặt (xem ví dụ 7).

Ví dụ 7. Duyệt các cá thể
...
       // read the source document
       bookStoreOntModel.read( source );        

   }

    public void getIndividuals(){
        
         int counter = 0;
                
        for (Iterator i = bookStoreOntModel.listIndividuals();  i.hasNext(); ) {
            
            counter++;
            Individual thisIndividual = (Individual) i.next();
            System.out.println(counter);
            
        }        

    }
        
    public static void main(String[] args) {

        MashupOntologyReader reader = new MashupOntologyReader();
        reader.getIndividuals();

    }

}

Để bắt đầu, cần tạo ra một phương thức getIndividuals() mà nó sẽ tạo ra một bộ đếm và sử dụng mô hình của phương thức listIndividuals() của bản thể luận để lấy bộ lặp Iterator chuẩn của JAVA qua nó bạn có thể tiếp cận các cá thể tìm được. Bạn chưa có bất kỳ một dữ liệu nào về các cá thể do đó đơn giản cung cấp một bộ đếm để xem điều gì xảy ra. Bạn sẽ có một danh sách từ một đến mười một.

Bây giờ mọi việc đều thú vị, rõ ràng bạn có nhiều hơn là các cá thể Bookstore. Hãy tìm hiểu xem bạn thật sự thu được cái gì.

Có các thông tin về cá thể

Khi có thông tin tham khảo của cá thể, việc thu thập các thông tin của nó là vấn đề đơn giản thông qua sử dụng các phương thức thu thập mà API cung cấp. Bất kỳ một cá thể Individual nào, cho dù là loại đối tượng nào, đều có ba loại thông tin giống nhau: URI, sử dụng duy nhất để xác định tài nguyên, kiểu, và tên, cái mà tương ứng với thuộc tính rdf:ID trong tệp RDF (xem ví dụ 8):

Ví dụ 8. Lấy thông tin cá thể
...
    public void getIndividuals(){
        
        int counter = 0;
                
        for (Iterator i = bookStoreOntModel.listIndividuals();  i.hasNext(); ) {
            
            counter++;
            Individual thisIndividual = (Individual) i.next();
            
            String indType = thisIndividual.getRDFType().getLocalName();
            String indName = thisIndividual.getLocalName();
            String indResourceURI = thisIndividual.getURI(); 
            System.out.println(indType + "   " + indName + "  " + 
                                                        indResourceURI);
        }        

    }
...

Bạn cần chú ý đầu ra trông giống với Ví dụ 9:

Ví dụ 9. Đầu ra thông tin cá thể
0: Book   Harry_Potter_and_the_Sorcerers_Stone  
http://example.com/store#Harry_Potter_and_the_Sorcerers_Stone
1: Genre   Memoir  http://example.com/store#Memoir
2: Genre   Philosophy  http://example.com/store#Philosophy
3: Genre   History  http://example.com/store#History
4: Genre   Nonfiction  http://example.com/store#Nonfiction
5: Genre   Fiction  http://example.com/store#Fiction
6: Author   Fyodor_Dostoevsky  http://example.com/store#Fyodor_Dostoevsky
7: Author   Joanne_Rowling  http://example.com/store#Joanne_Rowling
8: Author   J_K_Rowling  http://example.com/store#J_K_Rowling
9: Bookstore   Buy.com  http://example.com/store#Buy.com
10: Bookstore   Amazon.com  http://example.com/store#Amazon.com
11: Bookstore   BarnesAndNoble.com  http://example.com/store#BarnesAndNoble.com

Chú ý rằng thứ tự các cá thể xuất hiện ở đầu ra thì không cần thiết phải giống với thứ tự chúng xuất hiện trong tệp bản thể luận. Hiện giờ chúng không là vấn đề, nhưng nếu nhúng dữ liệu vào mẫu (template) thì sẽ có vấn đề. May mắn là nếu biết trước là sẽ được chuẩn bị trước và đây là vấn đề có thể xử lý dễ dàng.

Tại thời điểm này bạn chỉ lo lắng về chuyện thu thập các cá thể Bookstore.

Chỉ lấy ra các Bookstores

Sự thật là các kiểu tài nguyên được đại diện như một chuỗi (string) sẽ tạo điều kiện dễ dàng để lấy ra Bookstores hoặc bất kỳ kiểu cụ thể nào (xem ví dụ 10):

Ví dụ 10. Chiết xuất chỉ một loại cá thể
...
    public Individual[] getIndividuals(String individualType){
        
        int counter = -1;
    
        Individual[] individuals = new Individual[50];
        
        for (Iterator i = bookStoreOntModel.listIndividuals();  i.hasNext(); ) {
            

            Individual thisIndividual = (Individual) i.next();
            
             String indType = thisIndividual.getRDFType().getLocalName();
             String indName = thisIndividual.getLocalName(); 
             String indResourceURI = thisIndividual.getURI(); 
             if (indType.equals(individualType)){
                 counter++;
                 individuals[counter] = thisIndividual;
                 System.out.println(counter + ": " + indType + "   " + indName + 
                                                             "  " + indResourceURI);
             } 
        }      
        
        return individuals;

    }
    
    
    public static void main(String[] args) {

        MashupOntologyReader reader = new MashupOntologyReader();
        Individual[] individuals = reader.getIndividuals("Bookstore");
        

    }

}

Trong trường hợp này, bạn kiểm tra kiểu đã gửi đến so với loại của từng cá thể, và nếu cá thể là một trong những loại bạn đang tìm kiếm thì bạn chuyển nó vào mảng các individuals. Sau khi bạn xem tất cả các cá thể, quay trở lại mảng như là đầu ra của phương thức.

Bước tiếp theo là thêm tính năng này vào ứng dụng thực sự.

Tạo ra một thực đơn từ danh sách các dịch vụ

Tại thời điểm này, bạn đã sẵn sàng tiếp cận với các khả năng của Jena từ trong các ứng dụng thật của web. Trước khi bạn bắt đầu, phải chắc chắn rằng các tệp *.jar đều có thể truy cập vào từ ứng dụng của web và lớp MashupOntologyReader có sẵn cho servlet. Bổ sung chức năng sau vào phương thức doGet() (xem ví dụ 11):

Ví dụ 11. Tạo ra một mẫu chọn thực đơn
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
                                            throws ServletException, IOException {
        
        MashupOntologyReader reader = new MashupOntologyReader();
        Individual[] individuals = reader.getIndividuals("Bookstore");

        
        response.getWriter().print("<html>");
        response.getWriter().print("<head></head>");
        response.getWriter().print("<body>");

        response.getWriter().print("<h1>The Mashup</h1>");
        response.getWriter().print("<form action='MashupClientServlet' 
                                                           method='post'>");
        response.getWriter().print("<p>Choose a bookstore:</p>");
        response.getWriter().print("<select name=\"serviceURI\">");
        
        for (int i = 0; i < individuals.length; i++){
            Individual thisIndividual = individuals[i];
            if (thisIndividual != null){
               String id = thisIndividual.getURI();
               System.out.println("["+id+"]");
               String label = thisIndividual.getLocalName();
               System.out.println("["+label+"]");
               response.getWriter().print("<option "+
                         "value=\""+id+"\">"+label+"</option>");
            }
        }
        response.getWriter().print("</select>");
        response.getWriter().print("<p>Enter a keyword:</p>");
        response.getWriter().print("<input type='text' name='query' />");
        response.getWriter().print("<input type='submit' />");
        response.getWriter().print("</form>");
        response.getWriter().print("</body>");
        response.getWriter().print("</html>");
    }

Đầu tiên, tạo một thể hiện của lớp MashupOntologyReader, cái mà cũng tải bản thể luận thực sự. Từ đó bạn có thể sử dụng phương thức getIndividuals() bạn vừa tạo ra để thu được một mảng Bookstore. Khi bạn đã có mảng Bookstore bạn có thể lặp vòng chúng nếu bạn muốn các mảng khác sử dụng cùng phương thức trước khi thu lại được URI và tên hoặc ID. Sử dụng chúng để tạo ra thực đơn HTML select trong mẫu có sẵn.

Kết quả cuối cùng trông giống hình 1

Hình 1. Thêm vào hộp lựa chọn
Thêm vào hộp lựa chọn

Gửi biểu mẫu và dịch vụ đầu ra

Lấy dịch vụ mà người sử dụng muốn sử dụng là việc rất giản đơn. Thực tế, nó không khác với lấy lại bất cứ thông tin nào đã gửi từ một biểu mẫu (xem ví dụ 12):

Ví dụ 12. Lấy lại thông tin từ mẫu thông tin
...
    protected void doPost(HttpServletRequest request, HttpServletResponse 
response) throws ServletException, IOException {

        
        String query = request.getParameter("query").toString();
        String serviceURI = request.getParameter("serviceURI").toString();
        Service service = ont.obtainServiceInfo(serviceURI);
        
        
        response.getWriter().print("<p>Results pulled from "
                                                        +serviceURI+"</p>");
        try {
            DocumentBuilder builder = 
                        DocumentBuilderFactory.newInstance().newDocumentBuilder();
...

Một cách đơn giản, lấy serviceURI như là một tham số từ mẫu. Bạn có thể cung cấp nó tới trang để bảo đảm nó hoạt động được.

Bây giờ bạn có thể sẵn sàng lấy lại thông tin dịch vụ thực tế.


Lấy lại dịch vụ thông tin từ bản thể luận

Giờ bạn đã biết loại dịch vụ nào người sử dụng muốn dùng, bạn sẽ cần phải lấy thông tin về nó từ bản thể luận. Để làm vậy, bạn cần thêm API đối với phương thức doPost().

Bổ sung thông tin dịch vụ vào bản thể luận

Khi bạn xây dựng bản thể luận ở Phần 4, đã bao gồm thông tin dịch vụ căn bản, nhưng bây giờ phải chi tiết hơn một chút. Đặc biệt, phải thêm vào các thông tin bổ sung về dịch vụ, chẳng hạn như mẫu và bản ghi dữ liệu hiển thị đang tồn tại ở thời điểm lớp Service hiện tại cũng như một cách để tập hợp các tham số bổ sung cho một dịch vụ, chẳng hạn như các kiểu tìm kiếm hoặc một mã phát triển (developer token).

Ví dụ 13. Làm rõ trên định nghĩa về dịch vụ
...
<owl:Class rdf:ID="Service">
   <rdfs:label>Web Service</rdfs:label>
   <rdfs:subClassOf>
     <owl:Restriction>
       <owl:onProperty rdf:resource="#endpoint" />
       <owl:minCardinality rdf:datatype=
           "&xsd;nonNegativeInteger">1</owl:minCardinality>
     </owl:Restriction>
   </rdfs:subClassOf>

   <rdfs:subClassOf>
     <owl:Restriction>
       <owl:onProperty rdf:resource="#template" />
       <owl:minCardinality rdf:datatype=
            "&xsd;nonNegativeInteger">1</owl:minCardinality>
     </owl:Restriction>
   </rdfs:subClassOf>

</owl:Class>
<owl:DatatypeProperty  rdf:ID="endpoint">
   <rdfs:domain rdf:resource="#Service"/>
   <rdfs:range rdf:resource=
                   "http://www.w3.org/2001/XMLSchema#anyURI"/>
</owl:DatatypeProperty>
<owl:ObjectProperty  rdf:ID="inputparameter">
   <rdfs:domain rdf:resource="#Service"/>
   <rdfs:range rdf:resource="#ServiceParameterMap"/>
</owl:ObjectProperty>
<owl:DatatypeProperty rdf:ID="rootoutputnode">
   <rdfs:domain rdf:resource="#Service"/>
   <rdfs:range rdf:resource="&xsd;string"/>
</owl:DatatypeProperty>
<owl:DatatypeProperty  rdf:ID="xsltTransformationString">
   <rdfs:domain rdf:resource="#Service"/>
   <rdfs:range rdf:resource="&xsd;string"/>
</owl:DatatypeProperty>

<owl:DatatypeProperty  rdf:ID="queryParameter">
   <rdfs:domain rdf:resource="#Service"/>
   <rdfs:range rdf:resource="&xsd;string"/>
</owl:DatatypeProperty>

<owl:DatatypeProperty  rdf:ID="template">
   <rdfs:domain rdf:resource="#Service"/>
   <rdfs:range rdf:resource="&xsd;string"/>
</owl:DatatypeProperty>
<owl:DatatypeProperty  rdf:ID="elementValue">
   <rdfs:domain rdf:resource="#Service"/>
   <rdfs:range rdf:resource="&xsd;string"/>
</owl:DatatypeProperty>
<owl:DatatypeProperty  rdf:ID="attributeValue">
   <rdfs:domain rdf:resource="#Service"/>
   <rdfs:range rdf:resource="&xsd;string"/>
</owl:DatatypeProperty>

<owl:Class rdf:ID="ServiceParameterMap">
   <rdfs:label>Web Service Parameter Map</rdfs:label>
   <rdfs:subClassOf>
     <owl:Restriction>
       <owl:onProperty rdf:resource="#paramname" />
       <owl:cardinality 
rdf:datatype="&xsd;nonNegativeInteger">1</owl:cardinality>
     </owl:Restriction>
   </rdfs:subClassOf>
   <rdfs:subClassOf>
     <owl:Restriction>
       <owl:onProperty rdf:resource="#paramvalue" />
       <owl:cardinality 
rdf:datatype="&xsd;nonNegativeInteger">1</owl:cardinality>
     </owl:Restriction>
   </rdfs:subClassOf>
</owl:Class>
<owl:DatatypeProperty  rdf:ID="paramname">
   <rdfs:domain rdf:resource="#ServiceParameterMap"/>
   <rdfs:range rdf:resource="&xsd;string"/>
</owl:DatatypeProperty>
<owl:DatatypeProperty  rdf:ID="paramvalue">
   <rdfs:domain rdf:resource="#ServiceParameterMap"/>
   <rdfs:range rdf:resource="&xsd;string"/>
</owl:DatatypeProperty>
...

Bất cứ thông tin nào như mẫu ghi các hồ sơ hiển thị (ở đây gọi là rootnode) khá là dễ hiểu. Bạn chỉ cần thêm vào như một thuộc tính của lớp. Ở một số trường hợp, tình trạng không đơn giản như thế. Ví dụ, nhập các thông số đầu vào cần cả tên và giá trị, cho nên bạn phải xây dựng cấu trúc để có đủ các thông tin như vậy.

Trong trường hợp này, cấu trúc này được gọi là ServiceParameterMap. ServiceParameterMap tham chiếu với tài nguyên paramnameparamvalue. Với toàn bộ các thuộc tính đã được tạo ra, bây giờ bạn có thể thiết lập các cá thể thực tế.

Dịch vụ riêng biệt trong bản thể luận

Tạo các cá thể dịch vụ thực tế khá đơn giản, chỉ cần theo cấu trúc các lớp (xem ví dụ 14).

Ví dụ 14. Tạo ra cá thể hiệu sách
<Bookstore rdf:ID="Amazon.com">
    <endpoint>http://webservices.amazon.com/onca/xml</endpoint>
    <rootoutputnode>/ItemSearchResponse/Items/Item</rootoutputnode> 
    <inputparameter rdf:resource="#amazonInput1"/>
    <inputparameter rdf:resource="#amazonInput2"/>
    <inputparameter rdf:resource="#amazonInput3"/>
    <inputparameter rdf:resource="#amazonInput4"/> 
    <inputparameter rdf:resource="#amazonInput5"/> 
    <xsltTransformationString>
       <![CDATA[
           TBD
         ]]>
    </xsltTransformationString> 
    <template>
        <![CDATA[ 
             <p><a value='href'><value/></a> by 
<value/></p> 
        ]]>
    </template>
    <elementValue>ItemAttributes/Title!ItemAttributes/Author</elementValue>
    <attributeValue>DetailPageURL</attributeValue>
    <queryParameter>Title</queryParameter>
</Bookstore>
<ServiceParameterMap rdf:ID="amazonInput1">
    <paramname>Service</paramname>
    <paramvalue>AWSECommerceService</paramvalue>
</ServiceParameterMap>
<ServiceParameterMap rdf:ID="amazonInput2">
    <paramname>AWSAccessKeyId</paramname>
    <paramvalue>000000000000000</paramvalue>
</ServiceParameterMap>
<ServiceParameterMap rdf:ID="amazonInput3">
    <paramname>SearchIndex</paramname>
    <paramvalue>Books</paramvalue>
</ServiceParameterMap>
<ServiceParameterMap rdf:ID="amazonInput5">
    <paramname>ResponseGroup</paramname>
    <paramvalue>Large</paramvalue>
</ServiceParameterMap>
<ServiceParameterMap rdf:ID="amazonInput4">
    <paramname>Operation</paramname>
    <paramvalue>ItemSearch</paramvalue>
</ServiceParameterMap>

Một số đặc tính, ví dụ mẫuelementValue bạn cần nhận ra từ lớp Service. Các lớp khác, ví dụ như tài nguyên inputparameter là mới và được tạo ra như là các ví dụ riêng biệt của lớp ServiceParameterMap, sau đó được tham khảo từ trong phần chính của cá thể dịch vụ như đặc tính inputparameter.

Ngoài ra có vẻ sẽ là tốt nếu thêm mỗi elementValueattributeValue trong chính đặc tính của nó, nó sẽ gây ra rắc rối vì bạn không thể dự đoán thứ tự nào chúng có thể được lấy lại, nhưng bạn phải chắc chắn thứ tự mà chúng xuất hiện. Để xử lý vấn đề này, bao gồm cả tất cả các giá trị, được tách ra bởi một dấu chấm than (!). Dấu chấm than có vẻ sẽ không xuất hiện trong các biểu thức XPath, mà sau này bạn có thể sử dụng nó như là một dấu phân cách.

Chú ý bạn có thể đơn giản cho thêm vào một tham số đối với điểm cuối cùng, nhưng làm như vậy bạn sẽ có rất nhiều lợi ích. Một là bạn có thể chọn linh hoạt các tham số như là nguyên tắc của nhân tố phát triển (developer key), hai là cấu trúc của bạn được đồng nhất hơn và do đó dễ dàng trong việc áp dụng các ứng dụng cho các dịch vụ SOAP cũng nhưng REST.

Bây giờ hãy nhìn các thông tin thu được.

Thu lại các cá thể

Bước đầu tiên là tìm các tham khảo đối với tài nguyên đại diện cho cá thể ở trong bản thể luận. Do các giá trị quay lại bởi hộp lựa chọn là URI cho tài nguyên, việc lựa chọn là tương đối dễ dàng (xem ví dụ 15):

Ví dụ 15. Thu lại các cá thể
...
public class MashupOntologyReader {

    private OntModel bookStoreOntModel;
        
    public MashupOntologyReader(){
       ...
    }

    public Individual[] getIndividuals(String individualType){
        ...
        return individuals;

    }
    
    public void obtainServiceInfo(String serviceURI){ Individual bookstore = 
bookStoreOntModel.getIndividual(serviceURI);
        
        }
       
    }
   
    public static void main(String[] args) {

        MashupOntologyReader reader = new MashupOntologyReader();
        Individual[] individuals = reader.getIndividuals("Bookstore");
        reader.obtainServiceInfo( "http://example.com/store#Amazon.com");

    }

}

Tạo một phương thức mới, obtainServiceInfo() trong lớp MashupOntologyGreater và sử dụng phương thức getIndividual() để lấy lại tài liệu tham khảo đối với tài nguyên cụ thể.

Từ đây bạn có thể lấy ra các thông tin về chính dịch vụ đó.

Thu lại các tham số dịch vụ

Các tham biến dịch vụ được lưu như là đặc tính của tài nguyên đại diện cho dịch vụ do đó bạn phải tiếp cận những đặc tính này để lấy thông tin (xem ví dụ 16):

Ví dụ 16. Lấy các tham biến dịch vụ
...
public class MashupOntologyReader {

    private OntModel bookStoreOntModel;
        
    public MashupOntologyReader(){
       ...
    }

    public Individual[] getIndividuals(String individualType){
        ...
        return individuals;

    }
    
    public void obtainServiceInfo(String serviceURI){

        Individual bookstore = 
                   bookStoreOntModel.getIndividual(serviceURI);
        
        for (StmtIterator i = bookstore.listProperties(  );
                                               i.hasNext(); ) {
            
            Statement s = i.nextStatement();
            Property p = s.getPredicate();

            if (p.canAs(OntProperty.class)){
                
                Resource r;
                Literal l;
                if (p.getLocalName().equals("endpoint")){
                    l = s.getLiteral();
                    System.out.println( p.getLocalName() + " ==> " 
                                                 + l.getString() );
                }
                else if (p.getLocalName().equals("rootoutputnode")){
                    l = s.getLiteral();
                    System.out.println( p.getLocalName() + " ==> " 
                                                  + l.getString() );
                }
                else if (p.getLocalName().equals("inputparameter")){
                    r = s.getResource();
                    System.out.println( getParameterName(r.getURI())  
                          + " ==> " + getParameterValue(r.getURI()));            
                }
                else if (p.getLocalName()
                          .equals("xsltTransformationString")){
                    l = s.getLiteral();
                    System.out.println( p.getLocalName() + " ==> " 
                                                 + l.getString() );
                }
                else if (p.getLocalName().equals("template")){
                    l = s.getLiteral();
                    System.out.println( p.getLocalName() + " ==> " 
                                                  + l.getString() );
                }
                else if (p.getLocalName().equals("elementValue")){
                    l = s.getLiteral();
                    System.out.println( p.getLocalName() + " ==> " 
                                                  + l.getString() );
                }
                else if (p.getLocalName().equals("attributeValue")){
                    l = s.getLiteral();
                    System.out.println( p.getLocalName() + " ==> " 
                                                  + l.getString() );
                }
                else if (p.getLocalName().equals("queryParameter")){
                    l = s.getLiteral();
                    System.out.println( p.getLocalName() + " ==> " 
                                                  + l.getString() );
                }
            }
        }
       
    }
   
    public String getParameterName(String uri){
        // this assumes the uri is to a ServiceParameterMap
        OntResource or = bookStoreOntModel.getOntResource(uri);
        String toReturn=null;
        for (StmtIterator i = or.listProperties(  ); i.hasNext(); ) {
            Statement s = i.nextStatement();
            Property p = s.getPredicate();
            if (p.canAs(OntProperty.class)){
                Resource r;
                Literal l;
                if (p.getLocalName().equals("paramname")){
                    l = s.getLiteral();
                    toReturn=l.getString();
                }
            }
        }               
        return toReturn;        
    }

    public String getParameterValue(String uri){
        // this assumes the uri is to a ServiceParameterMap
        OntResource or = bookStoreOntModel.getOntResource(uri);
        String toReturn=null;
        for (StmtIterator i = or.listProperties(  ); i.hasNext(); ) {
            Statement s = i.nextStatement();
            Property p = s.getPredicate();
            if (p.canAs(OntProperty.class)){
                Resource r;
                Literal l;
                if (p.getLocalName().equals("paramvalue")){
                    l = s.getLiteral();
                    toReturn=l.getString();
                }
            }
        }               
        return toReturn;
    }
    
    public static void main(String[] args) {

        MashupOntologyReader reader = new MashupOntologyReader();
        Individual[] individuals = reader.getIndividuals("Bookstore");
        reader.obtainServiceInfo(
                               "http://example.com/store#Amazon.com");

    }

}

Đáng tiếc, bạn không thể chỉ đơn giản vào và nhặt lấy các đặc tính. Thay vào đó, bạn phải lặp lại tất cả các đặc tính sử dụng phương thức listProperties() mà nó sẽ trả lại cho một bộ lặp Iterator.

Bạn phải nhớ rằng trong RDF, các thuộc tính được trình bày dưới dạng các câu hoặc các câu lệnh ví dụ như "The Amazon.com service has an endpoint of http://webservices.amazon.com/onca/xml." Sử dụng ngữ pháp một cách thông minh, cụm "has an endpoint of http://webservices.amazon.com/onca/xml" là phần thuộc tính của câu. Do đó, bước đầu tiên để truy lục các thuộc tính là truy lục câu lệnh, sau đó truy lục các thuộc tính từ đây.

Khi bạn đã có các thuộc tính, đầu tiên bạn cần chắc chắn rằng thực tế đó là thuộc tính bản thể luận. Sau cùng, đó có thể là một thuộc tính RDF hoặc một thuộc tính bất thường khác. Khi bạn chắc rằng đó là một thuộc tính bản thể luận, bạn có thể truy vấn localName và so sánh nó với các tham số mà bạn mong đợi.

Khi bạn biết mình đang xử lý thuộc tính nào thì việc bạn làm gì phụ thuộc vào thể loại thuộc tính đó. Một số đặc tính như mẫu (template), đơn giản là các chuỗi ký tự bằng chữ, và bạn có thể trích ra như vậy. Tuy nhiên, một số thuộc tính khác như inputparameter là các tài nguyên, do đó bạn không thể đơn giản trích các giá trị bằng chữ từ đây. Thay vào đó, bạn cần trích các thuộc tính của chúng. Ví dụ inputparameter bao gồm một mục tiêu cùng với một thuộc tính paramnameparamvalue. Để tìm các thuộc tính này, bạn có thể thiết kế phương thức getParameterName()getParameterValue() mà lặp chính nó thông qua các thuộc tính của tài nguyên chủ thể.

Khi ta chạy ứng dụng, bạn sẽ có kết quả tương tự như hình 2:

Hình 2. Thông tin dịch vụ
Thông tin dịch vụ

Lớp dịch vụ được cập nhật

Tất cả các thông tin này không tốt với bạn trừ khi nó được lưu đâu đó mà bạn có thể có được. Ứng dụng hiện được cài đặt để phân tích và chạy một mảng các mục tiêu dịch vụ, vì vậy dự đoán tốt nhất là chỉnh sửa lớp dịch vụ sao cho nó có thể lưu trữ dữ liệu (xem ví dụ 17):

Ví dụ 17. Lớp dịch vụ được cập nhật
import java.util.Vector;

public class Service {

       String name = ";
       String baseURL = ";
       String template = ";
       Vector inputParameters = new Vector();
       String queryParameter = "";
       String recordExp = "";
       String xsltTransformationString = "";
       Vector elementValues = new Vector();
       Vector attributeValues = new Vector();
       String filterExp = "";
       Service subSvc = null;
   
}

Mục đích của lớp dịch vụ nguyên bản là cung cấp một nơi lưu dữ liệu, thuyết minh các mục tiêu bất kỳ và gửi chúng lại. Bạn sẽ không phải làm như vậy nữa - mọi dữ liệu có từ bản thể luận. Tất cả những gì bạn cần làm là chắc chắn bạn có các tham số thành viên cho mỗi mảng dữ liệu mà bạn muốn lưu trữ, như là inputparametersxsltTransformationString.

Tương tự, để làm các lớp dịch vụ linh động hơn, thay đổi elementValuesattributeValues thành các Vector, chứ không phải các mảng kích thước cố định, như lúc trước đây của chúng.

Bây giờ bạn có thể tạo dịch vụ .

Tạo dịch vụ

Bạn vừa hoàn thành công việc khó khăn là trích xuất dữ liệu từ bản thể luận. Những gì bạn cần làm bây giờ là tạo một mục tiêu dịch vụ mới và sau đó thêm các thông tin vào đó (xem ví dụ 18):

Ví dụ 18. Tạo dịch vụ
...
    public Service obtainServiceInfo(String serviceURI){

        Individual bookstore = 
                   bookStoreOntModel.getIndividual(serviceURI);
        
        Service svc = new Service();
        
        for (StmtIterator i = bookstore.listProperties(  );
                                               i.hasNext(); ) {
            
            Statement s = i.nextStatement();
            Property p = s.getPredicate();

            if (p.canAs(OntProperty.class)){
                
                Resource r;
                Literal l;
                if (p.getLocalName().equals("endpoint")){
                    l = s.getLiteral();
                    svc.baseURL=l.getString();
                    System.out.println( p.getLocalName() + " ==> " 
                                                 + l.getString() );
                }
                else if (p.getLocalName().equals("rootoutputnode")){
                    l = s.getLiteral();
                    svc.recordExp=l.getString();
                    System.out.println( p.getLocalName() + " ==> " 
                                                  + l.getString() );
                }
                else if (p.getLocalName().equals("inputparameter")){
                    r = s.getResource();
                    svc.inputParameters.add(r.getURI());
                    System.out.println( getParameterName(r.getURI())  
                          + " ==> " + getParameterValue(r.getURI()));            
                }
                else if (p.getLocalName()
                          .equals("xsltTransformationString")){
                    l = s.getLiteral();
                    svc.xsltTransformationString=l.getString();
                    System.out.println( p.getLocalName() + " ==> " 
                                                 + l.getString() );
                }
                else if (p.getLocalName().equals("template")){
                    l = s.getLiteral();
                    svc.template=l.getString();
                    System.out.println( p.getLocalName() + " ==> " 
                                                  + l.getString() ); 
                }
              else if (p.getLocalName().equals("elementValue")){
                    l = s.getLiteral();
                    String[] elementValues = l.getString().split("!");
                    for (int j = elementValues.length; j>0; j--){
                       svc.elementValues.add(elementValues[(j-1)]);
                    }
                    System.out.println( p.getLocalName() + " ==> " 
                                                  + l.getString() ); 
                }
                else if (p.getLocalName().equals("attributeValue")){
                    l = s.getLiteral();
                    String[] attributeValues = l.getString().split("!");
                    for (int j = attributeValues.length; j>0; j--){
                       svc.attributeValues.add(attributeValues[(j-1)]);
                    }
                    System.out.println( p.getLocalName() + " ==> " 
                                                  + l.getString() ); 
                }
                else if (p.getLocalName().equals("queryParameter")){
                    l = s.getLiteral();
                    svc.queryParameter = l.getString();
                    System.out.println( p.getLocalName() + " ==> " 
                                                  + l.getString() );
                }
            }
        }
        return svc;
        
    }
   
...

Lưu ý rằng bạn nắm được sự khác nhau của các tên giữa lớp dịch vụ và bản thể luận trong phương thức này. Ví dụ, bạn đã vạch ra endpoint đối với baseURL. Cũng lưu ý rằng, trong khi bạn có thể thêm chuỗi các chữ ví dụ như mẫu trực tiếp đối với lớp, bất cứ đặc tính được đại diện như là một tài nguyên, ví như inputparameter có thêm những thứ không phải là ký tự chữ, mà như URI đối với tài nguyên. (Bạn có thể quyết định các ứng dụng của mình sẽ có lợi từ tất cả thông tin chứa trực tiếp giữa các lớp. Trong tình huống đó, bạn cần chế tác thêm tại điểm này). Bạn cũng có thể phân chia các giá trị trong thuộc tính elementValueattributeValue thành một mảng, và sau đó sử dụng mảng để tạo dịch vụ.

Bước tiếp theo là xây dựng yêu cầu REST thực.

Xây dựng yêu cầu

Lúc này, bạn có tất cả thông tin dịch vụ, nhưng bạn không có một yêu cầu có thể gửi trực tiếp đến dịch vụ, vì tất cả các tham số đầu vào đã bị tách thành các tài nguyên riêng lẻ. Việc tạo ra yêu cầu này là một đặc tính đối với dịch vụ, và không phải một phần của bản thể luận hay servlet, vì vậy bao gồm nó như một phần của lớp dịch vụ (xem ví dụ 19):

Ví dụ 19. Xây dựng yêu cầu
import java.util.Vector;

public class Service {

       String name = "";
...
   public String getRESTRequest(MashupOntologyReader ont){

       String restQuery = this.baseURL;
       for (int i=0;i<this.inputParameters.size();i++){
           String serviceParameterMapURI = 
                (String) this.inputParameters.elementAt(i);
           if (restQuery.equals(this.baseURL))
               restQuery = restQuery + "?";
           else
               restQuery = restQuery + "&";
           restQuery = restQuery + 
                   ont.getParameterName(serviceParameterMapURI) + "=" +
                   ont.getParameterValue(serviceParameterMapURI);
       }
       
       restQuery = restQuery + "&" + this.queryParameter + "=";

       return restQuery;

   }
}

Trong phương thức getRESTRequest(), bạn lặp qua mỗi inputParameters, thêm chúng vào baseURL. Cuối cùng, cuối URL, bạn thêm các tham số truy vấn thực và một tín hiệu ngang bằng (=). Theo cách này, khi bạn thêm các từ khoá để tìm đến hết truy vấn, bạn có một truy vấn URL đầy đủ như:

http://webservices.amazon.com/onca/xml?ResponseGroup=Large&Service=
   AWSECommerceService&AWSAccess KeyId=000000000000000&SearchIndex=
   Books&Operation=ItemSearch&Title=Star+Wars

Lưu ý: Mã gốc là một dòng đơn thông thường. Để dễ nhìn, nó được diễn tả trên nhiều dòng như trên.

Tạo các yêu cầu

Thực ra, việc tạo các yêu cầu được tiến hành hầu như giống hệt như trước (xem ví dụ 20):

Ví dụ 20. Tạo yêu cầu
...
    protected void doPost(HttpServletRequest request, 
                          HttpServletResponse response) 
                             throws ServletException, IOException {

        MashupOntologyReader ont = new MashupOntologyReader();
        
        String query = request.getParameter("query").toString();
        String serviceURI = 
                   request.getParameter("serviceURI").toString();
        Service service = ont.obtainServiceInfo(serviceURI);
        
        
        try {
            DocumentBuilder builder = 
                   DocumentBuilderFactory.newInstance()
                                         .newDocumentBuilder();
           
            Service[] svcs = {service};
            
            Document hostDoc = builder.parse(
                     new InputSource(new StringReader("<results/>")));
            Node hostRoot = hostDoc.getDocumentElement();

            for (int k=0; k < svcs.length; k++){

                Service svc = svcs[k];
                Node renderedService =  
                     renderService(svc.getRESTRequest(ont)+query, 
                                                         hostDoc);

                if (renderedService != null){

                    Element nameElement = hostDoc.createElement("h1");
                    nameElement.appendChild(
                                    hostDoc.createTextNode(svc.name));
...

Đầu tiên, bạn cần mở bản thể luận - bạn cũng cần nó để đặt dịch vụ vào, và tạo yêu cầu REST. Khi bạn đã đặt dịch vụ vào rồi, bạn có thể sử dụng nó để thay thế các thành phần trong mảng dịch vụ với một thành phần đơn nhất. Từ đây, mọi thứ tiến hành như trước, trừ khi bạn tạo truy vấn khi bạn sử dụng dịch vụ renderService().

Bây giờ bạn có thể chạy ứng dụng và có kết quả tương tự với những gì được tạo ra trong phiên bản ứng dụng cơ bản hơn.


Chuyển đổi kết quả

Tới đây, những gì bạn cần hoàn tất là thay đổi ứng dụng nhận thông tin như thế nào về dịch vụ. Nó vẫn yêu cầu thông tin như vậy, và nó triển khai thông tin thô được trả lại từ dịch vụ. Bước tiếp theo là chuyển đổi thông tin đặc tính dịch vụ thành thông tin dạng bản thể luận tổng quát (generic ontological information).

Đầu vào

Hãy cùng bắt đầu bằng cách xem dữ liệu được trả về từ yêu cầu thực. Dịch vụ mạng Amazon thực tế đưa cho bạn một sự lựa chọn về lượng dữ liệu bạn muốn được gửi lại là bao nhiêu, bằng cách chọn một ResponseGroup của Small, bạn sẽ có thông tin cơ bản nhất, cái mà ít cồng kềnh để xử lý hơn là một kết quả đầy đủ. Không may rằng bạn sẽ cần yêu cầu một ResponseGroup của Large để có thông tin về giá. Dữ liệu trả lại có dạng như sau (xem Ví dụ 21):

Ví dụ 21. Dữ liệu thô
<?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>
...

Tất nhiên, bạn đủ khả năng để thêm các thông tin này vào bản thể luận của bạn, nhưng vì mục đích của bài viết này, nên gắn với các vấn đề cơ bản.

Kết quả đích

Mục tiêu tổng thể là nắm được thông tin và chuyển đổi nó thành một dạng phù hợp với bản thể luận. Trong trường hợp này, trông nó sẽ như sau (xem ví dụ 22):

Ví dụ 22. Mục tiêu đầu ra
<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>

Một vài mục cần lưu ý ở đây. Đầu tiên là Book có một mã số bao gồm số xuất bản (ISBN). Số này là duy nhất trong tất cả dịch vụ. Trong một quy trình sản xuất, bạn muốn kiểm tra để chắc chắn rằng yếu tố này không tồn tại trước khi bạn tạo lại nó; có thể rằng cuốn sách tương tự đã có yêu cầu từ dịch vụ khác, hoặc thậm chí một truy vấn khác từ dịch vụ tương tự.

Tương tự, mã này tránh được sự trùng lặp các yếu tố tác giả bằng cách chưa xử lý trước số xuất bản với tên tác giả trong mã số. Cũng như vậy, bạn sẽ phải xử lý với thực tế rằng một giá trị mã số không thể có các khoảng cách trong đó. StockItem tham chiếu ngược lại Book thông qua đặc tính stockProduct cái mà chứng nhận là những tài nguyên thích hợp.

Khi bạn đã chuyển dữ liệu sang dạng này, bạn có thể lưu nó trong cơ sở dữ liệu và phân tích nó bằng cách sử dụng công cụ dạng bản thể luận. Bạn sẽ hoàn tất sự chuyển đổi bằng cách sử dụng bộ chuyển đổi XSLT.

Bảng định kiểu

Bảng định kiểu (Stylesheet) là một trang dùng để định dạng điển hình, nhưng sử dụng một cặp chức năng XPath để hoàn thành một vài tác vụ khó hơn (xem ví dụ 23):

Ví dụ 23. The stylesheet
<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>

Đầu tiên bảng định kiểu tạo thành phần chính RDF, hoạt động như là khởi nguồn của tài liệu. Từ đây, nó lặp lại thông qua từng thành phần Item và tạo ra các thành phần Author, Book, và StockItem. Khi cần thiết nó sử dụng hàm translate() để thay thế những khoảng trống trong tên tác giả bằng dấu gạch chân.

Lưu ý cách dùng của các chuỗi ký tự bằng chữ như là AMAZON_. Do sự chuyển đổi này là đặc tính của dịch vụ, bạn có thể thực hiện việc chuyển đổi mà không bị sao.

Tạo một ứng dụng thử nghiệm

Bây giờ bạn gần như sẵn sàng để bắt đầu sự chuyển đổi, nhưng do gần như không thể xem những gì xảy ra giữa các servlet, nên tạo ra một lớp kiểm tra để chạy sự chuyển đổi và chắc chắn nó hoạt động đúng cách (xem ví dụ 24).

Ví dụ 24. Tạo lớp thử nghiệm
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();
        }

   }
}

Đây chỉ là một lớp đơn giản, nhưng do bảng định kiểu cuối cùng sẽ bị tiếp cận như là một chuỗi (như là một đặc tính của lớp Service).

Xây dựng tài liệu gốc

Để bắt đầu sự chuyển đổi, tạo DOMSource bằng cách phân tích cú pháp các kết quả của yêu cầu thực (xem ví dụ 25):

Ví dụ 25. Xây dựng 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 đang được phân tích là URL được tạo ra bởi phương thức getRESTRequest() nhưng để mọi thứ hoạt động đúng đắn, bạn cần chắc chắn rằng DocumentBuilderFactory tạo một DocumentBuilder mà nhận ra các khoảng trống. Nếu không, chương trình phân tích sẽ không hiểu các thành phần bảng định kiểu nên được xử lý như là một bảng định kiểu.

Tạo bảng định kiểu

Bạn cần tạo một DOMSource cái mà đại diện cho bảng định kiểu (xem ví dụ 26):

Ví dụ 26. Tạo đối tượng bảng định kiểu
...
        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();
     }
}

Tất nhiên trong ứng dụng thực, bạn sẽ thay thế transString bằng xsltTransformationString từ Service.

Chuyển đổi tài liệu

Bây giờ bạn cần thực hiện sự chuyển đổi thực (xem ví dụ 27):

Ví dụ 27. Thực hiện chuyển đổi
...
        TransformerFactory transFactory = 
                          TransformerFactory.newInstance();
        Transformer transformer = 
                    transFactory.newTransformer(xslSource);

        StreamResult result = new StreamResult(System.out); transformer.transform(xmlSource, result);
        
     } 
     catch (Exception e){    
        e.printStackTrace();
     }
}

Bạn đang thiết lập kết quả là System.out do đó bạn sẽ thấy các cá thể của bản thể luận xuất hiện trong dòng lệnh, hoặc cửa sổ bảng điều khiển, như bạn thấy trong hình 3.

Hình 3. Kết quả của sự chuyển đổi
Kết quả của sự chuyển đổi

Hiển thị các kết quả

Cuối cùng bạn đã gần hoàn thành. Bạn có thể truy xuất thông tin dịch vụ từ bản thể luận, thiết lập yêu cầu, và chuyển đổi kết quả sang thông tin dạng bản thể luận. Bây giờ bạn chỉ phải trình bày thông tin loại dạng bản thể luận như là bộ phận của một ứng dụng.

Quy trình hiển thị hoạt động như thế nào

Đến đây có thể là lúc để rà soát xem quy trình hiển thị thực sự hoạt động thế nào. Mọi yêu cầu dịch vụ trả lại một khối lớn XML. Mục tiêu là để hiển thị các phần cụ thể của khối này trên một trang HTML. Có nghĩa rằng bạn sẽ kết hợp dữ liệu với các thẻ HTML.

Đối với mỗi dịch vụ, bạn xác định một mẫu, một chuỗi mã HTML bao gồm các trình giữ chỗ (placeholders) trong đó mà bạn có thể thả các dữ liệu thích hợp vào. Ví dụ, mẫu bạn đang sử dụng đối với dịch vụ Amazon là (xem ví dụ 28):

Ví dụ 28. Mẫu
<p><a value='href'><value/></a> by <value/></p>

Bạn thấy hai thành phần value và một thuộc tính value . Khi bạn xử lý dịch vụ, bạn sẽ thay thế các nút này bằng thông tin cụ thể từ dịch vụ. Ví dụ, bạn muốn thành phần value đầu tiên để đại diện cho tiêu đề, nên bạn sẽ thay thế nó bằng nút tìm được trong kết quả REST tại /ItemSearchResponse/Items/Item/ItemAttributes/Title. Bạn biết đó là dữ liệu bạn cần vì recordExp được thiết lập tới /ItemSearchResponse/Items/Item, hoạt động như nguồn gốc khởi đầu của trường hợp này, và là elementValue đầu tiên được thiết lập ItemAttributes/Title.

Để mọi thứ xảy ra với dữ liệu được chuyển đổi, bạn cần phải làm như sau:

  1. Thêm thông tin chuyển đổi vào bản thể luận, và cả dịch vụ.
  2. Tạo yêu cầu.
  3. Chuyển đổi yêu cầu thô sang thông tin dạng bản thể luận.
  4. Trích dẫn thông tin phù hợp từ thông tin dạng bản thể luận.
  5. Chèn các thông tin thu được vào mẫu.
  6. Hiển thị mẫu

Hãy bắt đầu bằng cách chắc chắn rằng thông tin dịch vụ trong bản thể luận là mới cập nhật.

Điều chỉnh đầu vào tổng quát

Điều đầu tiên bạn cần làm là thêm bảng định kiểu XSLT vào xsltTransformationString một cách đúng đắn, nhưng trước khi làm như vậy hãy cân nhắc thêm một khía cạnh.

Bản thể luận được xây dựng để phục vụ một mục đích cụ thể, và phục vụ tốt mục đích đó, nhưng nó không đưa chính nó vào biểu thức XPath. Vì mục đích của bài viết này - bạn không cần đưa hết tất cả các phần vào biểu thức XPath khó hiểu - tạo một sự thay đổi đối với bảng định kiểu để đơn giản hoá đầu ra. Bạn có một đầu ra mới trông như sau (xem ví dụ 29):

Ví dụ 29. Cấu trúc dữ liệu mới
<rdf:RDF xmlns:rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#">
   <Book>
       <itemDescription>Cesar's Way: The Natural, Everyday Guide to 
Understanding and Correcting Common Dog Problems</itemDescription>
       <Author>Cesar Millan</Author>
       <itemDetailURL>http://www.amazon.com/gp/redirect.html%3FASIN=030733
7332%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/030733733
2%253FSubscriptionId=000000000000000</itemDetailURL>
   </Book>
   <Book>
       <itemDescription>Marley amp; Me: Life and Love with the World's Worst 
Dog</itemDescription>
       <Author>John Grogan</Author>
       <itemDetailURL>http://www.amazon.com/gp/redirect.html%3FASIN=006081
7089%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/006081708
9%253FSubscriptionId=000000000000000</itemDetailURL>
   </Book>
   ...
</rdf:RDF>

To set that up, add the following stylesheet to the ontology (see Listing 30):

Listing 30. Adding the stylesheet to the ontology
...   
<Bookstore rdf:ID="Amazon.com">
    <endpoint>http://webservices.amazon.com/onca/xml</endpoint>
    <rootoutputnode>//Book</rootoutputnode> 
    <inputparameter rdf:resource="#amazonInput1"/>
    <inputparameter rdf:resource="#amazonInput2"/>
    <inputparameter rdf:resource="#amazonInput3"/>
    <inputparameter rdf:resource="#amazonInput4"/> 
    <inputparameter rdf:resource="#amazonInput5"/> 
    <xsltTransformationString>
       <![CDATA[
            <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="Book">
                  <itemDescription><xsl:value-of select=
                               "res:ItemAttributes/res:Title"/>
                  </itemDescription>
                  <Author><xsl:value-of select=
                         "res:ItemAttributes/res:Author"/></Author>
                 <itemDetailURL><xsl:value-of select=
                         "res:DetailPageURL"/></itemDetailURL>
               </xsl:element>
            </xsl:template>
            </xsl:stylesheet>
         ]]>
    </xsltTransformationString>


    <template><![CDATA[ <p><a value='href'><value/></a> 
by <value/></p> ]]></template>
    <elementValue>ItemAttributes/Title!ItemAttributes/Author</elementValue>
    <attributeValue>DetailPageURL</attributeValue>
    <queryParameter>Title</queryParameter>
</Bookstore>
<ServiceParameterMap rdf:ID="amazonInput1">
    <paramname>Service</paramname>
    <paramvalue>AWSECommerceService</paramvalue>
</ServiceParameterMap>
...

Để thiết lập cấu trúc đó, thêm bảng định kiểu sau vào bản thể luận (xem ví dụ 30):

Ví dụ 30. Thêm bảng định kiểu vào bản thể luận
...   
<Bookstore rdf:ID="Amazon.com">
    <endpoint>http://webservices.amazon.com/onca/xml</endpoint>
    <rootoutputnode>//Book</rootoutputnode> 
    <inputparameter rdf:resource="#amazonInput1"/>
    <inputparameter rdf:resource="#amazonInput2"/>
    <inputparameter rdf:resource="#amazonInput3"/>
    <inputparameter rdf:resource="#amazonInput4"/> 
    <inputparameter rdf:resource="#amazonInput5"/> 
    <xsltTransformationString>
       <![CDATA[
            <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="Book">
                  <itemDescription><xsl:value-of select=
                               "res:ItemAttributes/res:Title"/>
                  </itemDescription>
                  <Author><xsl:value-of select=
                         "res:ItemAttributes/res:Author"/></Author>
                 <itemDetailURL><xsl:value-of select=
                         "res:DetailPageURL"/></itemDetailURL>
               </xsl:element>
            </xsl:template>
            </xsl:stylesheet>
         ]]>
    </xsltTransformationString>


    <template><![CDATA[ <p><a value='href'><value/></a> 
by <value/></p> ]]></template>
    <elementValue>ItemAttributes/Title!ItemAttributes/Author</elementValue>
    <attributeValue>DetailPageURL</attributeValue>
    <queryParameter>Title</queryParameter>
</Bookstore>
<ServiceParameterMap rdf:ID="amazonInput1">
    <paramname>Service</paramname>
    <paramvalue>AWSECommerceService</paramvalue>
</ServiceParameterMap>
...

Bây giờ bạn đã sẵn sàng thực hiện chuyển đổi trên phản hồi dịch vụ.

Chuyển đổi kết quả dịch vụ cụ thể

Sự chuyển đổi dữ liệu thô sang dữ liệu có ý nghĩa nên trong suốt; nó xảy ra như một phần của quy trình tổng thể của dịch vụ (xem ví dụ 31):

Ví dụ 31. Chuyển đổi phản hồi
...
public class MashupClientServlet extends javax.servlet.http.HttpServlet implements
 javax.servlet.Servlet {
...
    public static Document getData (String query, Service svc) {

        try {
            DocumentBuilderFactory factory = 
                   DocumentBuilderFactory.newInstance();
            factory.setNamespaceAware(true);
            
            DocumentBuilder builder = factory.newDocumentBuilder();

            String cached = checkCache(query);
            Document document = null;

            if (cached.equals("-1")){
                //Using fresh data
                Document inputDocument = builder.parse(query);

                try {
                    Source xmlSource = new DOMSource(inputDocument);
                    Document xslDoc = builder.parse(
                     new InputSource(new 
                       StringReader(svc.xsltTransformationString)));
                    DOMSource xslSource = new DOMSource(xslDoc);
                    TransformerFactory transFactory = 
                                      TransformerFactory.newInstance();
                    Transformer transformer = 
                                transFactory.newTransformer(xslSource);

                    DOMResult result = new DOMResult();
                    transformer.transform(xmlSource, result); 
                    
                    document = (Document)result.getNode();
                    
                 } 
                 catch (Exception e){    
                    e.printStackTrace();
                 }
                
        
                saveData(query, document);
            } else{
                //Using cached data, I hope
                Document cachedDocument;
...
    }

    public static Node renderService(String query, Service svc, 
                                               Document hostDoc){

        Document document = getData(query, svc);

        if (document != null){

...
    }

    protected void doPost(HttpServletRequest request, 
                     HttpServletResponse response) 
                        throws ServletException, IOException {

        MashupOntologyReader ont = new MashupOntologyReader();
        
        String query = request.getParameter("query").toString();
        String serviceURI = 
                   request.getParameter("serviceURI").toString();
        Service service = ont.obtainServiceInfo(serviceURI);
        
        try {
            DocumentBuilder builder = 
             DocumentBuilderFactory.newInstance().newDocumentBuilder();

            Service[] svcs = {service};
            
            Document hostDoc = builder.parse(
                     new InputSource(new StringReader("<results/>")));
            Node hostRoot = hostDoc.getDocumentElement();

            for (int k=0; k < svcs.length; k++){


                Service svc = svcs[k];
                Node renderedService = renderService(
                     svc.getRESTRequest(ont)+query, svc, hostDoc);

                if (renderedService != null){

                    Element nameElement = hostDoc.createElement("h1");
                    nameElement.appendChild(
                                 hostDoc.createTextNode(svc.name));
...

Mã này chỉ ra một số thay đổi, do vậy hãy bắt đầu từ cuối và làm ngược trở lại. Đầu tiên, do thông tin cần thiết cho việc chuyển đổi là một phần của Service, bạn cần phải chuyển nó như là một phần của lời gọi đến hàm renderService(). Có nghĩa bạn cần phải bổ sung nó vào chữ ký renderService(). Khi nó đã ở đấy, bạn có thể chuyển nó tới phương thức getData() nơi mà bạn thực sự cần nó.

Trong phương thức getData(), đầu tiên bạn tạo ra DocumentBuilder (lại như trong namespace-aware). Từ đó, bạn sử dụng nó để tạo ra nguồn DOMSource, lần này sử dụng Document được tạo ra khi bạn phân tách các truy vấn. Từ đó, tất cả sẽ được tiếp tục như trước đây ngoại trừ rằng bảng định kiểu đến từ Service.

Sau khi có kết quả, bạn có thể lấy lại DOM Document từ nó sử dụng phương thức getNode(). Khi bạn có nó, bạn có thể tiếp tục như trước đây, lưu dữ liệu vào cơ sở dữ liệu và chuyển nó quay lại ứng dụng chính như thể chưa có gì xảy ra với nó.

Điều chỉnh các tham số dịch vụ

Nếu hiện giờ bạn chạy servlet, tuy nhiên, bạn sẽ thấy có vẻ không thu được kết quả gì. Tại sao? Do tại thời điểm hiện nay servlet đang cố gắng nhúng vào dữ liệu từ /ItemSearchResponse/Items/Item/ItemAttributes/Title và những cái tương tự vào mẫu, nhưng dữ liệu này không còn tồn tại bởi vì bạn đã chuyển hóa nó vào một dạng thức mới. Vì vậy để có thể thực hiện, bạn cần điều chỉnh các biểu thức XPath (xem ví dụ 32):

Ví dụ 32. Điều chỉnh các biểu thức XPath
...
<Bookstore rdf:ID="Amazon.com">
    <endpoint>http://webservices.amazon.com/onca/xml</endpoint>
    <rootoutputnode>//Book</rootoutputnode> 
    <inputparameter rdf:resource="#amazonInput1"/>
    <inputparameter rdf:resource="#amazonInput2"/>
    <inputparameter rdf:resource="#amazonInput3"/>
    <inputparameter rdf:resource="#amazonInput4"/> 
    <inputparameter rdf:resource="#amazonInput5"/> 
...
    <xsltTransformationString>
       <![CDATA[
...
         ]]>
    </xsltTransformationString>


      <template><![CDATA[ <p><a 
value='href'><value/></a> by <value/></p> 
]]></template>
      <elementValue>itemDescription!Author</elementValue>
      <attributeValue>itemDetailURL</attributeValue>
      <queryParameter>Title</queryParameter>
</Bookstore>
...

Giờ thì bạn tìm kiếm dữ liệu kiểu như //Book/itemDescription tồn tại trong kiểu dạng dữ liệu đã chuyển hóa, do đó mọi thứ có vẻ trông hoàn chỉnh.

Kết quả cuối cùng trông giống hình 4:

Hình 4. Kết quả cuối cùng
Kết quả cuối cùng

Tổng kết

Và từ đây bạn sẽ đi tới đâu

Mục đích của bài viết này là điều chỉnh ứng dụng để người dùng có thể lựa chọn loại dịch vụ mà họ muốn và trong một khoảng thời gian nhất định có thể hoàn thành được việc này. Bạn có thể tạo nên một số lượng bất kỳ các hiệu sách dựa trên REST cho người sử dụng bằng cách đơn giản là thêm vào các thông tin của chúng trong tệp bản thể luận. Bạn cũng có thể mở rộng dịch vụ này thành các loại dịch vụ khác tệp. Tất cả cần làm là chỉ bổ sung chúng vào bản thể luận và thay đổi kiểu mà bạn đang tìm kiếm khi bạn tạo nên mẫu.

Chúng ta chưa thảo luận về các dịch vụ phụ trong bài viết này, bởi vì vấn đề là không còn đủ chỗ nữa. Các dịch vụ phụ hoạt động như trước đây. Chúng ta vẫn chưa đề cập gì về tìm kiếm các thông tin ngôn ngữ đã được phát triển trước đây. Bạn có thể lấy mã trong bài viết này và sử dụng chúng để tìm kiếm, như là các quyển sách giá thấp nhất trong cơ sở dữ liệu, độc lập với dịch vụ ở chỗ là dữ liệu được lấy lại, sử dụng cùng các công nghệ như nhau mà bạn đã học ở Phần 2

Trong bài bài viết này, bạn đã tạo cho người dùng cơ hội lựa chọn từ một số lượng hạn chế các dịch vụ xác định của một kiểu nhất định tùy chọn, lấy lại các dữ liệu thô và trả nó lại dữ liệu bản thể luận đánh dấu dưới hình thức ngôn ngữ. Ở Phần 6 bạn sẽ học cách làm thế nào để tạo cho người dùng lựa chọn loại dịch vụ nào được sử dụng và loại dữ liệu nào được trình bày cũng như là làm thế nào để trình diễn dữ liệu trên trang web.


Tải về

Mô tảTênKích thước
Mã nguồn Phần 5x-ultimashup5-source.zip27KB

Tài nguyên

Học tập

Lấy sản phẩm và công nghệ

Thảo luận

  • Các diễn đàn developerWorks XML: Liên lạc với các nhà phát triển XML khác để giải quyết những vấn đề giống nhau mà bạn đang mắc phải
  • developerWorks blogs: Tham gia vào cộng đồng liên quan đến công việc phát triển (developerWorks).

Bình luận

developerWorks: Đăng nhập

Các trường được đánh dấu hoa thị là bắt buộc (*).


Bạn cần một ID của IBM?
Bạn quên định danh?


Bạn quên mật khẩu?
Đổi mật khẩu

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Ở lần bạn đăng nhập đầu tiên vào trang developerWorks, một hồ sơ cá nhân của bạn được tạo ra. Thông tin trong bản hồ sơ này (tên bạn, nước/vùng lãnh thổ, và tên cơ quan) sẽ được trưng ra cho mọi người và sẽ đi cùng các nội dung mà bạn đăng, trừ khi bạn chọn việc ẩn tên cơ quan của bạn. Bạn có thể cập nhật tài khoản trên trang IBM bất cứ khi nào.

Thông tin gửi đi được đảm bảo an toàn.

Chọn tên hiển thị của bạn



Lần đầu tiên bạn đăng nhập vào trang developerWorks, một bản trích ngang được tạo ra cho bạn, bạn cần phải chọn một tên để hiển thị. Tên hiển thị của bạn sẽ đi kèm theo các nội dung mà bạn đăng tải trên developerWorks.

Tên hiển thị cần có từ 3 đến 30 ký tự. Tên xuất hiện của bạn phải là duy nhất trên trang Cộng đồng developerWorks và vì lí do an ninh nó không phải là địa chỉ email của bạn.

Các trường được đánh dấu hoa thị là bắt buộc (*).

(Tên hiển thị cần có từ 3 đến 30 ký tự)

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Thông tin gửi đi được đảm bảo an toàn.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=70
Zone=Information Management, Công nghệ Java, Nguồn mở, SOA và dịch vụ Web
ArticleID=391019
ArticleTitle=Ultimate mashup – Các dịch vụ Web và Web ngữ nghĩa, Phần 5: Thay đổi các dịch vụ Web
publish-date=03082007