2012-03-31 30 views
6

Giả sử tôi có một API REST trong java và nó hỗ trợ các phản hồi bằng JSON hoặc XML. Các câu trả lời chứa cùng một dữ liệu, nhưng biểu mẫu không giống nhau. Ví dụ, trong json tôi có thể có:hỗ trợ cả phản hồi REST xml và json trong clojure

{ 
    "persons": [ 
     { 
      "name":"Bob", 
      "age":24, 
      "hometown":"New York" 
     } 
    ] 
} 

Trong khi đó trong XML nó trông như thế này:

<persons> 
    <person name="bob" age="24"> 
     <hometown>New York</hometown> 
    </person> 
</persons> 

Đó là để nói rằng một số giá trị là thuộc tính trên người, và những người khác là những yếu tố con. Trong Java, sử dụng JAXB và Jackson, thật dễ dàng để che giấu sự khác biệt như vậy với các chú thích trên các đối tượng mô hình, ví dụ:

public class Person { 
    @XmlAttribute 
    String name; 

    @XmlAttribute 
    Integer age; 

    @XmlElement 
    String hometown; 
} 

JAXB đọc chú thích, và Jackson sử dụng tên trường để tìm ra những việc cần làm. Vì vậy, với một mô hình duy nhất thật dễ dàng để hỗ trợ nhiều định dạng đầu ra.

Vì vậy, câu hỏi của tôi là, cách thực hiện điều tương tự trong clojure. Tôi biết rằng có clj-json có thể dễ dàng chuyển đổi bản đồ clojure và vectơ thành json (sử dụng jackson nếu tôi không nhầm lẫn). Và tôi biết có cả clojure.xml.emit và clojure.contrib.xml.prxml có thể deserialize bản đồ & vectơ thành XML. Nhưng trừ khi tôi nhầm, tôi không nghĩ hai người này sẽ làm việc với nhau rất tốt.

Vì prxml mong các nút xml được biểu diễn dưới dạng vectơ và các thuộc tính xml được biểu diễn dưới dạng bản đồ, về cơ bản khác với hoạt động của clj-json, nơi các vectơ đại diện cho mảng và bản đồ đại diện cho các đối tượng. Và clojure.core.emit mong đợi một bản đồ ở dạng {:tag :person :attrs {:name "Bob" :age 24} :content ...}, một lần nữa hoàn toàn khác với những gì clj-json muốn. Điều duy nhất tôi có thể nghĩ là định dạng cấu trúc dữ liệu cho prxml trong mã của tôi, và sau đó viết một hàm chuyển đổi cấu trúc dữ liệu thành những gì clj-json muốn khi kiểu phản hồi là JSON. Nhưng điều đó có vẻ hơi xấu hổ. Tôi thích nếu có một cặp thư viện JSON và XML tương thích theo cách JAXB và Jackson.

Ý tưởng?

+0

Có thể xem [data.xml] mới (https://github.com/clojure/data.xml)? – Jeremy

+0

dường như vẫn yêu cầu dữ liệu phải được định dạng như clojure.xml mong đợi, ví dụ: '{: tag: person: attrs {: name" Bob ": tuổi 24}: nội dung ...}'. – Kevin

+0

Tôi chưa sử dụng data.xml, nhưng suy nghĩ của tôi là có thể xây dựng trình phát của riêng bạn để viết ra XML như bạn muốn. Tôi không chắc chắn 100%. – Jeremy

Trả lời

5

Rất nhiều phụ thuộc vào cách bạn chọn để đại diện cho các mô hình trong mã của mình.

Giả sử bạn sử dụng hồ sơ. Dưới đây là ví dụ về cách bạn có thể "chú thích" một bản ghi và cung cấp các trình tuần tự hóa cho XML và JSON.

;; Depends on cheshire and data.xml 
(ns user 
    (:require [cheshire.core :as json] 
      [clojure.data.xml :as xml])) 

(defrecord Person [name age hometown]) 
(defrecord Animal [name sound]) 

(def xml-attrs {Person [:name :age] 
       Animal [:name]}) 

(defn record->xml-data [rec] 
    (let [tag (-> rec class .getSimpleName .toLowerCase keyword) 
     attrs (select-keys rec (xml-attrs (class rec))) 
     content (for [[k v] rec 
         :when (not (contains? attrs k))] 
        (xml/element k nil (str v)))] 
    (apply xml/element tag attrs content))) 

(defn record->xml [rec] 
    (xml/emit-str (record->xml-data rec))) 

(defn record->json [rec] 
    (json/generate-string rec)) 

Cách sử dụng:

> (def bob (Person. "Bob" 24 "New York")) 
#'user/bob 

> (println (record->xml bob)) 
<?xml version="1.0" encoding="UTF-8"?><person age="24" name="Bob"><hometown>New York</hometown></person> 
nil 

> (println (record->json bob)) 
{"name":"Bob","age":24,"hometown":"New York"} 
nil 

> (println (record->xml (Animal. "Fido" "Bark!"))) 
<?xml version="1.0" encoding="UTF-8"?><animal name="Fido"><sound>Bark!</sound></animal> 
nil 

Một vĩ mô có thể được tạo ra để xác định mức kỷ lục và các thuộc tính XML của nó trong một tuyên bố singe. Ví dụ:

(defrecord-xml Person [^:xml-attr name ^:xml-attr age hometown]) 
+0

rất đẹp, cảm ơn. – Kevin

Các vấn đề liên quan