2015-02-16 14 views
6

Tôi muốn đọc một tài liệu YAML tới một bản đồ các đối tượng tùy chỉnh (thay vì bản đồ, mà snakeYaml làm theo mặc định). Vì vậy, đây:Phân tích cú pháp tài liệu YAML bằng một bản đồ ở gốc bằng cách sử dụng snakeYaml

19: 
    typeID: 2 
    limit: 300 
20: 
    typeID: 8 
    limit: 100 

sẽ được nạp vào một bản đồ mà trông như thế này:

Map<Integer, Item> 

nơi Item là:

class Item { 
    private Integer typeId; 
    private Integer limit; 
} 

tôi không thể tìm thấy một cách để làm điều này với snakeYaml và tôi cũng không tìm thấy thư viện nào tốt hơn cho tác vụ này.

Các tài liệu chỉ có ví dụ với bản đồ/bộ sưu tập lồng vào bên trong các đối tượng khác, vì vậy mà bạn có thể làm như sau:

TypeDescription typeDescription = new TypeDescription(ClassContainingAMap.class); 
    typeDescription.putMapPropertyType("propertyNameOfNestedMap", Integer.class, Item.class); 
    Constructor constructor = new Constructor(typeDescription); 
    Yaml yaml = new Yaml(constructor); 
    /* creating an input stream (is) */ 
    ClassContainingAMap obj = (ClassContainingAMap) yaml.load(is); 

Nhưng làm thế nào để tôi đi về định dạng Map khi nó là cội rễ của tài liệu?

Trả lời

2

Bạn cần thêm Constructor tùy chỉnh. Tuy nhiên, trong trường hợp của bạn, bạn không muốn đăng ký một thẻ "item" hoặc "item-list".

Thực tế, bạn muốn áp dụng Duck Typing cho Yaml của mình. Nó không phải là siêu hiệu quả, nhưng có một cách tương đối dễ dàng để làm điều này.

class YamlConstructor extends Constructor { 
    @Override 
    protected Object constructObject(Node node) { 

    if (node.getTag() == Tag.MAP) { 
     LinkedHashMap<String, Object> map = (LinkedHashMap<String, Object>) super 
       .constructObject(node); 
     // If the map has the typeId and limit attributes 
     // return a new Item object using the values from the map 
     ... 
    } 
    // In all other cases, use the default constructObject. 
    return super.constructObject(node); 
+6

Wow, hỗ trợ YAML trong Java đang bị trì hoãn. Trong khi giải pháp này hoạt động, nó sẽ là một nhức đầu khi phải đối phó với các cấu trúc lồng nhau. Tôi đoán tôi sẽ chuyển đổi mọi thứ thành JSON và sử dụng Jackson để phân tích cú pháp. – Justas

+0

Có. Phân tích cú pháp của Yaml trong java (/ scala) * là * khủng khiếp. Đến từ python, nơi nó là "miễn phí". – javadba

3

Đây là những gì tôi đã làm cho một tình huống rất giống nhau. Tôi chỉ cần gắn thẻ toàn bộ tệp yml của mình lên một tab và thêm thẻ bản đồ: lên trên cùng. Vì vậy, đối với trường hợp của bạn nó sẽ được.

map: 
    19: 
    typeID: 2 
    limit: 300 
    20: 
    typeID: 8 
    limit: 100 

Sau đó tạo lớp tĩnh trong lớp của bạn đọc tệp này như sau.

static class Items { 
    public Map<Integer, Item> map; 
} 

Sau đó đọc bản đồ của bạn chỉ cần sử dụng.

Yaml yaml = new Yaml(new Constructor(Items)); 
Items items = (Items) yaml.load(<file>); 
Map<Integer, Item> itemMap = items.map; 

UPDATE:

Nếu bạn không muốn hoặc không thể chỉnh sửa tệp yml của bạn, bạn có thể chỉ làm biến đổi trên trong mã trong khi đọc các tập tin với một cái gì đó như thế này.

try (BufferedReader br = new BufferedReader(new FileReader(new File("example.yml")))) { 
    StringBuilder builder = new StringBuilder("map:\n"); 
    String line; 
    while ((line = br.readLine()) != null) { 
     builder.append(" ").append(line).append("\n"); 
    } 

    Yaml yaml = new Yaml(new Constructor(Items)); 
    Items items = (Items) yaml.load(builder.toString()); 
    Map<Integer, Item> itemMap = items.map; 
} 
+0

Điều này thực sự thực sự thông minh nếu bạn đồng ý với việc sửa đổi hoặc tạo các tệp của riêng bạn. – Justas

+0

Xem cập nhật ở trên để biết cách thực hiện thủ thuật tương tự mà không phải sửa đổi tệp cơ bản. – crowmagnumb

+0

Đây là một hack khá nhiều. Nhưng nó đập ra * bất cứ điều gì khác * Tôi đã nhìn thấy để phân tích cú pháp yaml bởi java (scala thực sự trong trường hợp của tôi!). Được thăng hạng. – javadba

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