【问题标题】:How to unmarshall YAML v3 with full access to node如何解组具有对节点的完全访问权限的 YAML v3
【发布时间】:2019-10-17 11:12:02
【问题描述】:

我正在尝试学习使用 YAML v3 解组,并具有对复杂嵌入式结构中节点的完全访问权限。

The announcement 帖子解释了如何使用 yaml.Node,但没有给出一个严肃的例子。并且documentation 也没有显示使用节点。主要目的似乎是在 YAML 文件中出色地保存 cmets。

例如,使用公告文章的扩展,我有

package main

import(
    "fmt"
    "gopkg.in/yaml.v3"
    "os"
)

func main() {

    type Person struct {
        Name    string
        Address yaml.Node
    }

    data := `
name: John Doe
address: 
    street: 123 E 3rd St # street is like an avenue
    city: Denver  # A city might be a town as well
    state: CO  # A state might be a province or administrative unit
    zip: 81526 # zip might be "postal_code"
`

    var person Person
    err := yaml.Unmarshal([]byte(data), &person)
    if (err != nil) {
        fmt.Printf("Failed to unmarshall: %v", err)
        os.Exit(1)
    }
    fmt.Printf("Marshalled person=%v", person)

}

但如果我尝试使用地址项,我会发现它们每个都列为节点内的内容数组;那里没有实际有用的信息。 cmets 在那里,但不清楚它们与什么相关联。

Modify existing yaml file and add new data and comments 也处理相同的区域,但在解组到结构后不显示导航结构。

如何在解组后导航“地址”节点,并在再次编组时保留 cmets?

【问题讨论】:

    标签: go yaml


    【解决方案1】:

    所以 Node 结构有三个字段:

    // HeadComment holds any comments in the lines preceding the node and
    // not separated by an empty line.
    HeadComment string
    
    // LineComment holds any comments at the end of the line where the node is in.
    LineComment string
    
    // FootComment holds any comments following the node and before empty lines.
    FootComment string
    

    此 ^ 取自文档 here。对上面的例子进行了轻微的扩充:

    package main
    
    import (
        "fmt"
        "os"
    
        "gopkg.in/yaml.v3"
    )
    
    func main() {
        type Person struct {
            Name    yaml.Node
            Address yaml.Node
        }
    
        data := `
    name: John Doe
    #comment here
    address: 
        street: 123 E 3rd St
        city: Denver
        state: CO
        zip: 81526
    `
    
        var person Person
        err := yaml.Unmarshal([]byte(data), &person)
        if err != nil {
            fmt.Printf("Failed to unmarshall: %v", err)
            os.Exit(1)
        }
        address := &yaml.Node{}
    
        decErr := person.Address.Decode(address)
        if decErr != nil {
            fmt.Printf("Failed to decode: %v", decErr)
            os.Exit(1)
        }
        fmt.Printf("%v", address.HeadComment)
    }
    

    在我们的例子中

    #comment here
    address: 
        street: 123 E 3rd St
        city: Denver
        state: CO
        zip: 81526
    

    可以称为 Node,它的 cmets 可以从 Node 结构中的字段访问。但是我仍然无法获得节点上方的评论,尽管我能够访问文档中指出的其他字段。

    【讨论】:

      【解决方案2】:

      你必须声明完整的 struct 而不是使用 yaml.Node

      package main
      
      import (
          "fmt"
          "gopkg.in/yaml.v3"
          "os"
      )
      
      func main() {
          type Address struct {
              Street string
              City   string
              State  string
              Zip    string
          }
          type Person struct {
              Name    string
              Address Address
          }
      
      
      
      data := `
          name: John Doe
          address: 
              street: 123 E 3rd St
              city: Denver
              state: CO
              zip: 81526
          `
      
          var person Person
          err := yaml.Unmarshal([]byte(data), &person)
          if (err != nil) {
              fmt.Printf("Failed to unmarshall: %v", err)
              os.Exit(1)
          }
          fmt.Printf("Marshalled person=%v", person)
      }
      

      yaml.Node 似乎是一个中间表示。 必须对其进行解码才能获取值。

      package main
      
      import (
          "fmt"
          "gopkg.in/yaml.v3"
          "os"
      )
      
      func main() {
          type Address struct {
              Street string
              City   string
              State  string
              Zip    string
          }
      type Person struct {
          Name    string
          Address yaml.Node
      }
      
      data := `
      name: John Doe
      address: 
          street: 123 E 3rd St
          city: Denver
          state: CO
          zip: 81526
      `
      
      var person Person
      err := yaml.Unmarshal([]byte(data), &person)
      if (err != nil) {
          fmt.Printf("Failed to unmarshall: %v", err)
          os.Exit(1)
      }
      address := &Address{}
      _ = person.Address.Decode(address)
      fmt.Printf("Marshalled person=%v\n %v", person, *address)
      
      }
      

      【讨论】:

      • 感谢您指出 Decode()。不过,我仍然不了解 Node 的正确使用,因为根据the announcement post,最大的好处是能够保留 cmets 并将它们保存在正确的位置。如果您不能将 Node 的内容捆绑在一起,我不明白如何成功地做到这一点。我更新了问题以关注对 cme​​ts 的访问。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-13
      • 2013-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多