Domanda

Così ho due file YAML, "A" e "B" e voglio che il contenuto di Un essere inserita all'interno di B, sia impiombato nella struttura di dati esistenti, come un array, o come un bambino di un elemento, come il valore di un determinato tasto cancelletto.

Questo è possibile a tutti?Come?Se non, tutti i puntatori di un riferimento normativo?

È stato utile?

Soluzione

No, YAML non include alcun tipo di "importazione" o "include" dichiarazioni.

Altri suggerimenti

La tua domanda non chiede una soluzione Python, ma qui è uno che utilizza PyYAML .

PyYAML permette di collegare i costruttori personalizzata (ad esempio !include) per il caricatore YAML. Ho incluso una directory principale che può essere impostato in modo tale che questa soluzione supporta riferimenti ai file relativi e assoluti.

Classe-Based Solution

Ecco una soluzione di classe, che evita la variabile radice globale della mia risposta originale.

Gist per una simile, più robusto Python 3 soluzione che utilizza un metaclasse per registrare il costruttore personalizzato.

import yaml
import os

class Loader(yaml.SafeLoader):

    def __init__(self, stream):

        self._root = os.path.split(stream.name)[0]

        super(Loader, self).__init__(stream)

    def include(self, node):

        filename = os.path.join(self._root, self.construct_scalar(node))

        with open(filename, 'r') as f:
            return yaml.load(f, Loader)

Loader.add_constructor('!include', Loader.include)

Un esempio:

foo.yaml

a: 1
b:
    - 1.43
    - 543.55
c: !include bar.yaml

bar.yaml

- 3.6
- [1, 2, 3]

Ora i file possono essere caricati utilizzando:

>>> with open('foo.yaml', 'r') as f:
>>>    data = yaml.load(f, Loader)
>>> data
{'a': 1, 'b': [1.43, 543.55], 'c': [3.6, [1, 2, 3]]}

Se si utilizza la versione di Symfony di YAML , questo è possibile, in questo modo:

imports:
    - { resource: sub-directory/file.yml }
    - { resource: sub-directory/another-file.yml }

Include non sono supportati direttamente in YAML per quanto ne so, si dovrà fornire un meccanismo da soli però, che in genere è facile da fare.

Ho usato YAML come linguaggio di configurazione in mie applicazioni python, e in questo caso spesso di definire una convenzione in questo modo:

>>> main.yml <<<
includes: [ wibble.yml, wobble.yml]

Poi, nel mio codice (Python) che faccio:

import yaml
cfg = yaml.load(open("main.yml"))
for inc in cfg.get("includes", []):
   cfg.update(yaml.load(open(inc)))

L'unico lato negativo è che le variabili nel include sempre ignorare le variabili principali, e non v'è alcun modo per cambiare la situazione modificando la precedenza dove il "include: dichiarazione compare nel file main.yml

.

Su un punto leggermente diverso, YAML non supporta comprende come la sua non realmente progettato come come esclusivamente come un file in base mark up. Cosa sarebbe un include media se avete capito bene in una risposta ad una richiesta AJAX?

Ampliando @ risposta di Josh_Bode, ecco la mia propria soluzione PyYAML, che ha il vantaggio di essere una sottoclasse autonomo di yaml.Loader. Essa non dipende da alcuna globali a livello di modulo, o modificare lo stato globale del modulo yaml.

import yaml, os

class IncludeLoader(yaml.Loader):                                                 
    """                                                                           
    yaml.Loader subclass handles "!include path/to/foo.yml" directives in config  
    files.  When constructed with a file object, the root path for includes       
    defaults to the directory containing the file, otherwise to the current       
    working directory. In either case, the root path can be overridden by the     
    `root` keyword argument.                                                      

    When an included file F contain its own !include directive, the path is       
    relative to F's location.                                                     

    Example:                                                                      
        YAML file /home/frodo/one-ring.yml:                                       
            ---                                                                   
            Name: The One Ring                                                    
            Specials:                                                             
                - resize-to-wearer                                                
            Effects: 
                - !include path/to/invisibility.yml                            

        YAML file /home/frodo/path/to/invisibility.yml:                           
            ---                                                                   
            Name: invisibility                                                    
            Message: Suddenly you disappear!                                      

        Loading:                                                                  
            data = IncludeLoader(open('/home/frodo/one-ring.yml', 'r')).get_data()

        Result:                                                                   
            {'Effects': [{'Message': 'Suddenly you disappear!', 'Name':            
                'invisibility'}], 'Name': 'The One Ring', 'Specials':              
                ['resize-to-wearer']}                                             
    """                                                                           
    def __init__(self, *args, **kwargs):                                          
        super(IncludeLoader, self).__init__(*args, **kwargs)                      
        self.add_constructor('!include', self._include)                           
        if 'root' in kwargs:                                                      
            self.root = kwargs['root']                                            
        elif isinstance(self.stream, file):                                       
            self.root = os.path.dirname(self.stream.name)                         
        else:                                                                     
            self.root = os.path.curdir                                            

    def _include(self, loader, node):                                    
        oldRoot = self.root                                              
        filename = os.path.join(self.root, loader.construct_scalar(node))
        self.root = os.path.dirname(filename)                           
        data = yaml.load(open(filename, 'r'))                            
        self.root = oldRoot                                              
        return data                                                      

Per gli utenti di Python, si può provare pyyaml-includono.

Installare

pip install pyyaml-include

Utilizzo

import yaml
from yamlinclude import YamlIncludeConstructor

YamlIncludeConstructor.add_to_loader_class(loader_class=yaml.FullLoader, base_dir='/your/conf/dir')

with open('0.yaml') as f:
    data = yaml.load(f, Loader=yaml.FullLoader)

print(data)

Considerare l'abbiamo YAML file:

├── 0.yaml
└── include.d
    ├── 1.yaml
    └── 2.yaml
  • 1.yaml contenuti:
name: "1"
  • 2.yaml contenuti:
name: "2"

Includere i file per nome

  • Sul livello superiore:

    Se 0.yaml stato:

!include include.d/1.yaml

Otteniamo:

{"name": "1"}
  • Nel mapping:

    Se 0.yaml stato:

file1: !include include.d/1.yaml
file2: !include include.d/2.yaml

Otteniamo:

  file1:
    name: "1"
  file2:
    name: "2"
  • In sequenza:

    Se 0.yaml stato:

files:
  - !include include.d/1.yaml
  - !include include.d/2.yaml

Otteniamo:

files:
  - name: "1"
  - name: "2"

Nota:

Il nome del File può essere assoluto (come /usr/conf/1.5/Make.yml) o relativo (come ../../cfg/img.yml).

Includere i file con caratteri jolly

Il nome del File può contenere wildcard in stile shell.I dati caricati dal file(s) trovato da caratteri jolly, sarà ambientato in una sequenza.

Se 0.yaml stato:

files: !include include.d/*.yaml

Otteniamo:

files:
  - name: "1"
  - name: "2"

Nota:

  • Per Python>=3.5, se recursive argomento di !include YAML tag true, il modello “**” si adattano a qualsiasi file e zero o più directory e sottodirectory.
  • Utilizzando il “**” modello in grandi alberi di directory può consumare una quantità eccessiva di tempo a causa della ricerca ricorsiva.

Al fine di consentire recursive argomento, si deve scrivere il !include tag Mapping o Sequence modalità:

  • Argomenti Sequence modalità:
!include [tests/data/include.d/**/*.yaml, true]
  • Argomenti Mapping modalità:
!include {pathname: tests/data/include.d/**/*.yaml, recursive: true}

Purtroppo YAML non fornisce questo nel suo standard.

Ma se stai usando Ruby, c'è un gioiello che fornisce la funzionalità che si sta chiedendo per estendendo la ruby libreria YAML:https://github.com/entwanderer/yaml_extend

Credo che la soluzione utilizzata da @ maxy-B sembra grande. Tuttavia, non è riuscito per me con inclusioni nidificate. Ad esempio, se config_1.yaml include config_2.yaml, che comprende config_3.yaml c'è stato un problema con il caricatore. Tuttavia, se semplicemente puntare la nuova classe loader a se stesso il carico, funziona! In particolare, se si sostituisce la vecchia funzione _Include con la versione leggermente modificata:

def _include(self, loader, node):                                    
     oldRoot = self.root                                              
     filename = os.path.join(self.root, loader.construct_scalar(node))
     self.root = os.path.dirname(filename)                           
     data = yaml.load(open(filename, 'r'), loader = IncludeLoader)                            
     self.root = oldRoot                                              
     return data

Al momento di riflessione Concordo con gli altri commenti, che il carico nidificato non è appropriato per YAML, in generale, come il flusso di input non può essere un file, ma è molto utile!

Forse questo potrebbe ispirarvi, cercare di allineare alle convenzioni JBB:

https://docs.openstack.org /infra/jenkins-job-builder/definition.html#inclusion-tags

- job: name: test-job-include-raw-1 builders: - shell: !include-raw: include-raw001-hello-world.sh

standard YAML 1.2 non include nativamente questa funzione. Tuttavia molte implementazioni fornisce qualche estensione di farlo.

vi presento un modo per raggiungere con Java e snakeyaml:1.24 (libreria Java per analizzare / emettere file YAML) che permette di creare un tag YAML personalizzato per raggiungere il seguente obiettivo (si vedrà che sto usando per caricare suite di test definiti in diversi file YAML e che ho fatto funzionare come una lista di comprende un nodo di destinazione test:):

# ... yaml prev stuff

tests: !include
  - '1.hello-test-suite.yaml'
  - '3.foo-test-suite.yaml'
  - '2.bar-test-suite.yaml'

# ... more yaml document

Ecco il Java una classe che consente l'elaborazione del tag !include. I file vengono caricati dal percorso di classe (Maven risorse di directory):

/**
 * Custom YAML loader. It adds support to the custom !include tag which allows splitting a YAML file across several
 * files for a better organization of YAML tests.
 */
@Slf4j   // <-- This is a Lombok annotation to auto-generate logger
public class MyYamlLoader {

    private static final Constructor CUSTOM_CONSTRUCTOR = new MyYamlConstructor();

    private MyYamlLoader() {
    }

    /**
     * Parse the only YAML document in a stream and produce the Java Map. It provides support for the custom !include
     * YAML tag to split YAML contents across several files.
     */
    public static Map<String, Object> load(InputStream inputStream) {
        return new Yaml(CUSTOM_CONSTRUCTOR)
                .load(inputStream);
    }


    /**
     * Custom SnakeYAML constructor that registers custom tags.
     */
    private static class MyYamlConstructor extends Constructor {

        private static final String TAG_INCLUDE = "!include";

        MyYamlConstructor() {
            // Register custom tags
            yamlConstructors.put(new Tag(TAG_INCLUDE), new IncludeConstruct());
        }

        /**
         * The actual include tag construct.
         */
        private static class IncludeConstruct implements Construct {

            @Override
            public Object construct(Node node) {
                List<Node> inclusions = castToSequenceNode(node);
                return parseInclusions(inclusions);
            }

            @Override
            public void construct2ndStep(Node node, Object object) {
                // do nothing
            }

            private List<Node> castToSequenceNode(Node node) {
                try {
                    return ((SequenceNode) node).getValue();

                } catch (ClassCastException e) {
                    throw new IllegalArgumentException(String.format("The !import value must be a sequence node, but " +
                            "'%s' found.", node));
                }
            }

            private Object parseInclusions(List<Node> inclusions) {

                List<InputStream> inputStreams = inputStreams(inclusions);

                try (final SequenceInputStream sequencedInputStream =
                             new SequenceInputStream(Collections.enumeration(inputStreams))) {

                    return new Yaml(CUSTOM_CONSTRUCTOR)
                            .load(sequencedInputStream);

                } catch (IOException e) {
                    log.error("Error closing the stream.", e);
                    return null;
                }
            }

            private List<InputStream> inputStreams(List<Node> scalarNodes) {
                return scalarNodes.stream()
                        .map(this::inputStream)
                        .collect(toList());
            }

            private InputStream inputStream(Node scalarNode) {
                String filePath = castToScalarNode(scalarNode).getValue();
                final InputStream is = getClass().getClassLoader().getResourceAsStream(filePath);
                Assert.notNull(is, String.format("Resource file %s not found.", filePath));
                return is;
            }

            private ScalarNode castToScalarNode(Node scalarNode) {
                try {
                    return ((ScalarNode) scalarNode);

                } catch (ClassCastException e) {
                    throw new IllegalArgumentException(String.format("The value must be a scalar node, but '%s' found" +
                            ".", scalarNode));
                }
            }
        }

    }

}

Symfony , la sua gestione della YAML permetterai indirettamente a file YAML nido. Il trucco è quello di utilizzare l'opzione parameters. ad esempio:

common.yml

parameters:
    yaml_to_repeat:
        option: "value"
        foo:
            - "bar"
            - "baz"

config.yml

imports:
    - { resource: common.yml }
whatever:
    thing: "%yaml_to_repeat%"
    other_thing: "%yaml_to_repeat%"

Il risultato sarà lo stesso di:

whatever:
    thing:
        option: "value"
        foo:
            - "bar"
            - "baz"
    other_thing:
        option: "value"
        foo:
            - "bar"
            - "baz"

Probabilmente non è stato supportato quando domanda è stato chiesto, ma è possibile importare altri file YAML in uno:

imports: [/your_location_to_yaml_file/Util.area.yaml]

Anche se non ho alcun riferimento online, ma questo funziona per me.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top