web-dev-qa-db-ja.com

既存のyamlファイルを変更し、新しいデータとコメントを追加する

私は最近、go yaml libに新しいバージョン(V3)があることを確認しました

nodes 機能(私の意見ではキラー機能です:))を使用すると、ファイルの構造を変更せずにyamlを変更するのに役立ちます

しかし、それは(先週から)かなり新しいので、必要なコンテキストの有用なドキュメントと例が見つかりませんでした(新しいオブジェクト/ノードとファイル構造を同じに保つためコメントを削除せずに)

私が必要なのはyamlファイルを操作することです

例えば

このyamlファイルがあるとしましょう

_version: 1
type: verbose
kind : bfr

# my list of applications
applications:
  - name: app1
    kind: nodejs
    path: app1
    exec:
      platforms: k8s
      builder: test
_

今私は既存のファイルに挿入する必要があるjsonオブジェクト(例えば_app2_付き)を取得しました

_[

    {
        "comment: "Second app",
        "name": "app2",
        "kind": "golang",
        "path": "app2",
        "exec": {
            "platforms": "dockerh",
            "builder": "test"
        }
    }
]
_

最初のアプリケーションの後にymlファイルに追加する必要があります(applicationsはアプリケーションの配列です)

_version: 1
type: verbose
kind : bfr

# my list of applications
applications:

#  First app
  - name: app1
    kind: nodejs
    path: app1
    exec:
      platforms: k8s
      builder: test

# Second app
  - name: app2
    kind: golang
    path: app2
    exec:
      platforms: dockerh
      builder: test
_

yamlファイルから新しいjsonオブジェクトを追加することは可能ですか?既存のものも削除

私もこのブログを見つけましたhttps://blog.ubuntu.com/2019/04/05/api-v3-of-the -yaml-package-for-go-is-available

これはオブジェクトを表すタイプです

_type VTS struct {
    version string       `yaml:"version"`
    types   string       `yaml:"type"`
    kind    string       `yaml:"kind,omitempty"`
    apps    Applications `yaml:"applications,omitempty"`
}

type Applications []struct {
    Name string `yaml:"name,omitempty"`
    Kind string `yaml:"kind,omitempty"`
    Path string `yaml:"path,omitempty"`
    Exec struct {
        Platforms string `yaml:"platforms,omitempty"`
        Builder   string `yaml:"builder,omitempty"`
    } `yaml:"exec,omitempty"`
}
_

更新

_wiil7200_によって提供されるソリューションをテストした後、2つの問題が見つかりました

最後に使用してファイルに書き込みますerr = ioutil.WriteFile("output.yaml", b, 0644)

そして、yaml出力には2つの問題があります。

  1. アプリケーションの配列はコメントから始まります。名前から始まる必要があります

  2. nameエントリの後、kindプロパティとそれ以降のすべてのプロパティはnameに揃えられません

これらの問題を解決する方法はありますか? commentsの問題について、jsonからではなく他のプロパティから取得したとしましょう(それがより簡単になる場合)

_version: 1
type: verbose
kind: bfr


# my list of applications
applications:
-   #  First app
name: app1
    kind: nodejs
    path: app1
    exec:
        platforms: k8s
        builder: test
-   # test 1
name: app2
    kind: golang
    path: app2
    exec:
        platform: dockerh
        builder: test
_
11
Rayn D

前のノードを削除せずに、新しいノードを作成してコンテンツに直接追加できます。次の例は、この点を示しています。

package main

import (
    "fmt"
    "log"

    "gopkg.in/yaml.v3"
)

var (
    sourceYaml = `version: 1
type: verbose
kind : bfr

# my list of applications
applications:

#  First app
  - name: app1
    kind: nodejs
    path: app1
    exec:
      platforms: k8s
      builder: test
`
)

type Application struct {
    Name string `yaml:"name,omitempty" json:"name,omitempty"`
    Kind string `yaml:"kind,omitempty" json:"kind,omitempty"`
    Path string `yaml:"path,omitempty" json:"path,omitempty"`
    Exec struct {
        Platforms string `yaml:"platforms,omitempty" json:"platforms,omitempty"`
        Builder   string `yaml:"builder,omitempty" json:"builder,omitempty"`
    } `yaml:"exec,omitempty" json:"exec,omitempty"`
}

func newApplicationNode(
    name string,
    kind string,
    path string,
    platforms string,
    builder string,
    comment string) (*yaml.Node, error) {

    app := Application{
        Name: name,
        Kind: kind,
        Path: path,
        Exec: struct {
            Platforms string `yaml:"platforms,omitempty" json:"platforms,omitempty"`
            Builder   string `yaml:"builder,omitempty" json:"builder,omitempty"`
        }{platforms, builder},
    }
    marshalledApp, err := yaml.Marshal(&app)
    if err != nil {
        return nil, err
    }

    node := yaml.Node{}
    if err := yaml.Unmarshal(marshalledApp, &node); err != nil {
        return nil, err
    }
    node.Content[0].HeadComment = comment
    return &node, nil
}

func main() {
    yamlNode := yaml.Node{}

    err := yaml.Unmarshal([]byte(sourceYaml), &yamlNode)
    if err != nil {
        log.Fatalf("error: %v", err)
    }

    newApp, err := newApplicationNode("app2", "golang", "app2", "dockerh",
        "test", "Second app")
    if err != nil {
        log.Fatalf("error: %v", err)
    }

    appIdx := -1
    for i, k := range yamlNode.Content[0].Content {
        if k.Value == "applications" {
            appIdx = i + 1
            break
        }
    }

    yamlNode.Content[0].Content[appIdx].Content = append(
        yamlNode.Content[0].Content[appIdx].Content, newApp.Content[0])

    out, err := yaml.Marshal(&yamlNode)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(string(out))
}

明らかに、私がnewApplicationNodeで行ったようなハッキーな方法をとるのではなく、JSONから適切に非整列化できます。ただし、前の回答で述べたように、キーと実際の値はContent内の後続のインデックスにあることに注意することが重要です。そのため、ドキュメントを変更するときにこれを考慮する必要があります。 (たとえば、applicationsキーを検索しますが、次のインデックス(appIdx = i + 1(私の例では)その内容について。

お役に立てば幸いです。

0
nettrino