Saya memiliki YAML berikut:
paths:
patha: /path/to/root/a
pathb: /path/to/root/b
pathc: /path/to/root/c
Bagaimana saya bisa "menormalkan" ini, dengan menghapus /path/to/root/
dari tiga jalur, dan menjadikannya sebagai pengaturannya sendiri, seperti:
paths:
root: /path/to/root/
patha: *root* + a
pathb: *root* + b
pathc: *root* + c
Jelas itu tidak valid, saya hanya mengada-ada. Apa sintaks sebenarnya? Bisakah itu dilakukan?
syntax
yaml
transclusion
Andrew Bullock
sumber
sumber
Jawaban:
Saya rasa itu tidak mungkin. Anda dapat menggunakan kembali "node" tapi bukan bagian darinya.
bill-to: &id001 given : Chris family : Dumars ship-to: *id001
Ini adalah YAML dan kolom yang benar-benar valid
given
danfamily
digunakan kembali dalamship-to
blok. Anda dapat menggunakan kembali node skalar dengan cara yang sama tetapi tidak ada cara untuk mengubah apa yang ada di dalamnya dan menambahkan bagian terakhir dari jalur ke sana dari dalam YAML.Jika pengulangan sangat mengganggu Anda, saya sarankan untuk membuat aplikasi Anda sadar akan
root
properti dan menambahkannya ke setiap jalur yang terlihat relatif tidak absolut.sumber
root
kode di awal. bukan masalah besar.Ya, menggunakan tag kustom. Contoh di Python, membuat
!join
tag menggabungkan string dalam sebuah array:import yaml ## define custom tag handler def join(loader, node): seq = loader.construct_sequence(node) return ''.join([str(i) for i in seq]) ## register the tag handler yaml.add_constructor('!join', join) ## using your sample data yaml.load(""" paths: root: &BASE /path/to/root/ patha: !join [*BASE, a] pathb: !join [*BASE, b] pathc: !join [*BASE, c] """)
Yang mengakibatkan:
{ 'paths': { 'patha': '/path/to/root/a', 'pathb': '/path/to/root/b', 'pathc': '/path/to/root/c', 'root': '/path/to/root/' } }
Larik argumen untuk
!join
dapat memiliki sejumlah elemen dari tipe data apa pun, selama mereka dapat dikonversi menjadi string, begitu!join [*a, "/", *b, "/", *c]
juga yang Anda harapkan.sumber
python3
?) Namun dengan modifikasi sederhana di atas, solusi ini berfungsi seperti yang diharapkan. Khususnya:yaml.SafeLoader.add_constructor(tag='!join', constructor=join)
yaml.load(open(fpth, mode='r'), Loader=yaml.SafeLoader)
Cara lain untuk melihatnya adalah dengan menggunakan bidang lain.
paths: root_path: &root val: /path/to/root/ patha: &a root_path: *root rel_path: a pathb: &b root_path: *root rel_path: b pathc: &c root_path: *root rel_path: c
sumber
Definisi YML:
dir: default: /home/data/in/ proj1: ${dir.default}p1 proj2: ${dir.default}p2 proj3: ${dir.default}p3
Di suatu tempat di daun timele
<p th:utext='${@environment.getProperty("dir.default")}' /> <p th:utext='${@environment.getProperty("dir.proj1")}' />
Keluaran: / home / data / in / / home / data / in / p1
sumber
Saya telah membuat perpustakaan, tersedia di Packagist, yang menjalankan fungsi ini: https://packagist.org/packages/grasmash/yaml-expander
Contoh file YAML:
type: book book: title: Dune author: Frank Herbert copyright: ${book.author} 1965 protaganist: ${characters.0.name} media: - hardcover characters: - name: Paul Atreides occupation: Kwisatz Haderach aliases: - Usul - Muad'Dib - The Preacher - name: Duncan Idaho occupation: Swordmaster summary: ${book.title} by ${book.author} product-name: ${${type}.title}
Contoh logika:
// Parse a yaml string directly, expanding internal property references. $yaml_string = file_get_contents("dune.yml"); $expanded = \Grasmash\YamlExpander\Expander::parse($yaml_string); print_r($expanded);
Array yang dihasilkan:
array ( 'type' => 'book', 'book' => array ( 'title' => 'Dune', 'author' => 'Frank Herbert', 'copyright' => 'Frank Herbert 1965', 'protaganist' => 'Paul Atreides', 'media' => array ( 0 => 'hardcover', ), ), 'characters' => array ( 0 => array ( 'name' => 'Paul Atreides', 'occupation' => 'Kwisatz Haderach', 'aliases' => array ( 0 => 'Usul', 1 => 'Muad\'Dib', 2 => 'The Preacher', ), ), 1 => array ( 'name' => 'Duncan Idaho', 'occupation' => 'Swordmaster', ), ), 'summary' => 'Dune by Frank Herbert', );
sumber
Dalam beberapa bahasa, Anda bisa menggunakan library alternatif. Misalnya, tampax adalah implementasi dari variabel penanganan YAML:
const tampax = require('tampax'); const yamlString = ` dude: name: Arthur weapon: favorite: Excalibur useless: knife sentence: "{{dude.name}} use {{weapon.favorite}}. The goal is {{goal}}."`; const r = tampax.yamlParseString(yamlString, { goal: 'to kill Mordred' }); console.log(r.sentence); // output : "Arthur use Excalibur. The goal is to kill Mordred."
sumber
Bahwa contoh Anda tidak valid hanya karena Anda memilih karakter khusus untuk memulai skalar Anda. Jika Anda mengganti
*
dengan beberapa karakter non-cadangan lainnya (saya cenderung menggunakan karakter non-ASCII untuk itu karena jarang digunakan sebagai bagian dari beberapa spesifikasi), Anda akan mendapatkan YAML yang legal:paths: root: /path/to/root/ patha: ♦root♦ + a pathb: ♦root♦ + b pathc: ♦root♦ + c
Ini akan dimuat ke dalam representasi standar untuk pemetaan dalam bahasa yang digunakan parser Anda dan tidak memperluas apa pun secara ajaib.
Untuk melakukan itu gunakan tipe objek default lokal seperti pada program Python berikut:
# coding: utf-8 from __future__ import print_function import ruamel.yaml as yaml class Paths: def __init__(self): self.d = {} def __repr__(self): return repr(self.d).replace('ordereddict', 'Paths') @staticmethod def __yaml_in__(loader, data): result = Paths() loader.construct_mapping(data, result.d) return result @staticmethod def __yaml_out__(dumper, self): return dumper.represent_mapping('!Paths', self.d) def __getitem__(self, key): res = self.d[key] return self.expand(res) def expand(self, res): try: before, rest = res.split(u'♦', 1) kw, rest = rest.split(u'♦ +', 1) rest = rest.lstrip() # strip any spaces after "+" # the lookup will throw the correct keyerror if kw is not found # recursive call expand() on the tail if there are multiple # parts to replace return before + self.d[kw] + self.expand(rest) except ValueError: return res yaml_str = """\ paths: !Paths root: /path/to/root/ patha: ♦root♦ + a pathb: ♦root♦ + b pathc: ♦root♦ + c """ loader = yaml.RoundTripLoader loader.add_constructor('!Paths', Paths.__yaml_in__) paths = yaml.load(yaml_str, Loader=yaml.RoundTripLoader)['paths'] for k in ['root', 'pathc']: print(u'{} -> {}'.format(k, paths[k]))
yang akan mencetak:
root -> /path/to/root/ pathc -> /path/to/root/c
Perluasan dilakukan dengan cepat dan menangani definisi bertingkat, tetapi Anda harus berhati-hati agar tidak meminta rekursi tak terbatas.
Dengan menentukan dumper, Anda dapat membuang YAML asli dari data yang dimuat, karena ekspansi on-the-fly:
dumper = yaml.RoundTripDumper dumper.add_representer(Paths, Paths.__yaml_out__) print(yaml.dump(paths, Dumper=dumper, allow_unicode=True))
ini akan mengubah urutan kunci pemetaan. Jika itu adalah masalah Anda harus membuat
self.d
sebuahCommentedMap
(diimpor dariruamel.yaml.comments.py
)sumber
Dengan Yglu , Anda dapat menuliskan contoh Anda sebagai:
paths: root: /path/to/root/ patha: !? .paths.root + a pathb: !? .paths.root + b pathc: !? .paths.root + c
Penafian: Saya adalah penulis Yglu.
sumber
Saya telah menulis perpustakaan saya sendiri di Python untuk memperluas variabel yang dimuat dari direktori dengan hierarki seperti:
/root | +- /proj1 | +- config.yaml | +- /proj2 | +- config.yaml | ... and so on ...
Perbedaan utamanya di sini adalah bahwa perluasan harus diterapkan hanya setelah semua
config.yaml
file dimuat, di mana variabel dari file berikutnya dapat menimpa variabel dari sebelumnya, jadi pseudocode akan terlihat seperti ini:env = YamlEnv() env.load('/root/proj1/config.yaml') env.load('/root/proj1/proj2/config.yaml') ... env.expand()
Sebagai opsi tambahan,
xonsh
skrip dapat mengekspor variabel yang dihasilkan menjadi variabel lingkungan (lihatyaml_update_global_vars
fungsinya).Scriptnya:
https://sourceforge.net/p/contools/contools/HEAD/tree/trunk/Scripts/Tools/cmdoplib.yaml.py https://sourceforge.net/p/contools/contools/HEAD/tree/trunk/Scripts /Tools/cmdoplib.yaml.xsh
Kelebihan :
${MYUNDEFINEDVAR}
->*$/{MYUNDEFINEDVAR}
)${env:MYVAR}
)\\
ke/
dalam variabel jalur (${env:MYVAR:path}
)Kekurangan :
${MYSCOPE.MYVAR}
itu tidak diterapkan)sumber