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
我想我是不假思索地照搬示例语法,结果把自己搞糊涂了。这个可以运行: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的序列化和反序列化。

