একই YAML ফাইলে অন্য কোথাও কোনও ওয়াইএএমএল "সেটিং" কে কীভাবে উল্লেখ করবেন?


145

আমি নিম্নলিখিত 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

অবশ্যই এটি অবৈধ, আমি এটি তৈরি করেছিলাম made আসল বাক্য গঠন কী? এটা করা যায়?


1
আরও দেখুন: stackoverflow.com/a/41620747/42223
dreftymac

উত্তর:


127

আমি মনে করি না এটি সম্ভব। আপনি "নোড" পুনরায় ব্যবহার করতে পারেন তবে এর অংশ নয়।

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

এটি পুরোপুরি বৈধ ওয়াইএএমএল এবং ক্ষেত্র givenএবং familyএটি ship-toব্লকে পুনরায় ব্যবহৃত হয় । আপনি একইভাবে কোনও স্কেলার নোডটি পুনরায় ব্যবহার করতে পারেন তবে ভিতরে কী রয়েছে তা পরিবর্তন করতে পারবেন এবং ওয়্যামের ভিতরে থেকে কোনও পথের শেষ অংশটি যুক্ত করতে পারবেন না।

যদি পুনরাবৃত্তি আপনাকে এতটা বিরক্ত করে তবে আমি আপনার অ্যাপ্লিকেশনটিকে rootসম্পত্তি সম্পর্কে সচেতন করার এবং এটিকে প্রতিটি পথে যুক্ত করার পরামর্শ দিচ্ছি যা পরম নয় looks


1
ঠিক আছে ধন্যবাদ, হ্যাঁ অসুস্থকে rootকোডটি প্রিপেন্ড করতে হবে । বড় কথা না
অ্যান্ড্রু বুলক

2
গৃহীত উত্তর সঠিক নয়। একটি সমাধানের জন্য আমার উত্তর দেখুন।
ক্রিস জনসন

কীভাবে এটি করবেন, যদি বিল-টু অন্য কোনও ফাইলে থাকে, যা আমরা আমদানি করেছি যেখানে শিপ-টু সংজ্ঞা দেওয়া হয়েছে?
পূর্বক জৈন

@ প্রীতেকজাইন: আপনি যদি একাধিক ফাইল নিয়ে কাজ করে থাকেন তবে আপনি সম্ভবত এখানে তালিকাভুক্ত স্ট্যান্ডলোন ওয়াইএএমএল-বর্ধনের পাঠাগারটি মূল্যায়নের জন্য সবচেয়ে ভাল করবেন। github.com/dreftymac/dynamic.yaml/blob/master/…
dreftymac

1
Yaml.org/spec/1.2/spec.html এ 2.9 উদাহরণ দেখুন ; যে কেউ
স্কেলারের

72

হ্যাঁ, কাস্টম ট্যাগ ব্যবহার করে। পাইথনের উদাহরণ, !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]আপনি যা প্রত্যাশা করবেন তা করে।


2
আমি আপনার সমাধানটি পছন্দ করি, কোডিংয়ের ক্ষেত্রে সহজ, তারপরে কিছুটা কম পঠনযোগ্য YAML এর দামে আমার।
অ্যান্থন

7
এই উত্তরটি আরও বেশি ভোটের দাবিদার। এটি প্রযুক্তিগতভাবে ওয়াইএএমএল স্পেসিফিকেশন অনুসারে সবচেয়ে নির্ভুল উত্তর। প্রকৃত ওয়াইএএমএল বাস্তবায়নের অনুসারে একটি সাবধানতা অবলম্বন করে , সেখানে খুব কম এমন লোক রয়েছে যা পুরো ওয়াইএএমএল অনুমানটি বাস্তবায়িত করে। পাইথনের পাইমল স্পেসিফিকেশনের সাথে এর অভিন্নতার দিক থেকে অনেকের উপরে এবং বাইরে।
dreftymac

5
প্রশ্নটি ইয়ামল ফাইলে একটি মান উল্লেখ করার বিষয়ে বলে মনে হচ্ছে। চারপাশে কোডের অন্য স্তর যুক্ত করা আমার পছন্দসই সমাধান হবে না।
ব্যবহারকারী 2020056

1
@ ক্রিস জোনসন এই উত্তরের জন্য ধন্যবাদ, আমি ভাবছিলাম যে আপনার কাছে যদি এমন একটি রেফারেন্স ডকুমেন্ট রয়েছে যা এই বাক্য গঠনটি তালিকাভুক্ত করেছে। আমি ওয়েবে একাধিক জায়গায় ওয়াইএএমএল স্পেসটি ব্যাখ্যা করে দেখেছি যাতে আমি ঠিক তা নিশ্চিত করতে চাই যে আপনি যে একই রেফারেন্সটির দিকে তাকিয়ে রয়েছেন। ধন্যবাদ!
ব্যবহারকারী5359531

3
এই সমাধানটি আমার ( python3?) এর জন্য কার্যকর হয়নি তবে উপরের একটি সাধারণ পরিবর্তনের সাথে এটি প্রত্যাশার মতো কাজ করে। বিশেষত:yaml.SafeLoader.add_constructor(tag='!join', constructor=join) yaml.load(open(fpth, mode='r'), Loader=yaml.SafeLoader)
বেনজমিনমগ্রস

20

এটি দেখার আরেকটি উপায় হ'ল কেবল অন্য ক্ষেত্রটি ব্যবহার করা।

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

5

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")}' /> 

আউটপুট: / হোম / ডেটা / ইন / হোম / ডেটা / ইন / পি 1


@ অ্যান্ড্রুবুলক আমি মনে করি এটি গ্রহণযোগ্য উত্তর হওয়া উচিত, কারণ এটি ঠিক আপনার সমস্যা সমাধান করে।
হনজা জিদেক

5
না, এটি YAML এ ভেরিয়েবলের স্থানীয় ব্যবহার নয় এবং এটি কোনও স্পেসিফিকেশন সংস্করণে নির্দিষ্ট করা হয়নি। কিছু পরীক্ষার পরে, এটি কাজ করে না।
আর্থার লাকোস্ট

2
এটি সম্ভবত পাভোল এমন কিছু ব্যবহার করে কাজ করেছিল যা ইয়ামল প্রাক প্রক্রিয়াজাতকরণ (অর্থাত্ মভেন-রিসোর্সেস-প্লাগইন ফিল্টারিং)
দেজক্যাসিউজ

1
মানক ইয়ামল নয়
ড্যান নেয়ারো

3

আমি প্যাকেগিস্টে উপলব্ধ একটি লাইব্রেরি তৈরি করেছি যা এই ফাংশনটি সম্পাদন করে: https://packagist.org/packages/grasmash/yaml-expender

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

প্রবাসী ধারণাটি প্রেমময়!
গিলিয়াম রডরিক

2

কিছু ভাষায়, আপনি একটি বিকল্প গ্রন্থাগার ব্যবহার করতে পারেন, উদাহরণস্বরূপ, ট্যাম্প্যাক্স হ'ল ওয়াইএএমএল হ্যান্ডলিং ভেরিয়েবলগুলির একটি বাস্তবায়ন:

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."

1

আপনার উদাহরণটি অবৈধ তা কেবল কারণ আপনি আপনার স্কেলারগুলি শুরু করার জন্য কোনও সংরক্ষিত চরিত্র বেছে নিয়েছিলেন। যদি আপনি *কিছু অন্যান্য অন-সংরক্ষিত চরিত্রের সাথে প্রতিস্থাপন করেন (এর জন্য আমি অ-এসসিআইআই অক্ষরগুলি ব্যবহার করার প্রবণতা খুব কমই কিছু স্পেসিফিকেশনের অংশ হিসাবে ব্যবহৃত হয়), আপনি পুরোপুরি আইনী ওয়াইএএমএল দিয়ে শেষ করবেন:

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

এটি আপনার পার্সার যে ভাষায় ম্যাপিংগুলি ব্যবহার করে এবং যাদুকরীভাবে কোনও কিছুর প্রসারিত করে না তার জন্য মানক উপস্থাপনায় এটি লোড হবে।
এটি করার জন্য নিম্নলিখিত পাইথন প্রোগ্রামের মতো স্থানীয়ভাবে ডিফল্ট অবজেক্ট টাইপ ব্যবহার করুন:

# 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

প্রসারণটি উড়ে গিয়ে সম্পন্ন হয় এবং নেস্টেড সংজ্ঞাগুলি পরিচালনা করে তবে আপনাকে অসীম পুনরাবৃত্তি না করার বিষয়ে সতর্ক থাকতে হবে।

ডাম্পারটি নির্দিষ্ট করে, অন-ফ্লাই সম্প্রসারণের কারণে, আপনি লোড হওয়া ডেটা থেকে আসল ওয়াইএএমএলটি ডাম্প করতে পারেন:

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)


0

পাইথনে আমি নিজস্ব লাইব্রেরি লিখেছি যেমন একটি শ্রেণিবদ্ধের সাহায্যে ডিরেক্টরি থেকে লোড করা ভেরিয়েবলগুলি প্রসারিত করতে:

/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/Scriptts/Tools/Cmdoplib.yaml.py https://sourceforge.net/p/contools/contools/HEAD/tree/trunk/Scriptts /Tools/cmdoplib.yaml.xsh

পেশাদাররা :

  • সহজ, পুনরাবৃত্তি এবং নেস্টেড ভেরিয়েবল সমর্থন করে না
  • স্থানধারক ( ${MYUNDEFINEDVAR}-> *$/{MYUNDEFINEDVAR}) এ একটি অপরিজ্ঞাত পরিবর্তনশীল প্রতিস্থাপন করতে পারে
  • পরিবেশ পরিবর্তনশীল ( ${env:MYVAR}) থেকে একটি রেফারেন্স প্রসারিত করতে পারে
  • সকলকে একটি পাথের ভেরিয়েবল ( ) এ প্রতিস্থাপন করতে \\পারে/${env:MYVAR:path}

কনস :

  • নেস্টেড ভেরিয়েবল সমর্থন করে না, তাই নেস্টেড ডিকশনারিগুলিতে মানগুলি প্রসারিত করতে পারে না (এমন কিছু ${MYSCOPE.MYVAR}বাস্তবায়িত হয় না)
  • স্থানধারক রাখার পরে পুনরাবৃত্তি সহ সম্প্রসারণ পুনরাবৃত্তি সনাক্ত করে না

0

ইগলু দিয়ে আপনি নিজের উদাহরণটি লিখতে পারেন:

paths:
  root: /path/to/root/
  patha: !? .paths.root + a
  pathb: !? .paths.root + b
  pathc: !? .paths.root + c

দাবি অস্বীকার: আমি ইগলু এর লেখক।


YAML এর উপরে এই কার্যকারিতা যুক্ত করে এমন একটি গ্রন্থাগার সম্পর্কে সচেতন হওয়া ভাল
ধীরাজ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.