Golang中YAML序列化与反序列化导入结构体的实现方法

Golang中YAML序列化与反序列化导入结构体的实现方法 我正在尝试使用YAML和导入的结构体,但未得到预期的结果。当我创建一个x509证书时,我可以打印出像PostalCode这样的值,但当我尝试将其转储为YAML时,嵌套数据看起来是空的。我希望通过这种方式创建并使用YAML黄金文件来测试证书自动化。以下是一个示例。提前感谢任何建议:

https://play.golang.org/p/6XCkq8MUd4H

备注:

我正在查看这些结构体: https://golang.org/pkg/crypto/x509/pkix/#Name

我认为YAML需要与公共结构体一起工作,所以可能这就是我的问题所在:

摘录: // 注意:结构体字段必须是公共的,以便unmarshal能够正确填充数据。


更多关于Golang中YAML序列化与反序列化导入结构体的实现方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

我想我是不假思索地照搬示例语法,结果把自己搞糊涂了。这个可以运行:https://play.golang.org/p/KMmEnYP9Rw9

更多关于Golang中YAML序列化与反序列化导入结构体的实现方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Golang中使用YAML序列化与反序列化导入的结构体时,确实需要注意字段的可访问性。对于crypto/x509/pkix包中的结构体,由于它们包含私有字段,直接使用YAML库处理会遇到问题。以下是解决方案:

解决方案:创建自定义结构体

package main

import (
    "crypto/x509/pkix"
    "fmt"
    "gopkg.in/yaml.v3"
)

// 自定义结构体,仅包含公共字段
type CustomName struct {
    Country            []string `yaml:"country,omitempty"`
    Organization       []string `yaml:"organization,omitempty"`
    OrganizationalUnit []string `yaml:"organizationalUnit,omitempty"`
    Locality           []string `yaml:"locality,omitempty"`
    Province           []string `yaml:"province,omitempty"`
    StreetAddress      []string `yaml:"streetAddress,omitempty"`
    PostalCode         []string `yaml:"postalCode,omitempty"`
    SerialNumber       string   `yaml:"serialNumber,omitempty"`
    CommonName         string   `yaml:"commonName,omitempty"`
}

// 转换为pkix.Name
func (c *CustomName) ToPkixName() pkix.Name {
    return pkix.Name{
        Country:            c.Country,
        Organization:       c.Organization,
        OrganizationalUnit: c.OrganizationalUnit,
        Locality:           c.Locality,
        Province:           c.Province,
        StreetAddress:      c.StreetAddress,
        PostalCode:         c.PostalCode,
        SerialNumber:       c.SerialNumber,
        CommonName:         c.CommonName,
    }
}

// 从pkix.Name创建CustomName
func CustomNameFromPkix(name pkix.Name) CustomName {
    return CustomName{
        Country:            name.Country,
        Organization:       name.Organization,
        OrganizationalUnit: name.OrganizationalUnit,
        Locality:           name.Locality,
        Province:           name.Province,
        StreetAddress:      name.StreetAddress,
        PostalCode:         name.PostalCode,
        SerialNumber:       name.SerialNumber,
        CommonName:         name.CommonName,
    }
}

func main() {
    // 示例:创建pkix.Name
    pkixName := pkix.Name{
        Country:            []string{"US"},
        Organization:       []string{"Example Corp"},
        OrganizationalUnit: []string{"Engineering"},
        Locality:           []string{"San Francisco"},
        Province:           []string{"CA"},
        PostalCode:         []string{"94105"},
        CommonName:         "example.com",
    }
    
    // 转换为自定义结构体
    customName := CustomNameFromPkix(pkixName)
    
    // 序列化为YAML
    yamlData, err := yaml.Marshal(&customName)
    if err != nil {
        panic(err)
    }
    
    fmt.Println("序列化后的YAML:")
    fmt.Println(string(yamlData))
    
    // 反序列化示例
    yamlStr := `
country:
  - US
organization:
  - Example Corp
organizationalUnit:
  - Engineering
locality:
  - San Francisco
province:
  - CA
postalCode:
  - 94105
commonName: example.com
`
    
    var loadedName CustomName
    err = yaml.Unmarshal([]byte(yamlStr), &loadedName)
    if err != nil {
        panic(err)
    }
    
    fmt.Println("\n反序列化后的结构体:")
    fmt.Printf("Country: %v\n", loadedName.Country)
    fmt.Printf("PostalCode: %v\n", loadedName.PostalCode)
    fmt.Printf("CommonName: %s\n", loadedName.CommonName)
    
    // 转换回pkix.Name
    restoredPkixName := loadedName.ToPkixName()
    fmt.Printf("\n恢复的pkix.Name PostalCode: %v\n", restoredPkixName.PostalCode)
}

使用yaml标签控制输出

package main

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

type CertificateConfig struct {
    Subject Subject `yaml:"subject"`
    SANs    []string `yaml:"sans,omitempty"`
    KeySize int      `yaml:"keySize"`
}

type Subject struct {
    Country      string `yaml:"country,omitempty"`
    Province     string `yaml:"province,omitempty"`
    Locality     string `yaml:"locality,omitempty"`
    Organization string `yaml:"organization,omitempty"`
    CommonName   string `yaml:"commonName"`
    Email        string `yaml:"email,omitempty"`
}

func main() {
    config := CertificateConfig{
        Subject: Subject{
            Country:      "US",
            Province:     "California",
            Locality:     "San Francisco",
            Organization: "Test Company",
            CommonName:   "test.example.com",
            Email:        "admin@example.com",
        },
        SANs:    []string{"alt1.example.com", "alt2.example.com"},
        KeySize: 2048,
    }
    
    // 序列化
    data, err := yaml.Marshal(&config)
    if err != nil {
        panic(err)
    }
    
    fmt.Println("证书配置YAML:")
    fmt.Println(string(data))
    
    // 反序列化
    yamlInput := `
subject:
  country: US
  province: New York
  locality: New York City
  organization: Another Company
  commonName: another.example.com
  email: contact@example.com
sans:
  - san1.example.com
  - san2.example.com
keySize: 4096
`
    
    var newConfig CertificateConfig
    err = yaml.Unmarshal([]byte(yamlInput), &newConfig)
    if err != nil {
        panic(err)
    }
    
    fmt.Printf("\n反序列化的CommonName: %s\n", newConfig.Subject.CommonName)
    fmt.Printf("SANs: %v\n", newConfig.SANs)
}

使用mapstructure处理复杂嵌套

package main

import (
    "fmt"
    "github.com/mitchellh/mapstructure"
    "gopkg.in/yaml.v3"
)

type CertificateRequest struct {
    Version  int                    `yaml:"version"`
    Subject  map[string]interface{} `yaml:"subject"`
    KeyUsage []string               `yaml:"keyUsage"`
}

func main() {
    yamlContent := `
version: 3
subject:
  country: GB
  organization: British Company
  organizationalUnit:
    - IT Department
    - Security
  commonName: uk.example.com
keyUsage:
  - digitalSignature
  - keyEncipherment
`
    
    var req CertificateRequest
    err := yaml.Unmarshal([]byte(yamlContent), &req)
    if err != nil {
        panic(err)
    }
    
    fmt.Println("解析后的版本:", req.Version)
    fmt.Println("Subject数据:", req.Subject)
    
    // 使用mapstructure转换为具体类型
    type SubjectDetail struct {
        Country            string   `mapstructure:"country"`
        Organization       string   `mapstructure:"organization"`
        OrganizationalUnit []string `mapstructure:"organizationalUnit"`
        CommonName         string   `mapstructure:"commonName"`
    }
    
    var subject SubjectDetail
    decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
        Result: &subject,
    })
    if err != nil {
        panic(err)
    }
    
    err = decoder.Decode(req.Subject)
    if err != nil {
        panic(err)
    }
    
    fmt.Printf("\n转换后的Subject:\n")
    fmt.Printf("Country: %s\n", subject.Country)
    fmt.Printf("Organization: %s\n", subject.Organization)
    fmt.Printf("OrganizationalUnit: %v\n", subject.OrganizationalUnit)
    fmt.Printf("CommonName: %s\n", subject.CommonName)
}

运行前需要安装依赖:

go get gopkg.in/yaml.v3
go get github.com/mitchellh/mapstructure

这些示例展示了如何处理包含私有字段的标准库结构体,通过创建自定义的公共结构体作为中间层来实现YAML的序列化和反序列化。

回到顶部