片段func parseTables(data string) error {
d := xml.NewDecoder(strings.NewReader(data))
for {
var table Table
err := d.Decode(&table)
if err == io.EOF {
break // 解析完成
}
if err != nil {
return fmt.Errorf("decode table failed: %w", err)
}
// ✅ 关键步骤:根据 table.Name 创建对应业务结构体
switch table.Name {
case "users":
users := make([]User, 0, len(table.Rows))
for _, row := range table.Rows {
users = append(users, NewUserFromRow(row))
}
fmt.Printf("Parsed %d User(s): %+v\n", len(users), users)
case "categories":
cats := make([]Category, 0, len(table.Rows))
for _, row := range table.Rows {
cats = append(cats, NewCategoryFromRow(row))
}
fmt.Printf("Parsed %d Category(ies): %+v\n", len(cats), cats)
default:
fmt.Printf("Skipped unknown table: %s\n", table.Name)
}
}
return nil
}
✅ 按行构建业务对象(类型安全 + 可扩展)
以 user 为例,定义结构体并提供行解析方法:
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
func NewUserFromRow(r Row) User {
var u User
for _, col := range r.Cols {
switch col.Name {
case "id":
if id, err := strconv.Atoi(col.Value); err == nil {
u.ID = id
}
case "name":
u.Name = col.Value
case "email":
u.Email = col.Value
}
}
return u
}
同理可为 Category、Product 等定义 NewXxxFromRow() 方法。这种方式完全跳过 Table 中间层,直连原始 XML 到领域模型,兼具类型安全与灵活性。
? 注意事项与最佳实践
-
XML 合法性:确保输入 XML 是良构的(well-formed)。若存在非法字符或未闭合标签,
Decoder.Decode() 会返回具体错误,建议配合 xml.CharsetReader 处理编码(如 UTF-8 BOM)。
-
性能考量:对超大 XML,避免一次性
strings.NewReader(data) 加载全部内存;可改用 os.File 或 bufio.Reader 流式读取。
-
错误容忍:生产环境建议增加字段缺失/类型转换失败的兜底逻辑(如默认值、日志告警),而非 panic。
-
扩展性:若表结构频繁变化,可将列名→字段映射关系外置为配置(JSON/YAML),实现“配置驱动解析”。
通过以上方式,你既能精准处理 name 属性驱动的动态 schema,又能无缝对接 Go 的强类型生态,真正实现“XML 即数据,解码即建模”。