2014-08-18 11 views
8

Mi piacerebbe avere file YAML con un include, simili a questa domanda, ma con Snakeyaml: How can I include an YAML file inside another?Includere file YAML da snakeyaml

Ad esempio:

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

!include "load2.yml" 

Sto avendo un sacco di guai con esso. Ho definito il Costruttore e posso farlo importare un documento, ma non due. L'errore che ottengo è:

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

Con un comprendono, Snakeyaml è felice che trova un EOF ed elabora l'importazione. Con due, non è felice (sopra).

La mia fonte è java:

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

domanda è, qualcuno ha fatto una cosa simile con Snakeyaml? Qualche idea su cosa potrei fare male?

+0

p.s. grazie per aver postato questa domanda; mi ha dato un vantaggio per il supporto di un tag '! include'. –

risposta

2

vedo due questioni:

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

Si deve usare yaml.load(input), non yaml.loadAll(input). Il metodo loadAll() restituisce più oggetti, ma il metodo construct() prevede di restituire un singolo oggetto.

L'altro problema è che si può avere alcune aspettative incoerenti con il modo in cui le YAML processing pipeline opere:

Se pensate che i vostri !include opere come in C, dove i bastoni preprocessore nel contenuto di il file incluso, il modo per implementarlo sarebbe gestirlo nello stage di presentazione (analisi) o nella fase di serializzazione (composizione). Ma lo hai implementato nella fase di Rappresentazione (costruzione), quindi !include restituisce un oggetto e la struttura del tuo file YAML deve essere coerente con questo.

Diciamo che avete i seguenti file:

test1a.yaml

activity: "herding cats" 

test1b.yaml

33 

test1.yaml

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

Questo potrebbe funzionare ok, e tu Ld equivalente a

favorites: 
    activity: "herding cats" 
age: 33 

Ma il seguente file non funzionerebbe:

!include test1a.yaml 
!include test1b.yaml 

perché non c'è nulla da dire come combinare i due valori in una gerarchia più grande.Avresti bisogno di fare questo, se si vuole un array: nuovo

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

o,, gestire questa logica personalizzata in una fase precedente, come l'analisi e composizione.

In alternativa, è necessario indicare alla libreria YAML che si sta avviando un secondo documento (che è l'errore si lamenta: expected '<document start>') poiché YAML supporta più "documenti" (valori di livello superiore) in un singolo .yaml file.