2014-08-18 12 views
8

chciałbym mieć pliki YAML z obejmują, podobne do tego pytania, ale z Snakeyaml: How can I include an YAML file inside another?Dołącz pliki YAML z snakeyaml

Na przykład:

%YAML 1.2 
--- 
!include "load.yml" 

!include "load2.yml" 

mam dużo kłopoty z tym. Mam zdefiniowany Konstruktor i mogę go zaimportować jeden dokument, ale nie dwa. Otrzymuję błąd:

Exception in thread "main" expected '<document start>', but found Tag 
in 'reader', line 5, column 1: 
    !include "load2.yml" 
    ^

Z jednym z nich, Snakeyaml jest szczęśliwy, że znajduje EOF i przetwarza import. Przy dwóch nie jest szczęśliwy (powyżej).

Moje źródło Java jest:

package yaml; 
import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.InputStream; 

import org.yaml.snakeyaml.Yaml; 
import org.yaml.snakeyaml.constructor.AbstractConstruct; 
import org.yaml.snakeyaml.constructor.Constructor; 
import org.yaml.snakeyaml.nodes.Node; 
import org.yaml.snakeyaml.nodes.ScalarNode; 
import org.yaml.snakeyaml.nodes.Tag; 

public class Main { 
    final static Constructor constructor = new MyConstructor(); 

    private static class ImportConstruct extends AbstractConstruct { 
     @Override 
     public Object construct(Node node) { 
      if (!(node instanceof ScalarNode)) { 
       throw new IllegalArgumentException("Non-scalar !import: " + node.toString()); 
      } 

      final ScalarNode scalarNode = (ScalarNode)node; 
      final String value = scalarNode.getValue(); 

      File file = new File("src/imports/" + value); 
      if (!file.exists()) { 
       return null; 
      } 

      try { 
       final InputStream input = new FileInputStream(new File("src/imports/" + value)); 
       final Yaml yaml = new Yaml(constructor); 
       return yaml.loadAll(input); 
      } catch (FileNotFoundException ex) { 
       ex.printStackTrace(); 
      } 
      return null; 
     } 
    } 

    private static class MyConstructor extends Constructor { 
     public MyConstructor() { 
      yamlConstructors.put(new Tag("!include"), new ImportConstruct()); 
     } 
    } 

    public static void main(String[] args) { 
     try { 
      final InputStream input = new FileInputStream(new File("src/imports/example.yml")); 
      final Yaml yaml = new Yaml(constructor); 
      Object object = yaml.load(input); 
      System.out.println("Loaded"); 

     } catch (FileNotFoundException ex) { 
      ex.printStackTrace(); 
     } 
     finally { 
     } 
    } 
} 

Pytanie jest, czy ktoś zrobił coś podobnego z Snakeyaml? Jakieś myśli o tym, co robię źle?

+0

p.s. dzięki za zamieszczenie tego pytania; dało mi to przewagę w obsłudze tagu '! include'. –

Odpowiedz

2

Widzę dwa problemy:

final InputStream input = new FileInputStream(new File("src/imports/" + value)); 
      final Yaml yaml = new Yaml(constructor); 
      return yaml.loadAll(input); 

Należy używać yaml.load(input) nie yaml.loadAll(input). Metoda loadAll() zwraca wiele obiektów, ale metoda construct() oczekuje, że zwróci pojedynczy obiekt.

Innym problemem jest to, że może masz jakieś niespójne oczekiwania z okazji, że YAML processing pipeline utwory:

Jeśli uważasz, że Twoje !include działa jak w C, gdzie patyki preprocesora w treści załączony plik, sposobem na jego wdrożenie byłoby obsłużenie go na etapie Prezentacja (parsowanie) lub Serializacja (komponowanie). Ale zaimplementowałeś go na etapie reprezentacji (konstruowania), więc !include zwraca obiekt, a struktura twojego pliku YAML musi być zgodna z tym.

Powiedzmy, że masz następujące pliki:

test1a.yaml

activity: "herding cats" 

test1b.yaml

33 

test1.yaml

favorites: !include test1a.yaml 
age:  !include test1b.yaml 

to będzie działać ok, i wou ld być równoważne

favorites: 
    activity: "herding cats" 
age: 33 

Ale następujący plik nie będzie działać:

!include test1a.yaml 
!include test1b.yaml 

bo nie ma nic do powiedzenia, jak połączyć dwie wartości w większej hierarchii.trzeba by to zrobić, jeśli chcesz tablicy:

- !include test1a.yaml 
- !include test1b.yaml 

lub znowu obsługiwać ten niestandardowy logikę we wcześniejszym etapie, takich jak parsowanie lub komponowania.

Alternatywnie, musisz poinformować bibliotekę YAML, że uruchamiasz drugi dokument (na co składa się ten błąd: expected '<document start>'), ponieważ YAML obsługuje wiele "dokumentów" (wartości najwyższego poziomu) w jednym .yaml plik.