Ultimate mashup – Các dịch vụ Web và Web ngữ nghĩa (semantic Web), Phần 6: Cho người dùng quyền kiểm soát

Sử dụng các kỹ thuật ngữ nghĩa để người dùng mashup có thể kiểm soát được dịch vụ, thông tin và cách trình bày.

Đây là bài viết cuối cùng trong một loạt các bài viết để chỉ cho bạn cách tạo một ứng dụng mashup. Ở đây, bạn cần có một ứng dụng đang chạy và một khung làm việc thay thế nhờ đó hệ thống có thể sử dụng các lập luận ngữ nghĩa để hiểu các dịch vụ tại điểm sử dụng của nó. Trong bài viết này, bạn sẽ để cho người dùng kiểm soát việc chọn lựa loại hình dịch vụ, dữ liệu lấy về từ dịch vụ Web, và cách trình bày dữ liệu đó.

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

Bài viết này dành cho các nhà phát triển muốn học thêm về cách dùng kỹ thuật ngữ nghĩa và ứng dụng ngữ nghĩa. Đặc biệt, bài viết chỉ cho bạn cách sử dụng kỹ thuật Web ngữ nghĩa để lấy dữ liệu từ một dịch vụ web bất kỳ và trình bày chúng dưới dạng người dùng tự chọn.

Khi tham dự bài viết này bạn chắc chắn phải có kiến thức kỹ càng về lập trình Java. Bạn cũng cần hiểu nhiều về khái niệm XML và khung làm việc mô tả tài nguyên (Resource Description Framework - RDF) nói chung cũng như biết kỹ về ngôn ngữ Web bản thể (Web Ontology Language - OWL) nói riêng. Nếu bạn cần tìm hiểu lại ba chủ đề này hãy đọc phần 34 trong loạt hướng dẫn này.

Về loạt bài viết

Dường như bạn không thể vào Web mà không vào một trang Web hoặc là cung cấp cho bạn quyền truy cập dữ liệu của nó thông qua một dịch vụ Web có gốc API hoặc là sử dụng dữ liệu từ trang web khác lấy từ một dịch vụ Web có gốc API. Khi bạn xem xét lợi thế của việc sử dụng các thông tin sẵn có trong ứng dụng của riêng bạn thì điều đó không hề gây ngạc nhiên. Đây chỉ là vấn đề thời gian trước khi ai đó bắt đầu kết hợp dữ liệu từ các hệ thống khác nhau để tạo ra một thứ hoàn toàn mới. Những ứng dụng này được gọi là mashups là hiện tượng thịnh hành nhất trên Web, từ các trang giao tiếp thông thường đến các trang tìm kiếm đặc biệt tới chiến lược mashup từng xuất hiện.

Hầu hết các mashup rất hữu ích, nhưng chúng có một đặc điểm chung là chúng được tạo ra cho một loạt các dịch vụ riêng biệt, và nếu một trong các dịch vụ đó thay đổi hoặc dịch vụ riêng biệt của một loại hình cụ thể nào đó thay đổi thì bạn sẽ có nhiều việc phải làm với nó.

Mục đích của loạt bài viết này nhằm tạo ra một ứng dụng mashup tốt đến mức mà người dùng có thể thêm hoặc bớt các dịch vụ nếu muốn, và hệ thống sẽ biết cách giải quyết vấn đề này. Các chuỗi tiến trình diễn ra như sau:

Phần 1: Giới thiệu khái niệm mashups, trình bày cách ứng dụng hoạt động và xây dựng một phiên bản đơn giản nhất của một mashup. Những sự cố trình bày nghiêm trọng liên quan tới việc tạo ra hàng loạt các cuộc gọi trên Web cũng sẽ được chỉ ra.

Phần 2: Giải quyết một số sự cố khi sử dụng pureXML™ của IBM® DB2 ® để xây dựng bộ nhớ lưu trữ XML để lưu giữ kết quả của các yêu cầu trước đó và để cho phép bạn truy lục thông tin cụ thể.

Ở cấp độ cơ bản nhất, bạn sẽ cần phải dùng bản thể luận và các từ vựng để định nghĩa các khái niệm và mỗi quan hệ giữa chúng vì thế ở Phần 3 bạn bắt đầu tiến trình này bằng cách tìm hiểu về RDF và RDFs, đó là hai thành phần chính của ngôn ngữ web bản thể (OWL), được mô tả trong Phần 4. Phần 5 Lấy các bản thể luận bạn tạo được ở phần 4 và sử dụng nó để cho phép người dùng thay đổi nguồn gốc thông tin.

Và bài viết này rất hấp dẫn đối với bạn. Ở đây, bạn có một ứng dụng đang chạy và một khung làm việc để hệ thống có thể sử dụng lập luận ngữ nghĩa để hiểu các dịch vụ tại điểm sử dụng của nó. Trong bài viết này, bạn cung cấp cho người dùng quyền kiểm soát, cho phép người dùng lựa chọn dịch vụ trong bản thể luận và chọn ra các dữ liệu để dùng cho một mashup thông thường.

Về bài viết này

Bài viết này là phần 6 trong loạt bài viết giải thích cách thêm các khả năng ngữ nghĩa cho ứng dụng mashup các dịch vụ Web. Ở phần 5 (xem Tài nguyên bạn lấy một cây thư mục đã có và bổ sung nó để cho phép người dùng dễ dàng thay đổi dịch vụ. Trong bài viết này bạn sẽ dùng các kỹ năng ngữ nghĩa để cung cấp cho người dùng quyền kiểm soát hoàn toàn đối với các thông tin được hiển thị và đối với cách trình bày của nó.

Ở bài viết này bạn sẽ học cách

  • Gọi một reasoner trên dữ liệu ngữ nghĩa
  • Định rõ các lớp và lớp con theo lập trình
  • Định rõ các đặc tính sẵn có của lớp theo lập trình
  • Định rõ các giá trị đặc tính cố định theo lập trình
  • Xây dựng một ứng dụng có thể lấy được thông tin dựa trên ngữ nghĩa chứ không dựa trên các biểu thức XPath.

Trong bài viết này, bạn sẽ lấy mashup bạn tạo được từ phần 1 đến phần 5 và cho người dùng quyền kiểm soát tối ưu. Người dùng sẽ có khả năng chọn một loại dịch vụ, một dịch vụ Web cố định để dùng, dữ liệu lấy từ dịch vụ Web, và sự trình bày các dữ liệu đó. Cuối cùng, bạn có thể thêm hàm mới và các dịch vụ mới vào ứng dụng bằng cách đơn giản là thêm chúng vào bản thể luận mà không phải chạm tới ứng dụng đó.

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

Bạn cần phải cài đặt và kiểm tra các phần mềm sau đây nhằm tuân theo mã trong bài viết này

  • IBM® DB2® 9 (trước đây gọi là “Viper”) Cơ sở dữ liệu liên quan này bao gồm khả năng XML mà bạn sẽ cần cho bài viết này. Bạn có thể tải về phiên bản thử nghiệm DB2 9: DB2 Enterprise 9 hoặc DB2 Express-C 9 phiên bản dữ liệu máy chủ DB2 Express 9 miễn phí.
  • Apache Tomcat Hay dụng cụ servlet khác: bài viết này cho rằng bạn sẽ dùng các servlet để xây dựng các ứng dụng Web, vì thế bạn sẽ cần có dụng cụ servlet như là Apache Tomcat. Nếu bạn chọn cách xây dựng ứng dụng sử dụng môi trường khác thì hãy đảm bảo chắc chắn rằng bạn có phần mềm thích hợp trong tay. Tải phần mềm apache-tomcat-5.5.17.zip và cài đặt nó vào trong một thư mực (không để dấu cách khi viết tên thư mục).
  • Java: bài viết này được xây dựng cùng Apache Tomcat 5.5, cần có Java 1.5 hoặc các phiên bản mới hơn. Tải phần mềm J2SE SDK.
  • Để tiến hành công việc thuận lợi hơn bạn có thể sử dụng một IDE như Eclipse hoặc Rational IBM™ Web Developer cho việc khai thác của bạn. Bạn có thể tải Eclipse tại Eclipse.org, tải phiên bản thử nghiệm của Rational Web Developer hoặc dùng môi trường khai thác thông dụng của bạn. Bạn sẽ không thể làm được gì thú vị trừ khi việc đó liên quan tới tài liệu thu thập và sự triển khai của mình.

Tổng quan

Cho đến nay rất nhiều điều đã xảy ra trong loạt bài viết. Khi bạn đến điểm tột cùng của đề án này bạn cần đảm bảo rằng bạn hiểu vị trí của mình trước khi bạn bắt đầu để thêm vào những tính năng tiên tiến cuối cùng cho chương trình ứng dụng của mình.

Mục đích của loạt bài viết này

Từ khởi đầu của loạt bài viết này, ý tưởng tạo ra một mashup ngữ nghĩa hoặc một ứng dụng Web để lấy thông tin từ các nguồn khác nhau được đưa ra. Ngày nay, mashups đã khá thông dụng. Vào thời điểm viết loạt bài này, Mashupfeed.com đã có danh sách 994 mashups tồn tại và có thêm 2,7 mashups được đưa vào sử dụng mỗi ngày. Nhưng mỗi một mashup đều không thay đổi loại hình thông tin chúng trình bày. Và do đó, người dùng phải chọn một truy vấn để thực hiện, nhưng nguồn dữ liệu và sự trình bày của nó là cố định. Ứng dụng sử dụng một dịch vụ đơn hoặc một loạt các dịch vụ và người dùng sẽ không kiểm soát được điều xảy ra khi chọn một truy vấn.

Mục đích của loạt bài viết này là tạo ra một chút khác biệt. Ứng dụng bạn đang xây dựng cuối cùng sẽ mang lại cho người dùng quyền kiểm soát đối với dịch vụ, với dữ liệu lấy được và cách trình bày các dữ liệu đó. Nhưng trước khi bước vào nội dung chi tiết, chúng ta nên xem chúng ta đã đạt được những gì trong hành trình này

Các bài viết trước

Ở phần một của loạt bài viết, bạn xây dựng một ứng dụng mashup cơ bản dùng để lấy dữ liệu từ các dịch vụ bất kỳ được xác định tại một lớp Java riêng biệt. Dữ liệu mà các dịch vụ này trình bày và hình thức trình bày được điều khiển bởi khuôn mẫu XML lưu giữ như một đặc tính của lớp dịch vụ. Để thêm một dịch vụ mới, bạn cần thêm một định nghĩa dịch vụ mới và mọi thứ được tiến hành tự động

Sự điều biến này thực sự có chủ ý. Nó cho phép bạn tạo ra một tình huống mà ở đó người dùng có thể chuyển đổi các dịch vụ theo tác động. Hàm của ứng dụng có thể thay đổi bằng cách thay đổi các nội dung của Service

Ở phần 2 bạn đã thực hiện các vấn đề về trình bày bằng việc tạo ra một tình huống trong đó dữ liệu trước hết được lấy ra từ cơ sở dữ liệu, và nếu dữ liệu này không tồn tại bạn sẽ phát một truy vấn và dữ liệu sẽ được bổ sung vào cơ sở dữ liệu. Sau đó ở phần 3, và 4 bạn học về khung làm việc mô tả tài nguyên, một chi nhánh của nó, ngôn ngữ Web bản thể (OWL).

Ở phần 5, mọi thứ nhập lại với nhau, bạn cung cấp thêm khả năng thay đổi dịch vụ cho người dùng. Nói cách khác, nếu người dùng muốn xem kết quả từ BarnesandNoble.com thay vì xem từ Amazon.com, người dùng phải chọn dịch vụ đó như một lựa chọn và hệ thống sẽ hiểu cách tìm một giá trị Amazon tương đương với cách tìm một giá trị Barnes & giá trị Noble bởi vì cả hai bộ dữ liệu đều được mã hóa trong một bản thể luận thông thường.

Trong bài viết này bạn sẽ hiểu dần từng khái niệm này.

Các bước tiếp theo

Bây giờ là lúc tạo ra một ứng dụng mà ở đó người dùng có thể đưa ra các quyết định của mình. Bạn không phải khởi động ứng dụng và ngay lập tức đưa ra một hộp tìm kiếm để bạn nhập truy vấn của mình. Đầu tiên bạn phải chọn loại hình dịch vụ như là Bookstore, MappingService, và những dịch vụ tương tự trước khi bạn được thấy một danh mục lựa chọn các dịch vụ.

Khi bạn đã lựa chọn dịch vụ bạn sẽ được thấy một danh mục tất cả thông tin mà bạn có thể lấy từ dịch vụ đó. Bạn sẽ có cơ hội tạo một khuôn mẫu bằng tay hoặc một chuỗi ký tự XML/XHTML có chỗ lưu các dữ liệu hiện thời.

Từ đây bạn có thể phát một truy vấn và yêu cầu dữ liệu hiện lên theo cách bạn vừa yêu cầu.

Bản thể luận

Hãy bắt đầu bằng việc nhớ lại các phần liên quan của bản thể luận mà bạn sẽ sử dụng cho dự án này. (Xem ví dụ 1).

Ví dụ 1. Bản thể luận
<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>

<!-- SERVICE DEFINITIONS -->
  
<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="#rootoutputnode" />
       <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>

<!-- SUBCLASSES OF SERVICE -->

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

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

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

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

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

<!-- BOOKSTORE RELATED CLASSES -->

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

<owl:Class rdf:ID="StockItem">
</owl:Class>
<owl:DatatypeProperty rdf:ID="itemPrice">
  <rdfs:label>Item Price</rdfs:label> 
  <rdfs:domain rdf:resource="#StockItem"/>
  <rdfs:range rdf:resource="&xsd;double"/> 
</owl:DatatypeProperty>
<owl:DatatypeProperty rdf:ID="itemDescription"> 
  <rdfs:label>Item Description</rdfs:label> 
  <rdfs:domain rdf:resource="#StockItem"/>
  <rdfs:range rdf:resource="&xsd;string"/> 
</owl:DatatypeProperty>
<owl:DatatypeProperty rdf:ID="itemDetailURL"> 
  <rdfs:label>Item Detail Page URL</rdfs:label> 
  <rdfs:domain rdf:resource="#StockItem"/>
  <rdfs:range rdf:resource="&xsd;string"/> 
</owl:DatatypeProperty>
<owl:ObjectProperty  rdf:ID="stockedProduct">
   <rdfs:label>Stocked Product</rdfs:label> 
   <rdfs:domain rdf:resource="#StockItem"/>
   <rdfs:range rdf:resource="#Book"/>
</owl:ObjectProperty>

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

<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:label>Title</rdfs:label> 
  <rdfs:domain rdf:resource="#Book"/>
  <rdfs:range rdf:resource="&xsd;string"/> 
</owl:DatatypeProperty>

...
<owl:ObjectProperty rdf:ID="writtenBy">
  <rdfs:label>Written By</rdfs:label>
  <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>

<!-- INSTANCES -->

<Bookstore rdf:ID="Amazon.com">
   <endpoint>http://localhost/xml.xml</endpoint><!-- 
http://webservices.amazon.com/onca/xml</endpoint> -->
   <rootoutputnode>//Book</rootoutputnode> 
   <outputType>http://example.com/store#StockItem</outputType>
   <inputparameter rdf:resource="#amazonInput1"/>
   <inputparameter rdf:resource="#amazonInput2"/>
   <inputparameter rdf:resource="#amazonInput3"/>
   <inputparameter rdf:resource="#amazonInput4"/> 
   <xsltTransformationString>

      <![CDATA[
...
         ]]>
   </xsltTransformationString> 
   <template><![CDATA[ <p><a 
value='href'><value/></a> by <value/></p> 
]]></template>
    <elementValue>Author!itemDescription</elementValue>
    <attributeValue>itemDetailURL</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>Title</paramname>
   <paramvalue></paramvalue>
</ServiceParameterMap>
<ServiceParameterMap rdf:ID="amazonInput4">
   <paramname>Operation</paramname>
   <paramvalue>ItemSearch</paramvalue>
</ServiceParameterMap>

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

</rdf:RDF>

Lưu ý là dữ liệu được cung cấp cho thể hiện Amazon.com của lớp Bookstore, nhưng không phải cho Barnesandnoble.com hay Buy.com hay các mục trong bản thể luận của Buy.com. Bởi vì đây là một ví dụ, và cũng có thể là một chứng minh về khái niệm. Trong một ứng dụng thực, hiển nhiên là bạn sẽ có sẵn thông tin này hoặc là bạn sẽ nhận được báo lỗi như là NullPointerException nếu người dùng chọn chúng. Và trong một ứng dụng thực bạn sẽ muốn bắt những loại lỗi này.

Cũng cần lưu ý rằng đặc tính outputType rất phổ biến với URI cho lớp StockItem, vì thế ứng dụng biết nó cần xem xét điều gì.

Chuyển đổi dữ liệu thô sang dữ liệu bản thể luận

Trước khi tiếp tục bạn cần lưu ý một điểm. Ở phần 5 của loạt bài này (Xem mục Tài nguyên bạn đã nhìn thấy việc tạo ra một chuyển đổi căn bản là chuyển dữ liệu Amazon.com sang dữ liệu Property của riêng bạn và sau đó bằng một biến đổi đơn giản làm cho biểu thức cần có XPath có thể quản lý được. Bài viết này cũng sẽ nói rõ tại sao bạn sẽ không dùng XPath để phân tích các dữ liệu trả về, bạn sẽ cần chuyển dữ liệu sang dạng bản thể luận hiện thời.

Và cũng vì đặc tính của cách mà bộ xử lý dùng trong bài viết này tương tác, bạn cần chuyển đổi dữ liệu sang dạng bản thể luận theo cách rất đặc biệt. Bạn cần đảm bảo rằng bản thể luận sẽ cụ thể hóa chuỗi chuyển đổi như sau. (Xem ví dụ 2):

Ví dụ 2. Chuỗi chuyển đổi
...
<Bookstore rdf:ID="Amazon.com">
   <endpoint>http://localhost/xml.xml</endpoint><!-- 
http://webservices.amazon.com/onca/xml</endpoint> -->
   <rootoutputnode>//Book</rootoutputnode> 
   <outputType>http://example.com/store#StockItem</outputType>
   <inputparameter rdf:resource="#amazonInput1"/>
   <inputparameter rdf:resource="#amazonInput2"/>
   <inputparameter rdf:resource="#amazonInput3"/>
   <inputparameter rdf:resource="#amazonInput4"/> 
   <xsltTransformationString>

      <![CDATA[
      <xsl:stylesheet version="1.0" xmlns="" 
xmlns:store="http://example.com/store#" 
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="store:Author">
               <xsl:attribute name="rdf:ID">_<xsl:value-of 
select="res:ASIN"/><xsl:value-of 
select="translate(res:ItemAttributes/res:Author, ' ', '_' 
)"/></xsl:attribute>
            </xsl:element>
            <xsl:element name="store:Book">
               <xsl:attribute name="rdf:ID">_<xsl:value-of 
select="res:ASIN"/></xsl:attribute>
               <xsl:element name="store: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="store:StockItem">
               <xsl:attribute name="rdf:ID">AMAZON_<xsl:value-of 
select="res:ASIN"/></xsl:attribute>
               <xsl:element name="store:stockedProduct">
                  <xsl:attribute name="rdf:resource">#_<xsl:value-of 
select="res:ASIN"/></xsl:attribute>
               </xsl:element>
               <xsl:element name="store:itemPrice">
                  <xsl:attribute 
name="rdf:datatype">http://www.w3.org/2001/XMLSchema#double</xsl:attribute
><xsl:value-of 
select="translate(res:ItemAttributes/res:ListPrice/res:FormattedPrice, '$', 
'')"/>
               </xsl:element>
               <xsl:element name="store:itemDetailURL">
                  <xsl:value-of select="res:DetailPageURL"/>
               </xsl:element>
               <xsl:element name="store:itemDescription">
                  <xsl:value-of select="res:ItemAttributes/res:Title"/>
               </xsl:element>
            </xsl:element>
         </xsl:template>
      </xsl:stylesheet>

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

Ở đây trong ví dụ 2 này một lần nữa bạn cần tạo ra các đối tượng trong http://example.com/store# nhưng bạn sẽ thấy nó hiện ra cụ thể.

Một số chú ý về chuyển đổi dữ liệu

Trong loạt bài này, bạn lấy dữ liệu thô và chuyển đổi nó sang dạng XML sao cho hòa hợp với một bản thể luận cụ thể. Có thể bạn sẽ tự hỏi “Tại sao không đơn giản là để cho reasoner tự làm ra mà không cần phải chuyển đổi dữ liệu?”. (reasoner là một dịch vụ lấy các phát biểu có trong một bản thể luận và từ đó suy luận ra các phát biểu mới.) Ví như bạn có thể báo cho bản thể luận biết rằng phần tử FormattedPrice ở trong trang http://webservices.amazon.com/AWSECommerceService/2005-10-05 không gian tên là một equivalentProperty đối với itemPrice. Bạn có thể dùng một reasoner để lấy dữ liệu từ kết quả thô hơn là trình bày một quá trình chuyển đổi.

Câu trả lời là không có lý do gì mà bạn không thực hiện được điều này. Nhưng sự thật là ngày nay reasoner Web ngữ nghĩa hơi giậm giật, và cách thức này sẽ thay đổi trọng tâm của bài viết này sang cách xây dựng bản thể luận chứ không phải xây dựng các ứng dụng Web. Vì thế, chúng ta cần nhớ là chúng ta có quyền lựa chọn, trong tương lai đó có thể sẽ là lựa chọn tốt cho bạn. Nhưng bây giờ, bạn sẽ làm mọi thứ đơn giản hơn bằng trình bày việc chuyển đổi dữ liệu.


Cải tiến cấu trúc

Trước khi bạn đi sâu hơn, bạn cần phải thay đổi cấu trúc để phù hợp với hàm mới.

Thêm kiểu đầu ra

Trước khi bắt đầu, xem lại một số điều liên quan tới bản thể luận. Từ vị trí của bản thể luận bây giờ, các lớp tương ứng sẽ như dưới đây. Trong trường hợp dịch vụ Bookstore là một lớp con của lớp Service trả lại một hoặc nhiều StockItems thì lớp StockItem có nhiều đặc tính như là itemPricestockedProduct. Nhưng một loại dịch vụ khác NewsService chẳng hạn có thể cho ra một loại mục khác (ví dụ, StockItem) thay vì cho ra một StockItems thì có thể cho ra một hoặc nhiều mục NewsStory. Vì thế, để hệ thống làm việc hợp lý, bản thể luận cần phải biết rõ từng lớp đại diện cho các mục riêng rẽ khi hiển thị câu trả lời cho dịch vụ. Để làm được điều này, bạn cần định nghĩa đặc tính outputType cho dịch vụ (Xem ví dụ 3).

Ví dụ 3. Thêm outputType
...
<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="outputType">
   <rdfs:domain rdf:resource="#Service"/>
   <rdfs:range rdf:resource="&owl;Class"/>
</owl:ObjectProperty>

<owl:ObjectProperty  rdf:ID="inputparameter">
   <rdfs:domain rdf:resource="#Service"/>
   <rdfs:range rdf:resource="#ServiceParameterMap"/>
</owl:ObjectProperty>
...

Lưu ý rằng đặc tính này chứa giá trị của nó ở bất kỳ Class nào. Ví dụ ở Bookstore giá trị của đặc tính này nằm ở StockItem. Dạng này là một dạng phức (các lớp là các giá trị và các biểu mẫu) gây khó khăn cho việc soạn thảo một reasoner OWL.

Tạo đặc tính sẵn có

Để sử dụng được đặc tính outputType bạn cần phải truy cập được nó. Vị trí hợp lý nhất nằm ở phương thức obtainServiceInfo() phương thức của MashupOntologyReader để đọc thông tin đưa vào lớp Service (xem ví dụ 4).

Ví dụ 4. Tạo đặc tính sẵn có
...
    public Service obtainServiceInfo(String serviceURI){
...
            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("outputType")){
                    l = s.getLiteral();
                    svc.recordExp=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() );                    
                }
...

    public static void main(String[] args) {

      MashupOntologyReader reader = new MashupOntologyReader();
      reader.obtainServiceInfo(
                        "http://example.com/store#Amazon.com");
    }

}

Trong trường hợp này (xem ví dụ 4) đơn giản là bạn cần xử lý đặc tính outputType tương tự cách bạn xử lý các đặc tính theo chuỗi khác, bạn truy cập vào Literal qua từng câu lệnh có chứa nó.

Bạn có thể nhìn thấy kết quả của việc thực thi phương thức obtainServiceInfo() (xem ví dụ 5).

Ví dụ 5. Thực thi phương thức obtainServiceInfo()
rootoutputnode ==> //Book
xsltTransformationString ==> 
            <xsl:stylesheet version="1.0" xmlns="" ...>
...
            </xsl:stylesheet>
Service ==> AWSECommerceService
AWSAccessKeyId ==> 000000000000000
template ==>  <p><a value='href'><value/></a> 
by <value/></p> 
endpoint ==> http://localhost/xml.xml
outputType ==> http://example.com/store#StockItem
elementValue ==> Author!itemDescription
attributeValue ==> itemDetailURL
SearchIndex ==> Books
queryParameter ==> Title
Operation ==> ItemSearch

Liệt kê tất cả các đặc tính

Bạn sẽ phải thực hiện các hàm khác cùng MashupOntologyReader. Ví dụ, bạn sẽ cần một danh sách tất cả các đặc tính của một lớp, đặc biệt là lớp outputType trình bày. Để làm điều này bạn cần tạo ra một phương thức mới (Xem ví dụ 6).

Ví dụ 6. Phương thức showAllProperties()
...
import com.hp.hpl.jena.util.iterator.*; 
import com.hp.hpl.jena.ontology.*;

public class MashupOntologyReader {

    private OntModel serviceOntModel;
       
    public OntModel getOnt(){
       return serviceOntModel;
    }

    public MashupOntologyReader(){
...
    }

 
    public void showAllProperties(OntClass theClass){
       
        String thisClassURI = theClass.getURI();
       
        for (ExtendedIterator i = theClass.listDeclaredProperties(); 
             i.hasNext(); ) {

            OntProperty thisProp = (OntProperty)i.next();
            System.out.println("Property (raw): "
                        +thisProp.getLocalName());
         }   
    }
    
   
    public static void main(String[] args) {

       MashupOntologyReader reader = new MashupOntologyReader();
       reader.showAllProperties(reader.getOnt().getOntClass(
                             "http://example.com/store#StockItem"));
   
    }

}

Bắt đầu từ phần cuối cùng của ví dụ 6, trong hàm main() bạn gọi một hàm mới nhưng lưu ý là để có được các đặc tính cho một lớp bạn cần phải có tham chiếu cho một lớp hiện thời. Để làm điều này, bạn cần một tham chiếu cho chính bản thân bản thể luận chứ không chỉ là đối tượng MashupOntologyReader. Vì thế bạn cần có một phương thức mới để lấy được tham chiếu cho mẫu bản thể luận đó. Khi mà bạn đã thực hiện được điều này, bạn có thể lấy được tham chiếu cho lớp dựa trên URI của nó. Trong trường hợp này bạn đang tìm các đặc tính cho lớp StockItem

Rõ ràng là việc lấy các đặc tính có liên quan tới sử dụng phương thức listProperties(), phương thức này sẽ trả về ExtendedIterator. Bạn có thể lặp lại qua các đặc tính. Trong trường hợp này bạn nhớ xem localName.

Bạn sẽ thấy kết quả tương tự (xem ví dụ 7).

Ví dụ 7. Các đặc tính của lớp StockItem
Property (raw): writerOf
Property (raw): itemDescription
Property (raw): itemDetailURL
Property (raw): authorOf
Property (raw): stockedProduct
Property (raw): itemPrice

Tất nhiên cách này không dễ sử dụng. Bạn có thể làm cho nó trông dễ coi hơn một chút.

Tân trang lại

Mặc dù là các thông tin trên có ích nhưng chưa chắc là thứ bạn muốn hiển thị cho người dùng thấy. Và may mắn là RDF cho phép bạn dán nhãn cho từng lớp hay từng đặc tính. Những gì bạn cần làm là hiển thị đặc tính chứ không phải localName (xem ví dụ 8).

Ví dụ 8. Sử dụng nhãn thay cho localName
...
    public void showAllProperties(OntClass theClass){
       
        String thisClassURI = theClass.getURI();
       
        for (ExtendedIterator i = theClass.listDeclaredProperties(); 
             i.hasNext(); ) {

            OntProperty thisProp = (OntProperty)i.next();
            Property labelProp = 
                  (Property)serviceOntModel.getProperty(
                      "http://www.w3.org/2000/01/rdf-schema#label");
            if (thisProp.hasProperty(labelProp)){
               System.out.println("Property: "
                   +thisProp.getProperty(labelProp).getLiteral()
                   //+thisProp.getLabel(null)
                   );
            } else {
               System.out.println("Property (raw): "
                        +thisProp.getLocalName());
            }
         }   
    }
...

ví dụ 8 bạn sẽ thấy có một kỹ thuật mới. Bạn dùng phương thức getProperty() để gọi một đối tượng đặc tính cụ thể và sau đó kiểm tra xem mỗi đặc tính có đặc tính đó không (tất nhiên là đặc tính có thể có đặc tính). Nếu nó có chứa đặc tính thì bạn cho OutputLabel nếu nó không chứa đặc tính thì ở đầu ra sẽ xuất hiện localName. Lưu ý là phương thức getLabel() cho phép bạn chọn nhãn dựa theo ngôn ngữ.

Kết quả bây giờ trông sẽ như (xem ví dụ 9).

Ví dụ 9. Sử dụng nhãn.
Property (raw): writerOf
Property: Item Description
Property: Item Detail Page URL
Property (raw): authorOf
Property: Stocked Product
Property: Item Price

Một số các đặc tính này không có nhãn bởi vì người dùng không cần thiết phải nhìn thấy chúng. Giới hạn đầu ra để phân loại dữ liệu các đặc tính.

Giới hạn đầu ra đối với đặc tính dataType.

Ở một ứng dụng hoàn chỉnh, bạn sẽ muốn hiển thị các đặc tính và bất kỳ các đặc tính của đối tượng chứ không chỉ các đối tượng. Ví dụ, trong trường hợp này bạn tạo ra một StockItem có chứa đặc tính của sản phẩm mà nó đại diện. Trong một ứng dụng hoàn chỉnh, bạn sẽ muốn hiển thị tác giả của quyển sách mà sản phẩm đại diện. Tuy nhiên, để làm điều này bạn cần gọi lại phương thức showAllProperties()

Bản thân đây không là một sai sót, tuy nhiên bạn cần nhận ra rằng có một số khó khăn xuất hiện. Lý do là StockItem của bạn có chứa một đặc tính mang giá trị của Product trong trường hợp này là Book. Book có một đặc tính là writtenBy đó là một đối tượng Author. Đối tượng Author này có một đặc tính chung đối với tất cả các quyển sách do tác giả này viết, điều này dẫn bạn quay trở lại với đối tượng Author, đối tượng tác giả dẫn bạn quay trở lại với các đối tượng Books, và cứ tiếp tục như thế.

Bạn có thể làm việc này nhưng để mọi thứ đơn giản hơn bạn cần giới hạn bản thân bằng các giá trị DatatypeProperty. May mắn là không khó để phân biệt sự khác nhau giữa DatatypeProperty và một ObjectProperty (xem ví dụ 10).

Ví dụ 10. Giới hạn DatatypeProperties
...
    public void showAllProperties(OntClass theClass){
       
        String thisClassURI = theClass.getURI();
       
        for (ExtendedIterator i = theClass.listDeclaredProperties(); 
             i.hasNext(); ) {

           OntProperty thisProp = (OntProperty)i.next();
            if (thisProp.isObjectProperty()){
                //System.out.println("This is an object property.");
            } else {
               Property labelProp = 
                     (Property)serviceOntModel.getProperty(
                         "http://www.w3.org/2000/01/rdf-schema#label");
               if (thisProp.hasProperty(labelProp)){
                  System.out.println("Property: "
                      +thisProp.getProperty(labelProp).getLiteral()
                      //+thisProp.getLabel(null)
                      );
               } else {
                  System.out.println("Property (raw): "
                        +thisProp.getLocalName());
               }
            }
         }   
    }
...

Với thay đổi này, đầu ra sẽ như (xem ví dụ 11).

Ví dụ 11. Đặc tính xuất:
Property:
Property: Item Description
Property: Item Detail Page URL
Property: Item Price

Biểu mẫu dữ liệu đầu vào mới

Bạn đã biết về truy lục đặc tính, đã đến lúc xem xét việc xây dựng biểu mẫu thực.

Biểu mẫu sẽ hoạt động như thế nào

Trước khi bạn bắt đầu, bạn nên hiểu rõ chính xác bạn đang xây dựng cái gì. Để cho người dùng quyền kiểm soát, bạn cần một biểu mẫu chấp nhận dữ liệu vào của người dùng. Biểu mẫu dữ liệu đầu vào mới sẽ có thể là vài dạng thu thập thông tin. (Bạn có thể thực hiện việc này như một dạng sử dụng Ajax nhưng đây sẽ là một bài tập dành cho người đọc bài viết).

biểu mẫu này sẽ thực hiện các bước sau:

  1. Người dùng chọn một loại dịch vụ. Dạng này sẽ hiển thị cố định bằng việc kiểm tra các lớp con của lớp Service
  2. Người dùng chọn một dịch vụ hiện thời. Dạng này sẽ hiển thị cố định bằng việc kiểm tra các Instances của lớp được chọn trong bước một
  3. Người dùng nhập một khuôn mẫu và chọn các đặc tính hiển thị. Dạng này là sự kết hợp các đặc tính của outputType của dịch vụ đã chọn với trường nhập văn bản .

Chúng ta cùng bắt đầu.

Liệt kê các loại dịch vụ

Bước đầu tiên là cung cấp một dạng liệt kê các loại dịch vụ thích hợp. Thêm mã cho lớp MashupClientServlet (xem ví dụ 12).

Ví dụ 12. Liệt kê các loại dịch vụ.
...
public class MashupClientServlet 
             extends javax.servlet.http.HttpServlet 
             implements javax.servlet.Servlet {

   public MashupClientServlet() {
      super();
   }      

   protected void doGet(HttpServletRequest request, 
                        HttpServletResponse response) throws 
                                ServletException, IOException {
      
      MashupOntologyReader reader = new MashupOntologyReader();
      
      response.getWriter().print("<html>");
      response.getWriter().print("<head></head>");
      response.getWriter().print("<body>");

      response.getWriter().print("<h1>The Mashup</h1>");
      
      response.getWriter().println(
              "<form action='MashupClientServlet' method='get'>");
      response.getWriter().print("<h1>Choose a sevice type</h1>");
      response.getWriter().print("<select name='serviceType'>");
      
      OntClass serviceClass = reader.getOnt()
                 .getOntClass("http://example.com/store#Service");
      for (ExtendedIterator i = serviceClass.listSubClasses();
              i.hasNext(); ) {
            OntClass thisClass = (OntClass)i.next();
            response.getWriter().print("<option value='"
                         +thisClass.getURI()+"'>"+
                         thisClass.getLocalName()+"</option>");
      }   
      response.getWriter().print("</select>");

      response.getWriter().println("<input type='submit' />");
      response.getWriter().print("</form>");
      
      response.getWriter().print("</body>");
      response.getWriter().print("</html>");
   }     
...

Phương thức doGet() giúp bạn tạo ra các dạng nhập hiện thời. Trong trường hợp này bạn tạo khung cho biểu mẫu và sau đó đưa tham chiếu tới lớp Service. Từ đây bạn có thể sử dụng phương thức listSubClasses() để lấy ExtendedIterator của các lớp con. Sau đó bạn có thể hiển thị thông tin của các lớp con, bao gồm một URI (được dùng như một giá trị cần được xem xét) và localName. (Để mọi việc trôi chảy hơn bạn nên dãn nhãn cho từng loại lớp và hiển thị chúng).

Kết quả là một biểu mẫu tương tự như hình 1.

Hình 1. Dạng lựa chọn cơ bản.
Các dạng lựa chọn cơ bản

Dạng này có duy nhất một rắc rối. Bạn sẽ nhận thấy biểu mẫu liệt kê dịch vụ Store, là một lớp con của ServiceMappingServiceNewsService cũng là các lớp con của Service nhưng biểu mẫu này không liệt kê bất kỳ lớp con nào của lớp Store mặc dù các lớp con này, theo định nghĩa, là các lớp con của Service.

Thêm lập luận

Vấn đề gặp phải ở đây là chẳng liên quan gì tới mã hay bản thể luận của bạn. Điều rắc rối là khi bạn tạo một mẫu, bạn tạo nó với một sự bổ sung rất dễ đọc bản thể luận mà không trình bày bất cứ lập luận nào khác ngoài việc thuyết minh cấu trúc RDF. Nói cách khác, mô hình hiểu được rằng Bookstore là một lớp con của Store nhưng điều này không có tính chất bắc cầu là vì Store là một lớp con của Service nên suy ra Bookstore là một lớp con của Service.

Để tạo ra thông tin này hoặc thông tin tương tự có thể chỉ gắn với các đặc tính của bạn và ngược lại với chuẩn các đặc tính OWL sẵn có bạn cần có một reasoner để tạo ra mô hình. Bạn bổ sung lớp MashupOntologyReader (xem ví dụ 13).

Ví dụ 13. Bổ sung reasoner.
...
public class MashupOntologyReader {

    private OntModel serviceOntModel;
       
    public MashupOntologyReader(){
       String source = "http://example.com/store";

       serviceOntModel =  
          ModelFactory.createOntologyModel(
                           OntModelSpec.OWL_MEM_MICRO_RULE_INF, null);
       serviceOntModel.getDocumentManager()
                 .addAltEntry(source, "file:c:/sw/stores.owl" );    
       serviceOntModel.read( source );
       
    }
...

Trong trường hợp này bạn đang dùng một reasoner siêu nhỏ không cung cấp tất cả các khả năng của trọn bộ bản thể luận OWL mà lại cung cấp một sự cân bằng giữa hàm và trình bày. (Tư liệu Jena liệt kê danh sách các reasoner khác nhau).

Nếu bây giờ bạn tải lại biểu mẫu bạn sẽ tìm thấy tất cả các lớp con tại chỗ như bạn nhìn thấy trong hình 2.

Hình 2. Tất cả các lớp con.
Tất cả các lớp con

Nhưng bây giờ bạn lại có một vấn đề khác. Lựa chọn “Nothing” là gì và nó có nguồn gốc từ đâu?

Khử “nothing”

Vấn đề ở đây là reasoner đang chạy tốt. Mỗi lớp là một lớp con của owl:Thing mỗi lớp là một liên lớp của owl:Nothing một loạt ví dụ rỗng. Vì thế khi bạn yêu cầu reasoner lấy tất cả các lớp con và nó thực hiện lệnh. Để tránh làm người dùng nhầm lẫn, bạn cần yêu cầu reasoner không hiển thị các lựa chọn riêng biệt (xem ví dụ 14):

Ví dụ 14. Loại trừ lựa chọn “Nothing”.
....
      OntClass serviceClass = reader.getOnt()
                 .getOntClass("http://example.com/store#Service");
      for (ExtendedIterator i = serviceClass.listSubClasses();         
              i.hasNext(); ) {
            OntClass thisClass = (OntClass)i.next();
            if (!thisClass.getURI()
                 .equals("http://www.w3.org/2002/07/owl#Nothing")){
               response.getWriter().print("<option value='"
                         +thisClass.getURI()+"'>"+
                         thisClass.getLocalName()+"</option>");
            }
      }   

      response.getWriter().print("</select>");
...

Và bây giờ thì kết quả sẽ là những gì bạn mong đợi, xem hình 3.

Hình 3. Tập các dịch vụ cuối cùng.
Tập các dịch vụ cuối cùng

Liệt kê các dịch vụ

Khi người dùng gửi biểu mẫu thì nó sẽ tự quay trở lại phương thức doGet() bởi vì hoạt động này đã được quy định trên phần tử form. Khi máy chủ nhận được yêu cầu này nó sẽ kiểm tra xem liệu tham số serviceType đã được chấp nhận chưa. Nếu tham số serviceType chưa được chấp nhận thì máy chủ sẽ hiển thị dạng gốc. Ngược lại, nếu nó đã được chấp nhận thì bạn phải sẵn sàng cho giai đoạn hai của biểu mẫu (xem ví dụ 15).

Ví dụ 15. Liệt kê các dịch vụ
...
   protected void doGet(HttpServletRequest request, 
                        HttpServletResponse response) throws 
                                ServletException, IOException {
      
      MashupOntologyReader reader = new MashupOntologyReader();
      
      response.getWriter().print("<html>");
      response.getWriter().print("<head></head>");
      response.getWriter().print("<body>");

      response.getWriter().print("<h1>The Mashup</h1>");
      
      String serviceType = request.getParameter("serviceType");
            
      if (serviceType == null) {
         response.getWriter().println(
              "<form action='MashupClientServlet' method='get'>");
...
         response.getWriter().print("</select>");
      } else {

         response.getWriter().println(
              "<form action='MashupClientServlet' method='get'>");

         Individual serviceTypeClass = 
              reader.getOnt().getIndividual(serviceType);
         String serviceTypeName = serviceTypeClass.getLocalName();
         
         Individual[] individuals = 
              reader.getIndividuals(serviceTypeName);
         
         response.getWriter().println(
              "<input type='hidden' value='"+serviceType+
                                      "' name='serviceType' />");

         
         response.getWriter().print("<p>Choose a service:</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().println("<input type='submit' />");
        response.getWriter().print("</form>");
      
        response.getWriter().print("</body>");
        response.getWriter().print("</html>");
   }     
...

Ở giai đoạn hai của biểu mẫu bạn lấy một tham chiếu tới một lớp serviceType do URI trình bày và sau đó sử dụng localName của nó để lấy tất cả Individuals của lớp đó bằng cách sử dụng phương thức getIndividuals() mà bạn đã xây dựng được ở phần 5 (xem Tài nguyên). Sau đó bạn có thể xây dựng biểu mẫu hiện thời.

Bắt đầu bằng việc tạo ra một trường ẩn dọc theo serviceType.

Tạo một phần tử select, hiển thị phần tử option bằng cách sử dụng URI như một giá trị và localName hoặc label (nếu muốn) như một văn bản người dùng có thể thấy được. Kết quả sẽ là một trang tương tự như hình 4.

Hình 4. Danh sách các dịch vụ
Danh sách các dịch vụ

Định nghĩa kết quả xuất

Bây giờ thì bạn đã biết người dùng muốn dịch vụ nào. Bạn cần xem người dùng muốn loại thông tin nào người dùng muốn tìm kiếm. Để làm điều này, bạn cần tạo ra một biểu mẫu chấp nhận tất cả lựa chọn của người dùng (xem ví dụ 16).

Ví dụ 16. Định nghĩa kết quả xuất.
 ...
...
   protected void doGet(HttpServletRequest request, 
                        HttpServletResponse response) throws 
                                ServletException, IOException {
      
      MashupOntologyReader reader = new MashupOntologyReader();
      
...
      String serviceURI = request.getParameter("serviceURI");
            
      if (serviceType == null) {
...
      } else if (serviceURI == null){

         response.getWriter().println(
              "<form action='MashupClientServlet' method='get'>");
...
         response.getWriter().print("</select>");
         
      } else {

         response.getWriter().println(
            "<form action='MashupClientServlet' method='get'>");
         
         response.getWriter().println("<input type='hidden' value='"
                             +serviceType+"' name='serviceType' />");
         response.getWriter().println("<input type='hidden' value='"
                               +serviceURI+"' name='serviceURI' />");

         response.getWriter().println("<h2>Define your output</h2>");
         
         response.getWriter().println(
           "<p>Define a template and choose the data to go into it."+
           "For example, to create a link, you might create a "+
           "template of <p><a value='href'><value "+
           "/></a></p>.  From there, designate the order in "+
           "which you want properties to appear.</p>");
         
         response.getWriter().println("<textarea name='template' "+ 
           "rows='5' cols='80'></textarea>");
         
         System.out.println("serviceuri="+serviceURI);
         OntClass serviceClass = 
                 reader.getOnt().getOntClass(serviceType);
         Property outputProp = (Property)reader.getOnt()
              .getProperty("http://example.com/store#outputType");
         RDFNode outputPropVal = 
               serviceClass.getPropertyValue(outputProp);
         System.out.println("The service outputs items of type "
                                         +outputPropVal.toString());
          
     }

        response.getWriter().println("<input type='submit' />");
        response.getWriter().print("</form>");
      
        response.getWriter().print("</body>");
        response.getWriter().print("</html>");
   }     
...

Phần đầu của biểu mẫu này rất đơn giản. Nó chỉ là một textarea mà người dùng có thể nhập vào đó một khuôn mẫu giống các khuôn mẫu mà bạn đã và đang sử dụng trong suốt đề tài này. Sau đó, mọi việc hơi phức tạp hơn. Trước khi bạn nhập các đặc tính bạn cần biết loại lớp nào mà bạn đang thấy. Để biết điều này bạn truy lục một tham chiếu vào lớp serviceType và dùng nó để truy lục đặc tính outputType.

Chính Property đại diện cho một lớp và lớp đó có các đặc tính riêng của nó.

Truy vấn các đặc tính

Đến đây bạn đã sẵn sàng cho việc truy lục các đặc tính nhưng điều này không có nghĩa là bạn nhúng tất cả các hàm vào servlet bởi vì hàm này tương tự những thao tác bạn đã thực hiện ở lớp MashupOntologyReader. Đặc biệt là tạo ra một phương thức mới ở trong lớp đó được gọi là getAllProperties() như mô tả ở ví dụ 17.

ví dụ 17. Phương thức getAllProperties()
...
public class MashupOntologyReader {
...
    public Vector getAllProperties(OntClass theClass){

        Vector properties = new Vector();
        
        String thisClassURI = theClass.getURI();
        
        for (ExtendedIterator i = theClass.listDeclaredProperties(); 
             i.hasNext(); ) {
               
            OntProperty thisProp = (OntProperty)i.next();
            Property labelProp = (Property)serviceOntModel.getProperty(
                        "http://www.w3.org/2000/01/rdf-schema#label");
            if (thisProp.hasProperty(labelProp)){
                System.out.println("Property: "+
                       thisProp.getProperty(labelProp).getLiteral());
            }
            if (thisProp.isObjectProperty()){
                   System.out.println(
                         "this bears further investigation: ");
            } else {
                   properties.add(thisProp);
            }
       }    
       return properties;
    }
...

Phương thức này mang tính đồng nhất ảo đối với phương thức showAllProperties() mà bạn đã tạo ra trước đây ngoại trừ việc nó gửi lại một Vector có chứa tất cả các đối tượng Property. Bạn có thể dùng phương thức này trong servlet.

Hiển thị các đặc tính

Biểu mẫu hiện thời cần trình bày vài nhiệm vụ. Ngoài việc truy lục template của người dùng, nó không chỉ liệt kê các đặc tính mà còn cho người dùng cơ hội yêu cầu sử dụng các đặc tính như các thuộc tính và các phần tử (xem ví dụ 18).

Ví dụ 18. Hiển thị đặc tính.
...
public class MashupClientServlet 
             extends javax.servlet.http.HttpServlet 
             implements javax.servlet.Servlet {

   public MashupClientServlet() {
      super();
   }      

   protected void doGet(HttpServletRequest request, 
                        HttpServletResponse response) throws 
                                ServletException, IOException {
...
         OntClass serviceClass = 
                 reader.getOnt().getOntClass(serviceType);
         Property outputProp = (Property)reader.getOnt()
              .getProperty("http://example.com/store#outputType");
         RDFNode outputPropVal = 
               serviceClass.getPropertyValue(outputProp);
         System.out.println("The service outputs items of type "
                                         +outputPropVal.toString());
          
         OntClass returnObjectClass = reader.getOnt()
                              .getOntClass(outputPropVal.toString());
         Vector properties = 
                          reader.getAllProperties(returnObjectClass);

         
response.getWriter().println("<table><tr><th>Attribute"+
                 "<br />position</th><th>Element<br 
/>position</th>"+
                 "<th>Property name</th></tr>");
           
         for (int i = 0; i < properties.size(); i++) {
              String cleanPropName = 
                   ((Property)properties.elementAt(i)).getURI()
                                     .replaceAll("#", "_").toString()
                                     .replaceAll("http://", "_");
              response.getWriter().println("<tr><td><input "+
                   "type='text' size='2' name='attribute"+
                   cleanPropName+"' /></td>");
              response.getWriter().println("<td><input "+
                   "type='text' size='2' name='element"+
                   cleanPropName+"' /></td>");
              response.getWriter().print("<td>"+
               ((OntProperty)properties.elementAt(i))
                          .getLabel(null)+"</td></tr>");
        }
           
        response.getWriter().println("</table>");
          
     }

        response.getWriter().println("<input type='submit' />");
        response.getWriter().print("</form>");
      
        response.getWriter().print("</body>");
        response.getWriter().print("</html>");
   }     
...

Đầu tiên biểu mẫu truy lục một tham chiếu tới lớp đầu ra và sau đó gọi phương thức getAllProperties() để lấy một Vector các đặc tính cho lớp đó. Từ đây tạo một khung của bảng HTML để sắp xếp những đặc tính này cho người dùng nhìn thấy.

Bây giờ bạn đã sẵn sàng lặp đi lặp lại qua mỗi đặc tính. Biểu mẫu cuối cùng là như hình 5 gồm hai hộp văn bản cho mỗi đặc tính. Bạn cần phải tạo một cái tên để kết nối dữ liệu của các hộp văn bản tới đặc tính. Bạn không thể dùng URI gốc cho các đặc tính tuy nhiên thay vì dùng URI gốc bạn có thể tạo ra một phiên bản URI mới để loại bỏ các ký tự lỗi và thay thế chúng bằng các ký tự gạch dưới.

Khi việc này hoàn thành, bạn có thể tự do tạo một phiên bản thuộc tính và phần tử cho từng hộp văn bản cho từng đặc tính. (Trong một ứng dụng sản xuất bạn cần đảm bảo rằng tất cả các đặc tính này đều có nhãn hoặc bắt được lỗi ở đây. Bạn cũng có thể muốn có khả năng lựa chọn các ngôn ngữ khác nhau hơn là lờ việc này đi). Biểu mẫu cuối cùng sẽ trông giống như ở hình 5.

Hình 5. Biểu mẫu đặc tính.
Biểu mẫu đặc tính

Tạo biểu mẫu cuối cùng

Bây giờ bạn đã thu thập đủ tất cả các thông tin từ người dùng, bạn đã sẵn sàng cho việc tái tạo biểu mẫu truy vấn gốc. Biểu mẫu này không chỉ bao gồm hộp đầu nhập cho thuật ngữ truy vấn mà còn chứa tất cả các thông tin người dùng đã chấp nhận, mã hóa như các trường ẩn (xem ví dụ 19).

Ví dụ 19. Biểu mẫu cuối cùng.
...
...
   protected void doGet(HttpServletRequest request, 
                        HttpServletResponse response) throws 
                                ServletException, IOException {
      
...
      String serviceType = request.getParameter("serviceType");
      String serviceURI = request.getParameter("serviceURI");
      String template = request.getParameter("template");
            
      if (serviceType == null) {
...
      } else if (template == null){
...
      } else {

        response.getWriter().println(
           "<form action='MashupClientServlet' method='post'>");
        response.getWriter().println(
           "<input type='hidden' value='"+serviceType+
           "' name='serviceType' />");
        response.getWriter().println(
           "<input type='hidden' value='"+serviceURI+
           "' name='serviceURI' />");
        response.getWriter().println(
           "<input type='hidden' value='"+
                template.replaceAll("<", "<")
                        .replaceAll("'", "'")
                        .replaceAll("\"", """)+
           "' name='template' />");

        OntClass serviceClass = 
                  reader.getOnt().getOntClass(serviceType);
        Property outputProp = (Property)reader.getOnt()
          .getProperty("http://example.com/store#outputType");
        RDFNode outputPropVal = 
                     serviceClass.getPropertyValue(outputProp);
          
        OntClass returnObjectClass = reader.getOnt()
                        .getOntClass(outputPropVal.toString());
        Vector properties = reader.getAllProperties(returnObjectClass);

        for (int i = 0; i < properties.size(); i++) {
           String cleanPropName = 
                ((Property)properties.elementAt(i)).getURI()
                     .replaceAll("#", "_").toString()
                     .replaceAll("http://", "_");
           response.getWriter().println(
              "<input type='hidden' name='attribute"+cleanPropName+
              "' value ='"+
              request.getParameter("attribute"+cleanPropName)+"'/>");
           response.getWriter().println(
              "<input type='hidden' name='element"+cleanPropName+
              "' value = '"+
              request.getParameter("element"+cleanPropName)+"'/>");
           }         

           response.getWriter().print("<p>Enter a keyword:</p>");
           response.getWriter().print(
                         "<input type='text' name='query' />");
      
        }

        response.getWriter().println("<input type='submit' />");
        response.getWriter().print("</form>");
      
        response.getWriter().print("</body>");
        response.getWriter().print("</html>");
   }     
...

Các biểu mẫu serviceTypeserviceURI rất đơn giản nhưng do khuôn mẫu được làm từ HTML nên bạn không thể thả nó vào giá trị thuộc tính của một phần tử đầu nhập mà không duyệt qua việc giải mã nó. Vì vậy, để giải quyết vấn đề này bạn cần thay thế các ký tự lỗi bằng các thực thể có thể diễn giải ngược trở lại các ký tự tương đương khi người dùng chấp nhận biểu mẫu.

Tiếp đó bạn cần tạo các trường ẩn cho các đặc tính. Để thực hiện điều này bạn cần lặp đi lặp lại qua các đặc tính để đạt được các giá trị thuộc tính và phần tử tiềm năng sau đó mã hóa chúng lại thành các trường ẩn.

Cuối cùng, tạo biểu mẫu truy vấn

Có rất nhiều mã nhưng về cơ bản nó tạo ra HTML (như trong ví dụ 20).

Ví dụ 20. Biểu mẫu kết quả.
<html><head></head><body><h1>The 
Mashup</h1><form 
action='MashupClientServlet' method='post'>
<input type='hidden' value='http://example.com/store#Bookstore' 
name='serviceType' />
<input type='hidden' value='http://example.com/store#Amazon.com' 
name='serviceURI' />
<input type='hidden' value='<p><a 
value='href'><value /></a>, $<value />
</p>' 
name='template' />
<input type='hidden' name='attribute_example.com/store_itemPrice' 
value =''/>
<input type='hidden' name='element_example.com/store_itemPrice' 
value = '2'/>
<input type='hidden' name='attribute_example.com/store_itemDescription' 
value =''/>
<input type='hidden' name='element_example.com/store_itemDescription' 
value = '1'/>
<input type='hidden' name='attribute_example.com/store_itemDetailURL' 
value ='1'/>
<input type='hidden' name='element_example.com/store_itemDetailURL' 
value = ''/>
<p>Enter a keyword:</p><input type='text' name='query' 
/><input 
type='submit' />
</form></body></html>

Ở trình duyệt, tất cả những gì bạn thấy là trường truy vấn (như trong hình 6).

Hình 6. Biểu mẫu truy vấn cuối cùng
Biểu mẫu truy vấn cuối cùng

Bây giờ bạn đang thu thập tất cả các dữ liệu đó và bạn sẽ chấp nhận nó ở chương trình phụ trợ.


Chấp nhận dữ liệu

Để riêng trong tất cả các mã cho biểu mẫu cuối cùng là cố định dùng phương thức POST mà không dùng phương thức GET sẽ đưa bạn quay trở lại phương thức doPost() nơi tất cả các xử lý thực sự diễn ra.

Lấy các tham số cơ bản

Bước đầu tiên là lấy các tham số cơ bản, các tham số đó là các văn bản dễ dàng truy lục (xem ví dụ 21).

Ví dụ 21. Lấy các tham số cơ bản.
...
public class MashupClientServlet 
             extends javax.servlet.http.HttpServlet 
             implements javax.servlet.Servlet {

...
   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);
      
      String template = request.getParameter("template")
                            .replaceAll("<", "<")
                            .replaceAll("'", "'")
                            .replaceAll(""", "\"");
      System.out.println("Template = "+template);
      
      String serviceType = 
           request.getParameter("serviceType").toString();
      System.out.println("serviceType = "+serviceType);
     
      try {
         DocumentBuilder builder = DocumentBuilderFactory
                     .newInstance().newDocumentBuilder();

...

Tất cả các bước này đơn giản chỉ là việc truy lục giá trị của các tham số. Mặc dù trong trường hợp khuôn mẫu thì bạn cần đảo ngược các thay đổi mà bạn tạo ra để gửi các dữ liệu thông qua biểu mẫu.

Nếu bạn chấp nhận biểu mẫu, bạn nên xem thiết bị đầu cuối sau đây (xem ví dụ 22).

Ví dụ 22. Các tham số cơ bản
Template = <p><a value='href'><value /></a>, 
$<value /></p>
serviceType = http://example.com/store#Bookstore

Lấy các dữ liệu đầu vào đặc tính

Lấy các dữ liệu đầu vào đặc tính hơi phức tạp một chút nhưng bạn nên tuân theo mẫu bạn đã sử dụng ở bước cuối cùng (xem ví dụ 23).

Ví dụ 23. Lấy dữ liệu đầu vào đặc tính.
...
      String serviceType = 
                request.getParameter("serviceType").toString();
      System.out.println("serviceType = "+serviceType);
      
      OntClass serviceClass = ont.getOnt().getOntClass(serviceType);
      Property outputProp = (Property)ont.getOnt()
               .getProperty("http://example.com/store#outputType");
      RDFNode outputPropVal =  
                        serviceClass.getPropertyValue(outputProp);
       
      OntClass returnObjectClass = ont.getOnt()
                            .getOntClass(outputPropVal.toString());
      System.out.println("returnObjectClass = "+returnObjectClass);

      Vector properties = ont.getAllProperties(returnObjectClass);

      String[] attributes = new String[20] ;
      String[] elements = new String[20] ;
        
      for (int i = 0; i < properties.size(); i++) {
           String cleanPropName = ((Property)properties.elementAt(i))
                       .getURI().replaceAll("#", "_").toString()
                                .replaceAll("http://", "_");
           try {
              int index = new Integer(request.getParameter(
                  "attribute"+cleanPropName).toString())
                                        .intValue() - 1;
              attributes[index] = ((Property)properties.elementAt(i))
                                        .getURI();
              System.out.println("Attribute = "+attributes[index]);
           } catch (Exception e){
              //Don't do anything, just weed out entries that 
              //aren't integers.
           }
           try {
              int index = new Integer(request.getParameter(
                "element"+cleanPropName).toString()).intValue() - 1;
              elements[index] = 
                   ((Property)properties.elementAt(i)).getURI();
              System.out.println("Element = "+elements[index]);
           } catch (Exception e){
              //Don't do anything, just weed out entries that 
              //aren't integers.
           }
        }

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

         Service[] svcs = {service};
         
...

Phần đầu trông rất quen thuộc, bạn đã thực hiện nó hai lần để lặp đi lặp lại thông qua các đặc tính. Nhưng việc lấy được các đặc tính lại là chuyện khác.

Về cơ bản, bạn sẽ cần hiểu URIs đối với từng đặc tính như là các mục của attributeValues hoặc là elementValues Vectors ở trong lớp Service. Hơn nữa, bạn cần bổ sung chúng theo trình tự lựa chọn của người dùng. Để điều này xảy ra bạn sẽ lặp đi lặp lại thông qua từng đặc tính và nếu người dùng đã nhập một giá trị nguyên, bạn sẽ dùng giá trị nguyên đó như một chỉ mục (mục lục chỉ thị) cho một mảng. Theo cách này bạn sẽ kết thúc bằng một mảng của đặc tính URI theo trình tự người dùng yêu cầu.

Nếu bạn tải lại biểu mẫu, bạn sẽ thấy tương tự như trong thiết bị đầu cuối sau đây (xem ví dụ 24).

Ví dụ 24. Đầu ra
Template = <p><a value='href'><value /></a>, 
$<value /></p>
serviceType = http://example.com/store#Bookstore
returnObjectClass = http://example.com/store#StockItem
Property: Item Price
Property: Item Description
Property: Item Detail Page URL
Property: Stocked Product
this bears further investigation: 
Element = http://example.com/store#itemPrice
Element = http://example.com/store#itemDescription
Attribute = http://example.com/store#itemDetailURL

Lưu ý rằng URI cho các đặc tính bây giờ đã trở lại dạng bình thường.

Bổ sung dữ liệu cho dịch vụ

Bây giờ bạn cần lưu giữ tất cả các thông tin trong lớp Service hiện thời (xem ví dụ 25).

Ví dụ 25. Bổ sung dữ liệu cho dịch vụ
...
      String template = request.getParameter("template")
                            .replaceAll("<", "<")
                            .replaceAll("'", "'")
                            .replaceAll(""", "\"");
      service.template = template;
      
      String serviceType = 
                request.getParameter("serviceType").toString();
      
      OntClass serviceClass = ont.getOnt().getOntClass(serviceType);
      Property outputProp = (Property)ont.getOnt()
               .getProperty("http://example.com/store#outputType");
      RDFNode outputPropVal =  
                        serviceClass.getPropertyValue(outputProp);
      service.recordExp = outputPropVal.toString();
       
      OntClass returnObjectClass = ont.getOnt()
                            .getOntClass(outputPropVal.toString());
...
              elements[index] = 
                   ((Property)properties.elementAt(i)).getURI();
           } catch (Exception e){
              //Don't do anything, just weed out entries that 
              //aren't integers.
           }
        }         

        service.attributeValues.clear();
        service.elementValues.clear();
        
        for (int i = 0; i < 20; i++){
           if (attributes[i] != null && !attributes[i].equals("")){
              service.attributeValues.add(attributes[i]);
           }
           if (elements[i] != null && !elements[i].equals("")){
              service.elementValues.add(elements[i]);
           }
       }
      
       try {
         DocumentBuilder builder = DocumentBuilderFactory
                     .newInstance().newDocumentBuilder();

         Service[] svcs = {service}; 
...

Bắt đầu từ các lệnh đầu tiên, thuộc tính khuôn mẫu là rất rõ ràng, và recordExp đại diện cho biểu thức xác định các kết quả riêng lẻ. Vì thế, theo cách làm mới này, URI sẽ đại diện cho outputType.

Cuối cùng, bạn đã sẵn sàng để bổ sung các thuộc tính đặc tính và các thuộc tính phần tử. Để thực hiện nó bạn đã có các vector của tất cả các giá trị trong dịch vụ vì bạn đã tải nó về từ bản thể luận, sau đó bạn lặp đi lặp lại thông qua các mảng, kết thúc bất kỳ giá trị tồn tại nào tới Vectors.

Bởi vì các servlet được cố định để lấy thông tin từ Service nên bạn không cần làm gì thêm để dữ liệu sẵn dùng cho servlet.


Biểu hiện dữ liệu dịch vụ

Bạn đã có các tham số do người dùng chọn ra, bây giờ là lúc để chúng chuyển từ dạng dữ liệu phác thảo sang dạng đầy đủ. Bạn cần phải thay thể các thao tác có gốc XPath hiện hành sang các thao tác dựa trên bản thể luận.

Truyền bản thể luận đi

Bước đầu tiên là đảm bảo rằng bản thân bản thể luận có sẵn bất kỳ chỗ nào người dùng cần tới. Trong trường hợp này có nghĩa là để cho nó sẵn sàng với phương thức renderService() của servlet (xem ví dụ 26).

Ví dụ 26. Truyền bản thể luận đi
...
   public static Node renderService(String query, Service svc, 
                 Document hostDoc, MashupOntologyReader ont ) {

      Document document = getData(query, svc);
...
   }

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

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


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

            if (renderedService != null){
...

Khi bạn gộp bản thể luận như một phần chữ ký cho phương thức renderService() bạn cần phải bổ sung bản thể luận vào lệnh gọi tới phương thức đó.

Tải dữ liệu mới

Khi bạn thông qua bản thể luận tới phương thức renderService(), nó sẽ chứa tất cả các định nghĩa nhưng không chứa bất kỳ dữ liệu nào. May thay, bạn có thể bổ sung các dữ liệu một cách rất đơn giản (xem ví dụ 27).

Ví dụ 27. Tải dữ liệu mới
...
...
            Document document = getData(query, svc);

            String source = "http://example.com/store#";
            Model model = ont.getOnt().getDocumentManager()
                         .getModel("http://example.com/store");
            
            DOM2Model.createD2M(source, model).load(document);
            OntModel ontModel = (OntModel)model;
            
            Node serviceElement = hostDoc.createElement("span");
            DocumentBuilder builder = DocumentBuilderFactory
                              .newInstance().newDocumentBuilder();
...

Lớp DOM2 bao gồm một phương thức tĩnh, createD2M() cho phép bạn tham chiếu mô hình đối với không gian tên (namepspace) bằng cách đặt câu hỏi. Từ đây bạn có thể dễ dàng tải tài liệu DOM làm đại diện cho các dữ liệu do dịch vụ trả về, sau đó chuyển đổi nó sang dạng bản thể luận chung của nó.

Bạn có thể nhận thấy sự khác biệt giữa mô hình trước và sau thao tác này bằng việc sử dụng phương thức model.write() nhưng vì không có thời gian nên bạn sẽ tự kiểm tra.

Truy lục các đặc điểm riêng biệt dựa trên kiểu dữ liệu đầu ra.

Bước tiếp theo là truy lục các kết quả riêng biệt. Đầu tiên, bạn thực hiện việc này bằng việc dùng giá trị của thuộc tính recordExp như một biểu thức XPath. Bây giờ bạn sẽ cần phải dùng outputType (xem ví dụ 28).

Ví dụ 28. Truy lục các đặc điểm riêng biệt dự trên kiểu dữ liệu outputType
...  
            DOM2Model.createD2M(source, model).load(document);
            OntModel ontModel = (OntModel)model;
            
            Node serviceElement = hostDoc.createElement("span");
            DocumentBuilder builder = DocumentBuilderFactory
                              .newInstance().newDocumentBuilder();

            Node toImport = null;

            //  Get individuals based on output type
            ExtendedIterator recordNodes = ontModel.listIndividuals(
                                ontModel.getOntClass(svc.recordExp));
            
            for (ExtendedIterator i = recordNodes; i.hasNext(); ) {

               Individual thisRecord = (Individual)i.next();

               Document templateDoc = builder.parse(new InputSource(
                                    new StringReader(svc.template)));      
               String expression = "//value";
               XPath xpath = XPathFactory.newInstance().newXPath();
               NodeList templateNodes = (NodeList) xpath.evaluate(
                    expression, templateDoc, XPathConstants.NODESET);
               for (int j=0; j < templateNodes.getLength(); j++){

                  Node thisNode = templateNodes.item(j);
                  Node parentNode = thisNode.getParentNode();            

                  // Get the appropriate property value and replace 
                  //it in the template
                  if ( (Boolean)xpath.evaluate(
                      svc.elementValues.elementAt(j).toString(), 
                      thisRecord, XPathConstants.BOOLEAN)) {
                      Node valueNode = (Node)xpath.evaluate(
                           svc.elementValues.elementAt(j).toString(), 
                           thisRecord, XPathConstants.NODE);
                      String valueText = valueNode.getTextContent();
                      Node replacementNode = 
                         templateDoc.createTextNode(valueText);
                      parentNode.replaceChild(replacementNode, 
                                                          thisNode);    
                  }
               }

               expression = "//@value";
               templateNodes = (NodeList) xpath.evaluate(expression, 
                                 templateDoc, XPathConstants.NODESET);
               for (int j=0; j < templateNodes.getLength(); j++){

                  Attr thisNode = (Attr) templateNodes.item(j);
                  Element parentElement = 
                                (Element)thisNode.getOwnerElement();

                  parentElement.removeAttribute("value");
                  if ( (Boolean)xpath.evaluate(
                      svc.attributeValues.elementAt(j).toString(), 
                      thisRecord, XPathConstants.BOOLEAN)) {
                    Node valueNode = (Node)xpath.evaluate(
                      svc.attributeValues.elementAt(j).toString(), 
                      thisRecord, XPathConstants.NODE);
                    parentElement.setAttribute(
                               thisNode.getNodeValue(),
                               valueNode.getTextContent());    
                        
                  }
              }

...

Trước tiên bạn lấy điểm lặp của các đặc điểm riêng biệt của lớp outputType, trình bày cho dịch vụ được lưu trong thuộc tính recordExp. Sau đó bạn có thể lặp đi lặp lại thông qua những đặc điểm riêng biệt này như trước. Nhưng lần này bạn dùng đặc điểm thisRecord chứ không dùng một mục trong NodeList.

Vào lúc này, đây là tất cả những thay đổi. Tất cả các thao tác XPath khác vẫn ở tại chỗ nhưng bạn thay thế các tham chiếu tới một recordNode bằng thisRecord với đối tượng thisRecord nên servlet sẽ biên dịch ra. Nếu nó không biên dịch thì nó sẽ gửi tới bạn bất cứ kết quả nào bởi vì nó đang tìm kiếm biểu thức XPath cho những dữ liệu không tồn tại.

Truy lục thuộc tính phần tử

Bạn đang thao tác lặp đi lặp lại thông qua bản ghi riêng biệt, bạn cần tiến lên để thay đổi trình giữ chỗ khuôn mẫu với các dữ liệu người dùng yêu cầu. Khuôn mẫu do người dùng cung cấp nhưng khi phương thức renderService() được đề cập đến thì chưa có điều gì thay đổi, nó vẫn được lưu ở thuộc tính template của lớp Service. Điều thay đổi chính là cách bạn đối phó với các mục trong elementValuesattributeValues Vectors. Ngược lại, trước đây chúng là biểu thức XPath và bạn thường lấy các dữ liệu cụ thể do dịch vụ trả về ra khỏi XML, bây giờ chúng là PropertyURI mà bạn sẽ dùng để lấy dữ liệu bằng cách sử dụng reasoner bản thể luận.

Bắt đầu thực hiện việc truy lục đặc tính riêng biệt (xem ví dụ 29).

Ví dụ 29. Truy lục đặc tính phần tử.
...     
               String expression = "//value";
               XPath xpath = XPathFactory.newInstance().newXPath();
               NodeList templateNodes = (NodeList) xpath.evaluate(
                    expression, templateDoc, XPathConstants.NODESET);
               for (int j=0; j < templateNodes.getLength(); j++){

                  Node thisNode = templateNodes.item(j);
                  Node parentNode = thisNode.getParentNode();            

                  // Get the appropriate property value and replace 
                  //it in the template
                  Property prop2 = ont.getOnt().getProperty(
                      svc.elementValues.elementAt(j).toString());
...
                  }
               }
...

Tiến trình này thường không phức tạp bởi vì thông tin lưu giữ trên elementValues Vector là chuỗi trình bày URI cho đặc tính đó.

Lấy giá trị tương ứng

Khi bạn có Property, bạn có thể dùng nó để lấy giá trị từ bản thể luận ra. (Nhớ là bản thể luận bây giờ còn bao gồm các dữ liệu do dịch vụ trả về (xem ví dụ 30)).

Ví dụ 30. Truy lục giá trị
...
               for (int j=0; j < templateNodes.getLength(); j++){

                  Node thisNode = templateNodes.item(j);
                  Node parentNode = thisNode.getParentNode();            

                  // Get the appropriate property value and replace 
                  //it in the template
                  Property prop2 = ont.getOnt().getProperty(
                      svc.elementValues.elementAt(j).toString());
                  RDFNode propVal2 = 
                           thisRecord.getPropertyValue(prop2);
                  if ( propVal2 != null ) {
                     String valueText;
                     if (propVal2.isLiteral()){
                        valueText = ((Literal)propVal2).getString();
                     } else {
                        valueText = propVal2.toString();
                     }
                     Node replacementNode = 
                          templateDoc.createTextNode(valueText);
                     parentNode.replaceChild(replacementNode, 
                                             thisNode);   
                  } else {
                     System.out.println("propval2 is null");
                  }
               }
...

Khi bạn sử dụng phương thức getPropertyValue() trên đối tượng thisRecord để truy lục giá trị bạn cần nhớ là phương thức này không có giá trị rỗng (Null). Nếu nó có giá trị rỗng (Null) thì bạn cần truy lục giá trị nguyên bản (nếu nó là giá trị nguyên bản) hoặc truy lục phiên bản String của giá trị đặc tính.

Bằng một trong hai cách thì valueText chứa dữ liệu thích hợp do dịch vụ gửi về và bạn có thể cho phép servlet tiến hành như trước đây, sử dụng dữ liệu này để thay thế value thích hợp của trình giữ chỗ phân tử trong khuôn mẫu.

Truy lục các đặc tính thuộc tính

Tiến trình mang tính đồng nhất ảo đối với các bộ phận trong một vécto attributeValues. (xem ví dụ 31).

Ví dụ 31. Truy lục các đặc tính thuộc tính.
...
               expression = "//@value";
               templateNodes = (NodeList) xpath.evaluate(expression, 
                                 templateDoc, XPathConstants.NODESET);
               for (int j=0; j < templateNodes.getLength(); j++){

                  Attr thisNode = (Attr) templateNodes.item(j);
                  Element parentElement = 
                                (Element)thisNode.getOwnerElement();

                  // Get the appropriate property value and replace 
                  //it in the template
                  parentElement.removeAttribute("value");

                  Property prop3 = ont.getOnt().getProperty(
                       svc.attributeValues.elementAt(j).toString());
                  RDFNode propVal3 = 
                         thisRecord.getPropertyValue(prop3);
                  if ( propVal3 != null ) {
                     
                     String valueText;
                     if (propVal3.isLiteral()){
                        valueText = ((Literal)propVal3).getString();
                     } else {
                        valueText = propVal3.toString();
                     }
                     parentElement.setAttribute(
                          thisNode.getNodeValue(), valueText);   

                  } else {
                     System.out.print("prop3 is null");                     
                  } 
               }

...

Bạn lại tiếp tục thay đổi bằng cách bạn cố định biến số valueText, đoạn mã đã có để thay thế các thuộc tính trình giữ chỗ trong khuôn mẫu vẫn giữ nguyên không đổi.

Kết quả cuối cùng

Cuối cùng, bạn đã sẵn sàng để xem dữ liệu xuất. Cho khuôn mẫu được nhập trở lại trong hiển thị các đặc tính. Bạn sẽ thấy một kết quả tương tự như ở hình 7.

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

Dĩ nhiên nếu bạn nhập một khuôn mẫu khác thì bạn sẽ nhìn thấy một kết quả khác, và đây chính là toàn bộ vấn đề. Bây giờ người dùng có thể trộn và lấy thông tin nào họ cần và cách thông tin được hiển thị theo cách họ muốn trên trang đó.


Tóm tắt và nguồn tài nguyên

Ngoài lề về mashup đầu tiên này

Bạn đã đi một quãng đường dài để đạt tới đích này. Bạn đã bắt đầu với tay không và làm theo cách của mình thông qua việc xây dựng lên một ứng dụng mashup đơn giản được gọi một cách tùy tiện là các dịch vụ Web và hiển thị các dịch vụ này lên một trang Web dựa trên một khuôn mẫu. Bạn đã lưu giữ thông tin như một cạc và sau đó ngắt nó ra thành từng phần để xây dựng một cây thư mục chung nhất.

Bây giờ bạn đã sẵn sàng mở ứng dụng để thu dữ liệu nhập từ người dùng. Người dùng có thể chọn bất kỳ dịch vụ sẵn có nào và chọn các thông tin mà dịch vụ nên cung cấp hay chọn cả cách thông tin được hiển thị. Từ đây, mọi thứ dường như trong tầm tay. Chức năng của ứng dụng chỉ bị giới hạn bởi mục đích của bạn khi định nghĩa các dịch vụ thêm (phụ) và các cấu trúc trong bản thể luận.

Cuối cùng, không phải tất cả các hàm từ phần một (xem Tài nguyên được chuyển sang quyền kiểm soát của người dùng, khả năng gọi nhiều dịch vụ cũng như khả năng sử dụng các dịch vụ phụ sẽ không còn hiện diện nữa. Tuy nhiên bổ sung lại các khả năng này cũng tương đối đơn giản. Bạn có thể bổ sung nhiều loại dịch vụ bằng việc thay đổi dạng dữ liệu đầu vào để điều chỉnh cho thích hợp với từng loại hình Service Bất cứ đối tượng dịch vụ nào được bổ sung vào services cũng sẽ tuân theo quy trình như thông thường

Thậm chí hàm dịch vụ bổ trợ cũng không nằm ngoài tầm tay. Tất cả những gì bạn phải làm là sửa đổi dạng dữ liệu nhập sao cho nếu người dùng chọn cả một phần tử subservice trong khuôn mẫu thì người dùng cũng có thể có cơ hội chỉ rõ đặc điểm tính chất của dịch vụ bổ trợ như đối với các dịch vụ chính. Thêm một mục cho thuộc tính filterExp và bạn có tất cả các thông tin cần thiết để bắt đầu tiến hành các bước.

Đây quả là một hành trình dài nhưng kiến thức kỹ thuật ngữ nghĩa không còn là một ý nghĩa viển vông của thì tương lai mà nó có khả năng sử dụng ngay bây giờ và cuộc hành trình này của bạn cũng có ý nghĩa đấy chứ./.


Tải về

Mô tảTênKích thước
Mã nguồn phần 6x-ultimashup6-source.zip9KB

Tài nguyên

Học tập

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

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, Nguồn mở, Công nghệ Java, SOA và dịch vụ Web
ArticleID=391028
ArticleTitle=Ultimate mashup – Các dịch vụ Web và Web ngữ nghĩa (semantic Web), Phần 6: Cho người dùng quyền kiểm soát
publish-date=03082007