2014-08-18 4 views
8

Ich möchte YAML-Dateien mit einer Include, ähnlich wie diese Frage haben, aber mit SnakeYAML: How can I include an YAML file inside another?Fügen Sie YAML-Dateien von SnakeYAML

Zum Beispiel:

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

!include "load2.yml" 

ich viel habe Ärger damit. Ich habe den Konstruktor definiert und kann ein Dokument importieren, aber nicht zwei. Der Fehler, den ich bekommen ist:

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

Mit einem gehören, SnakeYAML glücklich ist, dass es ein EOF findet und verarbeitet den Import. Mit zwei ist es nicht glücklich (oben).

Meine Java-Quelle ist:

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 { 
     } 
    } 
} 

Frage ist, hat jemand getan, um eine ähnliche Sache mit SnakeYAML? Irgendwelche Gedanken darüber, was ich falsch machen könnte?

+0

p.s. Danke für das Posten dieser Frage; es gab mir einen Vorsprung für die Unterstützung eines '! include'-Tags. –

Antwort

2

Ich sehe zwei Probleme:

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

sollten Sie yaml.load(input) verwenden, nicht yaml.loadAll(input). Die Methode loadAll() gibt mehrere Objekte zurück, aber die Methode construct() erwartet, dass ein einzelnes Objekt zurückgegeben wird.

Das andere Problem ist, dass Sie einige inkonsistenten Erwartungen mit der Art und Weise haben, dass die YAML processing pipeline Werke:

Wenn Sie denken, dass Ihr !include funktioniert wie in C, wo die Vorprozessor-Sticks in dem Inhalt der die mitgelieferte Datei, wäre die Art und Weise, es zu implementieren, in der Präsentationsstufe (Parsing) oder Serialisierungsstufe (Composing) zu handhaben. Aber Sie haben es in der Darstellungsphase implementiert (Konstruieren), also gibt !include ein Objekt zurück, und die Struktur Ihrer YAML-Datei muss damit konsistent sein.

Lasst uns sagen, dass Sie die folgenden Dateien:

test1a.yaml

activity: "herding cats" 

test1b.yaml

33 

test1.yaml

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

Diese funktionieren würde ok, und du?

!include test1a.yaml 
!include test1b.yaml 

, weil es nichts zu sagen, wie die beiden Werte in einer größeren Hierarchie zu kombinieren: ld

favorites: 
    activity: "herding cats" 
age: 33 

Aber die folgende Datei nicht funktionieren würde gleichwertig sein.Sie würden dies tun müssen, wenn Sie einen Array wollen:

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

oder wiederum behandeln diese kundenspezifische Logik in einem früheren Stadium wie Parsing oder Komponieren.

Alternativ müssen Sie der YAML-Bibliothek mitteilen, dass Sie ein zweites Dokument starten (worüber sich der Fehler beschweren kann: expected '<document start>'), da YAML mehrere "Dokumente" (Höchstwerte) in einer einzelnen .yaml unterstützt Datei.