Thứ Tư, 5 tháng 10, 2016

JAXB – chuyển đổi XML-Schema hay DTD trở thành Java Class, chuyển đổi từ XML sang Java Object và ngược lại

JAXB – chuyển đổi XML-Schema hay DTD trở thành Java Class, chuyển đổi từ XML sang Java Object và ngược lại

Mục đích: Chủ đề của bài này giới thiệu về framework JAXB – Java Architecture for XML Binding – hỗ trợ chuyển đổi XML-Schema hay DTD trở thành Java Class, và mapping dữ liệu từ XML sang thành Java Object và ngược lại. Chúng tôi sẽ thực hiện các bước hướng dẫn kết hợp với các ví dụ cụ thể nhằm thể hiện rõ khái niệm và cách sử dụng JAXB trong quá trình xây dựng ứng dụng. Ngoài ra, chúng tôi cung cấp các nội dung nâng cao khác đế ứng dụng trong việc xây dựng phần mềm như là mapping các kiểu dữ liệu trong schema với java class, tạo ra một order hoàn chỉnh phối hợp giữa các object customer – order – orderDetails - … sử dụng JAXB và keyword any trong XML Schema, phối hợp giữa quá trình marshaller XML với XSL để tạo ra tài liệu khác như là HTML.

Yêu cầu về kiến thức cơ bản

JAXB - Java Architecture for XML Binding

  • Nhằm giảm thiểu việc phức tạp trong xây dựng bộ parser sử dụng DOM API và nhằm hỗ trợ việc trao đổi dữ liệu giữa các ngôn ngữ và cấu trúc khác nhau thông qua DTD và XML-Schema, JAXB cung cấp 03 thành phần cơ bản như sau
    • Chuyển đổi từ XML-Schema/DTD thành Java Class – theo cách nghĩ dùng để giao tiếp giữa các ứng dụng với cấu trúc dữ liệu phức tạp thì cấu trúc dữ liệu được mô tả bằng Schema hay DTD. Sau đó, những cấu trúc trung gian này chuyển đi đến các ứng dụng xử lý và chúng sẽ được chuyển đổi thành định dạng object theo ngôn ngữ mà ứng dụng đó đang sử dụng để dễ dàng đón nhận dữ liệu và uyển chuyển trong thay đổi
    • Mapping dữ liệu từ tài liệu XML vào trong các instance của Java Object với dạng tổ chức collection - Unmarshaller
    • Mapping dữ liệu từ Java Object Collection dưới dạng có cấu trúc trở thành tài liệu XML - Marshaller
  • Tuy nhiên, việc chuyển đổi XML-Schema/DTD thành Java Class không phải là mạnh nhất vì nó không hỗ trợ tất cả mọi trường hợp. Do vậy, khuyến cáo chỉ sử dụng cấu trúc DTD với Schema ở cấu trúc Only-Element và mức độ tổ chức tương ứng với tổ chức dữ liệu trên DB theo node root – tên DB, container element – tên table, các element – tên cột tương ứng trong DB
  • Hình vẽ thể kiến tổng quát kiến trúc và cơ chế của JAXB

JAXB_architecture.gif

IBM, http://pic.dhe.ibm.com/infocenter/wasinfo/v7r0/index.jsp?topic=%2Fcom.ibm.websphere.express.doc%2Finfo%2Fexp%2Fae%2Fcwbs_jaxb.html

    • Trong cấu trúc trên, chúng ta thấy XML Schema sẽ thông qua bộ Schema Compiler để chuyển đổi thành Object Factory – class hỗ trợ để tạo ra các instance object class của từng kiểu dữ liệu cụ thể tương ứng với complex type trong schema, JAX-B class chính là class mapping với complex type trong Schema, Package là class chứa thông tin mapping namespace của XML Schema với package của class Java được phát sinh.
    • Ngoài ra, chúng ta nhìn thấy Schema Generator hỗ trợ dịch ngược từ Java Class thành XML Schema – đây là bộ sẵn có của JDK
    • Sau khi có các java class được phát sinh từ Schema với JAXB class, Object Factory class và Package class (Nguyên package java chứa 03 thành phần này được định nghĩa và xem như JAXB Context), nếu đưa XML như Input thì unmarshall sẽ kiểm tra well-formed xml, parse xml và mapping tương ứng node trong tài liệu xml với thuộc tính trong JAXB class để tạo thành các instance JAXB object trên bộ nhớ thông qua các annotation được khai báo trong JAXB class.
    • Ngược lại, khi chúng ta có instance JAXB object thì thông qua Binding framework kết hợp annotation sẽ chuyển đổi – marshaller – toàn bộ object của Collection JAXB Object trở thành tài liệu XML

Schema Generator – chuyển đổi XMLSchema trở thành Java Class

  • Có 02 cách thức thực hiện.
    • Tài liệu XML Schema có cấu trúc như sau

    • Lưu ý, cần validation tài liệu này trước khi xử lý.
    • Trong tài liệu này, chúng ta có thể nhận thấy Complex Type Customer tương ứng với class Customer trong thực tế với các thuộc tính tương ứng
    • Cách thứ 1: Sử dụng tool Netbeans để phát sinh
      • Tạo project bất kỳ. Từ menu File, chọn New File, chọn XML và chọn JAXB Binding

      • Click Next,

      • Click Finish
      • Chương trình sẽ phát sinh ra 03 class Customer, Object Factory và package-info

      • Với class Customer được mapping với complex type trong schema, chúng ta nhận thấy nó là một JavaBean với các annotation mapping với các element tương ứng trong schema

      • Class ObjectFactory là thành phần để có thể tạo ra class Customer gián tiếp hay tạo ra thành phần JAXBElement

      • Class package-info là nơi mapping giữa namespace trong schema được phát sinh với package của class được phát sinh code

      • Khi áp dụng cách này, việc phát sinh code khá nhanh và thuận lợi. Tuy nhiên, khi chúng ta bổ sung thêm code vào java class và thực hiện clean and build toàn bộ ứng dụng thì JAXB Binding tự động kích hoạt lại và phát sinh các thành phần JAXB từ đầu dẫn đến toàn bộ code của chúng ta sẽ bị xóa mất → không tốt khi phát triển thêm các methods cho các object
    • Cách thứ 2: sử dụng code để phát sinh các thành phần JAXB thông qua JDK
      • Tạo method utils để  phát sinh code với giá trị tham số là đường dẫn tập tin schema và vị trí xuất code trong project
      • Ở đây, để thuận lợi cho việc demo tiếp cận thì chúng tôi thực hiện làm trực tiếp vào main class. Quí vị cần xây dựng hàm utils như cách làm trong bài XML DOM để thuận lợi cho việc sử dụng lại

      • Lưu ý: các thư viện cần add vào project là  JAXB xx
      • Ngoài ra, vị trí xuất code được đặt tại giá trị của biến output. Cần lưu ý, code được đặt tại vị trí src nếu sử dụng java project. Nếu sử dụng web project thì đường dẫn output phải là src/java/ (Chúng ta nên sử dụng file Explorer trong Netbeans để tính đường dẫn. Vị trí đường dẫn hiện hành luôn tính từ thư mục chức toàn bộ Project)
      • Đường dẫn của tập tin schema cũng được tính như cách gợi ý ở trên. Code trong hình trên, chúng tôi đặt gọi tập tin schema đặt tại thư mục ngoài cùng của project. Nếu đặt đường dẫn như hình bên dưới thì chúng ta phải truyền là src/customers.xsd

      • Chúng ta thực hiện chạy code, chúng ta sẽ phát sinh được các thành phần component tương tự như dùng JAXBBinding của Netbeans. Tuy nhiên, khi clean and build ứng dụng thì các thành phần phát sinh và bổ sung vẫn còn nguyên không bị phát sinh lại từ đầu, trừ khi chúng ta gọi lại hàm mới vừa xây dựng → nên áp dụng trong việc xây dựng ứng dụng

Unmarshaller

  • Quá trình chuyển đổi hay mapping tài liệu XML trở thành Java Object trên bộ nhớ theo cấu trúc dạng cây – không phải là cây DOM

  • Các bước thực hiện
    • Tạo JAXBContext
      • JAXBContext là nơi xác định các thành phần cấu hình để JAXB có thể lấy thông tin trong quá trình chuyển đổi, cụ thể ở đây là các class phát sinh từ complex type trong schema, Object Factory và package-info
      • JAXBContext dạng rút gọn là chỉ cần xác định class sử dụng các annotation của JAXB, cụ thể là class được phát sinh từ complex type trong schema (ví dụ: Customers)

Phương thức

Đặc tả

newInstance

public static JAXBContext newInstance (“packageName”) throws JAXBException

newInstance

public static JAXBContext newInstance (Class… classesToBeBound) throws JAXBException

 

    • Sau khi có được JAXBContext, chúng ta sẽ tạo ra đối tượng Unmarshaller
      • Đây là đối tượng cung cấp api để hỗ trợ chúng ta chuyển đổi, đặc biệt là phương thức unmarshal

Phương thức

Đặc tả

createUnmarshaller

public abstract Unmarshaller createUnmarshaller() throws JAXBException

unmarshal

-       Object unmarshal (File f) throws JAXBException – unmarshall từ file

-       Object unmarshal (InputStream is) throws JAXBException – unmarshall từ stream

-       Object unmarshal (URL url) throws JAXBException – unmarshall từ đường dẩn url bất kỳ

-       Object unmarshal (Node node) throws JAXBException – unmarshall từ cây DOM

-       Object unmarshal (Source src) throws JAXBException – unmarshall từ một source dạng bất kỳ có cấy trúc cây

-       Object unmarshal (XMLEventReader/XMLStreamReader src) throws JAXBException – unmarshall từ một StAX

-      

      • Phương thức này hỗ trợ chúng ta chuyển đổi từ file đến cây DOM, StAX parser đến input source bất kỳ để convert thành dạng cây (Content Tree nhưng không phải là DOM)
      • Hình ảnh thể hiện cơ chế tổng quát của quá trình unmarshal như sau

Unmarshaller.gif

Figure 4-4, Java & XML Data Binding, Brett McLaughlin

        • Cơ chế đã được thể hiện qua hình, cụ thể khi đã có tài liệu XML và JAXB Object, với yêu cầu unmarshal, JAXB sẽ thực hiện Parse tài liệu XML sử dụng bộ XML Scanner.
        • Dữ liệu sau khi parse xong, sẽ được chuyển đến JAXB thông qua các annotation được khai báo trong JAXB class, JAXB sẽ xác định element hay attribute, … được mapping với properties nào trong JAXB Class. Một số Annotation được thể hiện trong bảng bên dưới

Annotations

Descriptions

XmlValue

Maps Java class hay kiểu enum với complex type

XmlType

Maps Java class với kiểu dữ liệu simple hay complex trong schema

XmlSchema

Maps package name của Java class với namespace trong schema

XmlRootElement

Maps Java class hay kiểu enum type với XML element

XmlList

Maps với property của java class với kiểu list trong Schema

XmlEnum

Maps kiểu dữ liệu enum với tập dữ liệu được lựa chọn trong Schema

XmlElement

Maps JavaBean property với một XML Element

XmlAttribute

Maps JavaBean property với attribute trong tài liệu XML

        • JAXB thực hiện khởi tạo instance JAXB trong bộ nhớ và nạp dữ liệu tương ứng vào các JAXB và construct thành các cấu trúc dữ liệu dưới dạng cây được tổ chức trong java.
        • Kết thúc quá trình unmarshal
  • Ví dụ: mapping tài liệu XML với thành phần class Customer đã được phát sinh ở phần SchemaGenerator bên trên
    • Tài liệu XML

    • Bổ sung XMLRootELement vào class Customer và xác định tên element tương ứng trong schema

    • Viết code thực hiện các bước đã nêu để unmarshal

      • Lưu ý: cần xác định đường dẫn tập tin customers.xml để cho kết quả khi chạy ứng dụng. Bên cạnh đó, cần xây dựng hàm utilities để sử dụng chức năng này tại thời điểm runtime
    • Kết quả khi chạy

    • Chúng ta vừa hoàn tất việc unmarshal cơ bản nhất cho một tài liệu chỉ có duy nhất một Element
  • Ví dụ: thực hiện unmarshaling với tài liệu phức tạp theo nghĩa là một object bên trong property của nó sẽ chứa một collection của một kiểu dữ liệu object khác – tương ứng với mô hình cây được tổ chức trong cấu trúc dữ liệu
    • Tài liệu XML Schema

      • Chúng ta sẽ thấy element persons chứa nhiều person – kiểu person Type
    • Sử dụng SchemaGenerator chúng ta sẽ có 4 class như sau

      • Class PersonType

      • Class Person

    • Tài liệu XML cần unmarshal

    • Code thực hiện unmarshal

    • Kết quả thực hiện

Marshaller

  • Quá trình chuyển đổi các java object được tổ chức theo cấu trúc cây (content tree) trở thành tài liệu XML dưới dạng file hay dạng SAX, StAX, DOM …

  • Các bước thực hiện
    • Xác định JAXBContext – tương tự như unmarshal
    • Tạo đối tượng Marshaller
    • Input cấu trúc dữ liệu thông qua cung cấp các object để thực hiện gọi phương thức marshal trên đối tượng Marshaller

Phương thức

Đặc tả

createMarshaller

public abstract Marshaller createMarshaller() throws JAXBException

marshal

·         void marshal(Object root,ContentHandler h)throws JAXBException – tạo ra SAX

·         void marshal (Object root, Node node) throws JAXBException – tạo ra DOM

·         void marshal (Object jaxbElement, XMLStreamWriter|file writer) throws JAXBException – tạo StAX hay file

·         ..

setProperty

·         void setProperty(String name, Object value) throws PropertyException

·         hỗ trợ format định dạng khi xuất kết quả

    • Ví dụ: thực hiện ví dụ để convert object Persons trong ví dụ ở phần UnMarshaller để chuyển thành file XML
      • Code để thực hiện Marshal

      • Kết quả được thực thi

    • Chúng ta đã hoàn tất được quá trình marshal
  • Marshaller có sự khác biệt đối với Unmarshaller là Unmarshaller hỗ trợ quá trình validation dữ liệu khi đưa dữ liệu từ tài liệu XML vào object. Còn đối với Marshaller, validation dữ liệu đã được xử lý liên quan đến kiểu dữ liệu được khai báo trong class và quá trình cấp phát bộ nhớ cho object cùng với việc bắt ràng buộc trực tiếp trên code nên Marshaller không hỗ trợ việc validation dữ liệu

Tổng quát, trong thực tế, các tài liệu XML được xử lý trong API đều được xem như là một qualified name. Do vậy, việc mapping dữ liệu đòi hỏi phải xác định rõ namespace cùng với prefix tương ứng để mapping giữa tài liệu XML, package class trong java và namespace trong schema

  • Để thực hiện điều đó, chúng ta chỉ cần cập nhật bổ sung cho tập tin class package-info như ví dụ bên dưới

    • Chúng ta đang mapping với namespace customer như default namespace và customerDetail với namespace có prefix là test
    • Điều này sẽ hỗ trợ chúng ta trong việc nhúng nhiều tài liệu xml vào nhau và hỗ trợ việc xác định rõ ngữ nghĩa của các element để tránh xung đột theo cách hiểu cùng tên element nhưng khác nghĩa

Case Study: Ứng dụng kiểu dữ liệu simpleContent của Schema (một element có thân là kiểu chuỗi, có hay không có attribute) với Java class

  • Mapping kiểu dữ liệu phone number thể hiện các dạng số điện thoại khác nhau như số nhà, số công việc, … và attribute của nó chính là số điện thoại. Thiết kế sẽ hướng tới việc dấu ẩn số phone mà chỉ trình bày mục đích, khi nào người dùng thực sự mới thấy được số phone thông qua attribute
  • Tập tin XML Schema có dạng như sau

  • Tạo java class để mapping trực tiếp schema. Ở đây, chúng tôi không tạo bằng code hay tool mà trực tiếp tạo một Java Class để thể hiện tính thuận lợi của JAXB theo ngữ nghĩa, JAXB object chỉ là một Java Class gắn thêm các annotation của JAXB và không cần thiết phải có object Factory và package-info
    • Mapping thuộc tính number trong java class với @Attribute thể hiện giá trị đó sẽ được mapping thành attribute trong xml/xml schema
    • Mapping một thuộc tính bất kỳ trong java class với @XMLValue để thể hiện đó sẽ là giá trị phần thân trong element của xml. Nếu không thể hiện điều này, JAXB coi thuộc tính đó như là một element
    • Mapping @XMLRootElement với tên root name của tài liệu XML tại vị trí khai báo class để định nghĩa kiểu dữ liệu và tên element khi phát sinh tương ứng với XML Schema
    • Class được implement như sau

  • Thực hiện implement code marshaller để chuyển đổi object trở thành dạng XML ứng dụng cho kiểu complex type trong XML Schema cho phép chứa chuỗi trong thân cùng chứa attribute

  • Kết quả thực thi chúng ta có được tập tin xml như sau

Case Study: Xây dựng một order hoàn chỉnh dạng xml kết hợp từ các object riêng biệt

  • Nội dung này hướng tới xây dựng một order kết xuất dạng xml để có thể apply xsl và sử dụng pdf để xuất ra dạng report
  • Tuy nhiên, quá trình truy vấn và thực hiện dữ liệu theo các tổ chức của DB thì chúng ta có được các object như là user customer, order và order details, và product, …. Các object này riêng biệt và chúng ta cần phối hợp với nhau để tạo thành order khi xuất. Theo cách thức thông thường, chúng ta sẽ tốn một chút công sức
  • Tận dụng tính tối ưu trong XML Schema có chứa keyword any cho phép chúng ta nhúng một XML fragment hay XML Element bất kỳ cùng với sự hỗ trợ marshaller của JAXB kết hợp ngữ nghĩa nghiệp vụ về bán hàng là một người dùng có nhiều order, một order lại có nhiều order details → diển dịch theo nghĩa user/customer có any và any đó có any bất kỳ cái khác, cứ như thế ….
  • Chúng ta tạo 03 schema như sau
    • Account schema mô tả thông tin người dùng có có chứa any thứ bất kỳ

    • Order Schema mô tả cho Order của một người dùng chứa any bất kỳ cái khác

    • Order Details schema mô tả kiểu dữ liệu details hay kiểu cuối cùng được chứa

  • Sử dụng JAXB theo các cách đã mô tả trong lý thuyết để phát sinh các thành phần java class tương ứng

  • Viết code để thực hiện việc tạo ra order với dạng xml từ các object đã tạo ra ở trên

  • Thực thi code, chúng ta có kết quả như sau (Lưu ý: cần compile tất các class JAXB trước khi thực thi code)

Case Study: Sử dụng JAXB kết hợp với XSL nhằm apply kết xuất XML với XSL

  • Mục đích của nội dung này là thay vì xuất ra file XML lưu trữ, chúng ta thực hiện lấy kết xuất của XML ngay trên bộ nhớ của JAXB apply ngay XSL để đưa ra kết quả cho người sử dụng
  • Với sự hỗ trợ của bộ XSLT – TrAX API chuyển đổi từ định dạng Source bất kỳ thành Result thì JAXB được coi là dạng Source với kiểu là JAXBSource hỗ trợ apply trực tiếp với XSLT
  • Các JAXB object chứa dữ liệu được làm trực tiếp có định dạng như sau
    • Class DTO

    • Class DTOList chứa DTO

  • Tập tin XSL để apply và trình bày giao diện

  • Cấu trúc đang được chứa trong project

  • Xây dựng code để chuyển đổi JAXB và apply XSL

  • Kết quả thực thi, chúng ta có được tập tin html như sau

Chúc mừng các bạn đã hoàn tất và nắm các khái niệm về sử dụng JAXBnâng cao kiến thức thông qua một số Case Study có thể áp dụng trong việc xây dựng phần mềm. Chúng ta sẽ áp dụng các khái niệm này trong các nội dung tiếp theo khi kết hợp các thành phần công nghệ Java liên quan đến XML trong xây dựng ứng dụng phần mềm

Chúng tôi hy vọng nội dung của bài này giúp ích quí vị.

Rất mong sự góp ý chân thành và chia sẻ của quí vị về vấn đề này. Hẹn gặp lại quý vị ở các chủ đề khác liên quan đến XML.

Không có nhận xét nào:

Đăng nhận xét