كيفية الرجوع إلى "إعداد" YAML من مكان آخر في نفس ملف YAML؟

StackOverflow https://stackoverflow.com/questions/2063616

  •  20-09-2019
  •  | 
  •  

سؤال

لدي YAML التالي:

paths:
  patha: /path/to/root/a
  pathb: /path/to/root/b
  pathc: /path/to/root/c

كيف يمكنني "تطبيع" هذا عن طريق إزالة /path/to/root/ من الطرق الثلاثة، وجعلها مكانًا خاصًا بها، مثل:

paths:
  root: /path/to/root/
  patha: *root* + a
  pathb: *root* + b
  pathc: *root* + c

من الواضح أن هذا غير صالح، لقد اختلقته للتو.ما هو بناء الجملة الحقيقي؟ويمكن أن يتم ذلك؟

هل كانت مفيدة؟

المحلول

وأنا لا أعتقد أنه من الممكن. يمكنك إعادة "العقدة" ولكن ليس جزءا منه.

bill-to: &id001
    given  : Chris
    family : Dumars
ship-to: *id001

وهذا صحيح تماما وإعادة استخدامها YAML والحقول given وfamily في كتلة ship-to. يمكنك إعادة عقدة العددية بنفس الطريقة ولكن لا توجد طريقة يمكنك تغيير ما يدور في داخل وأضيف أن الجزء الأخير من مساره من داخل YAML.

إذا تكرار يزعجك كثيرا أقترح أن يجعل تطبيق على علم الملكية root وإضافته إلى كل المسار الذي يبدو قريب يست مطلقة.

نصائح أخرى

نعم، وذلك باستخدام العلامات المخصصة. مثلا في بيثون، مما يجعل العلامة !join الانضمام السلاسل في صفيف:

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]
""")

وأي نتائج البحث في

{
    'paths': {
        'patha': '/path/to/root/a',
        'pathb': '/path/to/root/b',
        'pathc': '/path/to/root/c',
        'root': '/path/to/root/'
     }
}

وومجموعة من الحجج ل!join يمكن أن يكون أي عدد من العناصر من أي نوع البيانات، طالما أنها يمكن تحويلها إلى سلسلة، لذلك لا !join [*a, "/", *b, "/", *c] ما كنت تتوقع.

وهناك طريقة أخرى لإلقاء نظرة على هذا هو ببساطة استخدام حقل آخر.

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

تعريف YML:

dir:
  default: /home/data/in/
  proj1: ${dir.default}p1
  proj2: ${dir.default}p2
  proj3: ${dir.default}p3 

في مكان ما في ورق الزعتر

<p th:utext='${@environment.getProperty("dir.default")}' />
<p th:utext='${@environment.getProperty("dir.proj1")}' /> 

انتاج:/الصفحة الرئيسية/البيانات///الصفحة الرئيسية/البيانات/في/p1

في بعض اللغات، يمكنك استخدام مكتبة بديلة، على سبيل المثال، tampax هو تنفيذ 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."

ولقد إنشاء مكتبة، وهي متاحة على Packagist، أن ينفذ هذه المهمة: https://packagist.org/packages/grasmash/yaml-expander

مثال 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}

مثال المنطق:

// 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 (
  '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',
);

أن المثال الخاص بك غير صالح فقط لأنك اخترت حرفًا محجوزًا لبدء الكميات الخاصة بك به.إذا قمت باستبدال * مع بعض الأحرف الأخرى غير المحجوزة (أميل إلى استخدام أحرف غير ASCII لذلك، حيث نادرًا ما يتم استخدامها كجزء من بعض المواصفات)، ينتهي بك الأمر باستخدام YAML قانوني تمامًا:

paths:
  root: /path/to/root/
  patha: ♦root♦ + a
  pathb: ♦root♦ + b
  pathc: ♦root♦ + c

سيتم تحميل هذا في التمثيل القياسي للتعيينات باللغة التي يستخدمها المحلل اللغوي ولا يقوم بتوسيع أي شيء بطريقة سحرية.
للقيام بذلك، استخدم نوع كائن افتراضي محليًا كما في برنامج Python التالي:

# 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]))

والتي سوف تطبع:

root -> /path/to/root/
pathc -> /path/to/root/c

يتم التوسيع بسرعة ويتعامل مع التعريفات المتداخلة، ولكن عليك توخي الحذر بشأن عدم استدعاء التكرار اللانهائي.

من خلال تحديد أداة التفريغ، يمكنك تفريغ YAML الأصلي من البيانات المحملة فيه، بسبب التوسع الفوري:

dumper = yaml.RoundTripDumper
dumper.add_representer(Paths, Paths.__yaml_out__)
print(yaml.dump(paths, Dumper=dumper, allow_unicode=True))

سيؤدي هذا إلى تغيير ترتيب مفتاح التعيين.إذا كانت هذه مشكلة لديك لجعل self.d أ CommentedMap ( مستورد من ruamel.yaml.comments.py)

لقد كتبت مكتبتي الخاصة على بايثون لتوسيع المتغيرات التي يتم تحميلها من الدلائل بتسلسل هرمي مثل:

/root
 |
 +- /proj1
     |
     +- config.yaml
     |
     +- /proj2
         |
         +- config.yaml
         |
         ... and so on ...

والفرق الرئيسي هنا هو أن التوسيع يجب أن يتم تطبيقه فقط بعد كل config.yaml يتم تحميل الملفات، حيث يمكن للمتغيرات من الملف التالي أن تحل محل المتغيرات من الملف السابق، لذلك يجب أن يبدو الكود الكاذب كما يلي:

env = YamlEnv()
env.load('/root/proj1/config.yaml')
env.load('/root/proj1/proj2/config.yaml')
...
env.expand()

كخيار إضافي xonsh يمكن للبرنامج النصي تصدير المتغيرات الناتجة إلى متغيرات البيئة (انظر ملف yaml_update_global_vars وظيفة).

البرامج النصية:

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

الايجابيات:

  • بسيطة، لا تدعم العودية والمتغيرات المتداخلة
  • يمكن استبدال متغير غير محدد بعنصر نائب (${MYUNDEFINEDVAR} -> *$/{MYUNDEFINEDVAR})
  • يمكن توسيع مرجع من متغير البيئة (${env:MYVAR})
  • يمكن أن تحل محل جميع \\ ل / في متغير المسار (${env:MYVAR:path})

سلبيات:

  • لا يدعم المتغيرات المتداخلة، لذلك لا يمكن توسيع القيم في القواميس المتداخلة (شيء من هذا القبيل ${MYSCOPE.MYVAR} لم يتم تنفيذه)
  • لا يكشف عن العودية التوسع، بما في ذلك العودية بعد وضع العنصر النائب
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top