序列化
本示例演示如何将 NuGet 配置对象序列化为 XML 并处理自定义序列化场景。
概述
序列化涉及:
- 将配置对象转换为 XML
- 格式化 XML 输出
- 处理自定义序列化需求
- 使用 XML 模板
- 验证序列化输出
示例 1: 基本序列化
将配置对象转换为 XML:
go
package main
import (
"fmt"
"log"
"github.com/scagogogo/nuget-config-parser/pkg/nuget"
)
func main() {
api := nuget.NewAPI()
// 创建示例配置
config := api.CreateDefaultConfig()
// 添加一些额外的源和设置
api.AddPackageSource(config, "company-feed", "https://nuget.company.com/v3/index.json", "3")
api.AddPackageSource(config, "local-dev", "./packages", "")
api.AddConfigOption(config, "globalPackagesFolder", "/custom/packages")
api.AddCredential(config, "company-feed", "user", "pass")
fmt.Println("=== 基本序列化 ===")
// 序列化为 XML
xmlContent, err := api.SerializeToXML(config)
if err != nil {
log.Fatalf("序列化失败: %v", err)
}
fmt.Println("序列化的 XML:")
fmt.Println(xmlContent)
// 通过解析回来验证
fmt.Println("\n=== 验证 ===")
parsedConfig, err := api.ParseFromString(xmlContent)
if err != nil {
log.Fatalf("解析序列化的 XML 失败: %v", err)
}
fmt.Printf("原始源数量: %d\n", len(config.PackageSources.Add))
fmt.Printf("解析后源数量: %d\n", len(parsedConfig.PackageSources.Add))
if len(config.PackageSources.Add) == len(parsedConfig.PackageSources.Add) {
fmt.Println("✅ 序列化验证成功")
} else {
fmt.Println("❌ 序列化验证失败")
}
}
示例 2: 格式化 XML 输出
创建格式良好的 XML,具有适当的缩进:
go
package main
import (
"fmt"
"log"
"os"
"github.com/scagogogo/nuget-config-parser/pkg/nuget"
)
func main() {
api := nuget.NewAPI()
config := api.CreateDefaultConfig()
// 构建综合配置
buildComprehensiveConfig(api, config)
fmt.Println("=== 格式化 XML 序列化 ===")
// 带格式化的序列化
xmlContent, err := api.SerializeToXML(config)
if err != nil {
log.Fatalf("序列化失败: %v", err)
}
// 显示格式化的 XML
fmt.Println("格式化的 XML 输出:")
fmt.Println(xmlContent)
// 保存到文件并进行适当格式化
outputFile := "FormattedConfig.xml"
err = os.WriteFile(outputFile, []byte(xmlContent), 0644)
if err != nil {
log.Fatalf("写入文件失败: %v", err)
}
fmt.Printf("\n格式化的 XML 已保存到: %s\n", outputFile)
// 显示文件统计信息
info, _ := os.Stat(outputFile)
fmt.Printf("文件大小: %d 字节\n", info.Size())
// 验证输出
validateXMLOutput(api, xmlContent)
}
func buildComprehensiveConfig(api *nuget.API, config *types.NuGetConfig) {
// 添加多个包源
sources := []struct {
key, url, version string
}{
{"nuget.org", "https://api.nuget.org/v3/index.json", "3"},
{"company-stable", "https://stable.company.com/nuget", "3"},
{"company-preview", "https://preview.company.com/nuget", "3"},
{"local-packages", "/path/to/local/packages", ""},
}
for _, source := range sources {
api.AddPackageSource(config, source.key, source.url, source.version)
}
// 添加凭证
api.AddCredential(config, "company-stable", "employee", "secret123")
api.AddCredential(config, "company-preview", "employee", "preview_token")
// 添加配置选项
options := map[string]string{
"globalPackagesFolder": "/custom/packages",
"repositoryPath": "./packages",
"dependencyVersion": "Highest",
"automaticPackageRestore": "true",
"defaultPushSource": "https://stable.company.com/nuget",
}
for key, value := range options {
api.AddConfigOption(config, key, value)
}
// 禁用预览源
api.DisablePackageSource(config, "company-preview")
// 设置活跃源
api.SetActivePackageSource(config, "nuget.org", "https://api.nuget.org/v3/index.json")
}
func validateXMLOutput(api *nuget.API, xmlContent string) {
fmt.Println("\n=== XML 验证 ===")
// 解析序列化的 XML
parsedConfig, err := api.ParseFromString(xmlContent)
if err != nil {
fmt.Printf("❌ XML 验证失败: %v\n", err)
return
}
fmt.Println("✅ XML 有效且可解析")
// 检查结构完整性
checks := []struct {
name string
condition bool
}{
{"包源存在", len(parsedConfig.PackageSources.Add) > 0},
{"凭证存在", parsedConfig.PackageSourceCredentials != nil},
{"配置选项存在", parsedConfig.Config != nil && len(parsedConfig.Config.Add) > 0},
{"活跃源已设置", parsedConfig.ActivePackageSource != nil},
{"禁用源存在", parsedConfig.DisabledPackageSources != nil},
}
for _, check := range checks {
status := "❌"
if check.condition {
status = "✅"
}
fmt.Printf("%s %s\n", status, check.name)
}
}
示例 3: 自定义 XML 模板
使用 XML 模板和自定义序列化:
go
package main
import (
"fmt"
"log"
"strings"
"text/template"
"github.com/scagogogo/nuget-config-parser/pkg/nuget"
)
func main() {
api := nuget.NewAPI()
fmt.Println("=== 自定义 XML 模板 ===")
// 创建配置数据
configData := ConfigTemplateData{
PackageSources: []PackageSourceData{
{"nuget.org", "https://api.nuget.org/v3/index.json", "3"},
{"company-feed", "https://nuget.company.com/v3/index.json", "3"},
},
GlobalPackagesFolder: "/custom/packages",
RepositoryPath: "./packages",
DependencyVersion: "Highest",
ActiveSource: "nuget.org",
}
// 使用模板生成 XML
xmlContent, err := generateXMLFromTemplate(configData)
if err != nil {
log.Fatalf("模板生成失败: %v", err)
}
fmt.Println("从模板生成的 XML:")
fmt.Println(xmlContent)
// 解析生成的 XML
config, err := api.ParseFromString(xmlContent)
if err != nil {
log.Fatalf("解析模板 XML 失败: %v", err)
}
fmt.Printf("\n从模板解析了 %d 个包源\n", len(config.PackageSources.Add))
// 与标准序列化比较
compareWithStandardSerialization(api, config)
}
type ConfigTemplateData struct {
PackageSources []PackageSourceData
GlobalPackagesFolder string
RepositoryPath string
DependencyVersion string
ActiveSource string
}
type PackageSourceData struct {
Key string
Value string
ProtocolVersion string
}
const xmlTemplate = `<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
{{- range .PackageSources }}
<add key="{{ .Key }}" value="{{ .Value }}"{{if .ProtocolVersion}} protocolVersion="{{ .ProtocolVersion }}"{{end}} />
{{- end }}
</packageSources>
<activePackageSource>
<add key="{{ .ActiveSource }}" value="{{range .PackageSources}}{{if eq .Key $.ActiveSource}}{{.Value}}{{end}}{{end}}" />
</activePackageSource>
<config>
<add key="globalPackagesFolder" value="{{ .GlobalPackagesFolder }}" />
<add key="repositoryPath" value="{{ .RepositoryPath }}" />
<add key="dependencyVersion" value="{{ .DependencyVersion }}" />
</config>
</configuration>`
func generateXMLFromTemplate(data ConfigTemplateData) (string, error) {
tmpl, err := template.New("nuget-config").Parse(xmlTemplate)
if err != nil {
return "", fmt.Errorf("模板解析失败: %w", err)
}
var buf strings.Builder
err = tmpl.Execute(&buf, data)
if err != nil {
return "", fmt.Errorf("模板执行失败: %w", err)
}
return buf.String(), nil
}
func compareWithStandardSerialization(api *nuget.API, config *types.NuGetConfig) {
fmt.Println("\n=== 与标准序列化比较 ===")
// 使用标准方法序列化
standardXML, err := api.SerializeToXML(config)
if err != nil {
log.Printf("标准序列化失败: %v", err)
return
}
fmt.Println("标准序列化:")
fmt.Println(standardXML)
// 比较长度
fmt.Printf("\n模板 XML 长度: %d 字符\n", len(xmlTemplate))
fmt.Printf("标准 XML 长度: %d 字符\n", len(standardXML))
}
示例 4: 批量序列化
序列化多个配置:
go
package main
import (
"fmt"
"log"
"os"
"path/filepath"
"github.com/scagogogo/nuget-config-parser/pkg/nuget"
)
func main() {
api := nuget.NewAPI()
fmt.Println("=== 批量序列化 ===")
// 为多个环境创建配置
environments := []string{"development", "staging", "production"}
for _, env := range environments {
fmt.Printf("\n创建 %s 配置...\n", env)
config := createEnvironmentConfig(api, env)
// 序列化配置
xmlContent, err := api.SerializeToXML(config)
if err != nil {
log.Printf("序列化 %s 配置失败: %v", env, err)
continue
}
// 保存到环境特定文件
filename := fmt.Sprintf("NuGet.%s.Config", env)
err = os.WriteFile(filename, []byte(xmlContent), 0644)
if err != nil {
log.Printf("保存 %s 配置失败: %v", env, err)
continue
}
fmt.Printf("✅ %s 配置已保存到 %s\n", env, filename)
// 显示配置摘要
displayConfigSummary(config, env)
}
// 创建包含所有环境的主配置
createMasterConfiguration(api, environments)
}
func createEnvironmentConfig(api *nuget.API, environment string) *types.NuGetConfig {
config := api.CreateDefaultConfig()
switch environment {
case "development":
api.AddPackageSource(config, "nuget.org", "https://api.nuget.org/v3/index.json", "3")
api.AddPackageSource(config, "local-dev", "./packages", "")
api.AddPackageSource(config, "preview", "https://api.nuget.org/v3-flatcontainer", "3")
api.AddConfigOption(config, "globalPackagesFolder", "./dev-packages")
api.AddConfigOption(config, "dependencyVersion", "Highest")
api.AddConfigOption(config, "allowPrereleaseVersions", "true")
api.SetActivePackageSource(config, "local-dev", "./packages")
case "staging":
api.AddPackageSource(config, "nuget.org", "https://api.nuget.org/v3/index.json", "3")
api.AddPackageSource(config, "company-staging", "https://staging.company.com/nuget", "3")
api.AddConfigOption(config, "globalPackagesFolder", "/staging/packages")
api.AddConfigOption(config, "dependencyVersion", "HighestMinor")
api.AddConfigOption(config, "allowPrereleaseVersions", "false")
api.AddCredential(config, "company-staging", "staging_user", "staging_pass")
api.SetActivePackageSource(config, "company-staging", "https://staging.company.com/nuget")
case "production":
api.AddPackageSource(config, "nuget.org", "https://api.nuget.org/v3/index.json", "3")
api.AddPackageSource(config, "company-prod", "https://prod.company.com/nuget", "3")
api.AddConfigOption(config, "globalPackagesFolder", "/prod/packages")
api.AddConfigOption(config, "dependencyVersion", "Exact")
api.AddConfigOption(config, "allowPrereleaseVersions", "false")
api.AddConfigOption(config, "signatureValidationMode", "require")
api.AddCredential(config, "company-prod", "prod_user", "prod_pass")
api.SetActivePackageSource(config, "company-prod", "https://prod.company.com/nuget")
}
return config
}
func displayConfigSummary(config *types.NuGetConfig, environment string) {
fmt.Printf(" %s 配置摘要:\n", environment)
fmt.Printf(" 包源: %d\n", len(config.PackageSources.Add))
if config.Config != nil {
fmt.Printf(" 配置选项: %d\n", len(config.Config.Add))
}
if config.PackageSourceCredentials != nil {
fmt.Printf(" 已认证源: %d\n", len(config.PackageSourceCredentials.Sources))
}
if config.ActivePackageSource != nil {
fmt.Printf(" 活跃源: %s\n", config.ActivePackageSource.Add.Key)
}
}
func createMasterConfiguration(api *nuget.API, environments []string) {
fmt.Println("\n=== 创建主配置 ===")
masterConfig := api.CreateDefaultConfig()
// 添加所有可能的源
allSources := map[string]struct {
url string
version string
}{
"nuget.org": {"https://api.nuget.org/v3/index.json", "3"},
"local-dev": {"./packages", ""},
"preview": {"https://api.nuget.org/v3-flatcontainer", "3"},
"company-staging": {"https://staging.company.com/nuget", "3"},
"company-prod": {"https://prod.company.com/nuget", "3"},
}
for key, source := range allSources {
api.AddPackageSource(masterConfig, key, source.url, source.version)
}
// 默认禁用环境特定源
api.DisablePackageSource(masterConfig, "local-dev")
api.DisablePackageSource(masterConfig, "preview")
api.DisablePackageSource(masterConfig, "company-staging")
api.DisablePackageSource(masterConfig, "company-prod")
// 添加通用配置
api.AddConfigOption(masterConfig, "globalPackagesFolder", "${NUGET_PACKAGES}")
api.AddConfigOption(masterConfig, "dependencyVersion", "HighestMinor")
// 序列化主配置
xmlContent, err := api.SerializeToXML(masterConfig)
if err != nil {
log.Printf("序列化主配置失败: %v", err)
return
}
// 保存主配置
masterFile := "NuGet.Master.Config"
err = os.WriteFile(masterFile, []byte(xmlContent), 0644)
if err != nil {
log.Printf("保存主配置失败: %v", err)
return
}
fmt.Printf("✅ 创建主配置: %s\n", masterFile)
fmt.Printf(" 包含 %v 环境的所有源\n", environments)
}
关键概念
序列化过程
- 对象到 XML: 将配置对象转换为 XML 字符串
- 格式化: 应用适当的缩进和结构
- 验证: 确保输出是有效的 XML
- 往返: 通过解析序列化输出进行验证
XML 结构
序列化的 XML 遵循标准 NuGet.Config 格式:
<packageSources>
: 包源定义<packageSourceCredentials>
: 认证信息<config>
: 全局配置选项<activePackageSource>
: 活跃源选择<disabledPackageSources>
: 禁用的源
最佳实践
- 验证输出: 始终验证序列化的 XML 是否可解析
- 一致格式: 使用适当的缩进和结构
- 处理编码: 确保适当的 UTF-8 编码
- 转义值: 正确转义 XML 特殊字符
- 测试往返: 验证解析 → 序列化 → 解析循环
常见用例
配置导出
go
// 导出当前配置
config, _, _ := api.FindAndParseConfig()
xmlContent, _ := api.SerializeToXML(config)
os.WriteFile("exported-config.xml", []byte(xmlContent), 0644)
模板生成
go
// 从模板生成配置
templateData := ConfigTemplateData{...}
xmlContent, _ := generateXMLFromTemplate(templateData)
config, _ := api.ParseFromString(xmlContent)
批量处理
go
// 处理多个配置
for _, env := range environments {
config := createEnvironmentConfig(api, env)
xmlContent, _ := api.SerializeToXML(config)
saveToFile(fmt.Sprintf("%s.config", env), xmlContent)
}
下一步
掌握序列化后:
本指南为将 NuGet 配置对象序列化为 XML 提供了全面的示例,涵盖了从基本输出到复杂模板生成的各种场景。