如何用Quickfix/Go将FIX消息解析为可读JSON并处理字段组?
Quickfix/Go 解析FIX消息字段组并生成可读JSON
核心解决思路
要处理FIX消息中的字段组(对应NUMINGROUP类型字段),需借助Quickfix/Go的GroupTemplate和GetGroup方法递归解析组内数据。关键是通过数据字典获取组的结构定义,再逐个读取组实例并处理内部字段。
递归解析FieldMap(含字段组)的打印实现
以下是修改后的递归打印函数,支持解析嵌套字段组:
import ( "fmt" "quickfix" "quickfix/datadictionary" ) // PrintFieldMap 递归打印FieldMap内容,包含所有层级的字段组 func PrintFieldMap(fieldMap quickfix.FieldMap, dd *datadictionary.DataDictionary) { for _, tag := range fieldMap.Tags() { tagNum := quickfix.Tag(tag) value, err := fieldMap.GetString(tagNum) if err != nil { fmt.Printf("Tag %d: 获取值失败 - %v\n", tag, err) continue } fieldType, ok := dd.FieldTypeByTag[int(tag)] if !ok { fmt.Printf("Tag %d: 未在字典中定义 - 值: %s\n", tag, value) continue } fieldName := fieldType.Name() fmt.Printf("%s (%d): %s\n", fieldName, tag, value) // 处理字段组 if fieldType.Type == "NUMINGROUP" { groupDef, ok := dd.MessageDataDictionary.FieldGroups[int(tag)] if !ok { fmt.Printf("%s (%d): 未找到对应的组定义\n", fieldName, tag) continue } // 获取组的重复次数 groupCount, err := fieldMap.GetInt(tagNum) if err != nil { fmt.Printf("%s (%d): 获取组实例数量失败 - %v\n", fieldName, tag, err) continue } fmt.Printf("%s (%d): 共包含 %d 个组实例\n", fieldName, tag, groupCount) // 创建组模板,指定组起始Tag和组内字段Tag groupTemplate := quickfix.NewGroupTemplate(quickfix.Tag(groupDef.GroupTag), groupDef.Fields...) // 遍历每个组实例 for i := 1; i <= int(groupCount); i++ { group := quickfix.NewFieldMap() err := fieldMap.GetGroup(i, groupTemplate, group) if err != nil { fmt.Printf("第 %d 个组实例: 获取失败 - %v\n", i, err) continue } fmt.Printf("--- 组实例 %d ---\n", i) // 递归解析组内字段 PrintFieldMap(group, dd) } } } }
生成可读JSON的实现
如果需要直接生成字段名:值格式的JSON,可使用以下递归转换函数:
import ( "encoding/json" "fmt" "quickfix" "quickfix/datadictionary" ) // FieldMapToJSON 将FieldMap转换为以字段名为键的可读JSON结构 func FieldMapToJSON(fieldMap quickfix.FieldMap, dd *datadictionary.DataDictionary) map[string]interface{} { result := make(map[string]interface{}) for _, tag := range fieldMap.Tags() { tagNum := quickfix.Tag(tag) value, err := fieldMap.GetString(tagNum) if err != nil { result[fmt.Sprintf("Tag_%d", tag)] = fmt.Sprintf("获取值失败: %v", err) continue } fieldType, ok := dd.FieldTypeByTag[int(tag)] if !ok { result[fmt.Sprintf("Tag_%d", tag)] = value continue } fieldName := fieldType.Name() if fieldType.Type == "NUMINGROUP" { groupDef, ok := dd.MessageDataDictionary.FieldGroups[int(tag)] if !ok { result[fieldName] = fmt.Sprintf("未找到组定义,原始值: %s", value) continue } groupCount, err := fieldMap.GetInt(tagNum) if err != nil { result[fieldName] = fmt.Sprintf("获取组实例数失败: %v", err) continue } groupTemplate := quickfix.NewGroupTemplate(quickfix.Tag(groupDef.GroupTag), groupDef.Fields...) var groupList []map[string]interface{} for i := 1; i <= int(groupCount); i++ { group := quickfix.NewFieldMap() err := fieldMap.GetGroup(i, groupTemplate, group) if err != nil { groupList = append(groupList, map[string]interface{}{ "error": fmt.Sprintf("组实例 %d 获取失败: %v", i, err), }) continue } // 递归转换组内字段 groupList = append(groupList, FieldMapToJSON(group, dd)) } result[fieldName] = groupList } else { result[fieldName] = value } } return result } // 使用示例 func ExampleUsage(message quickfix.Message, dd *datadictionary.DataDictionary) { // 转换消息体为JSON结构 bodyJSON := FieldMapToJSON(message.Body, dd) // 格式化输出JSON jsonBytes, err := json.MarshalIndent(bodyJSON, "", " ") if err != nil { fmt.Println("JSON序列化失败:", err) return } fmt.Println(string(jsonBytes)) }
关键说明
GroupTemplate是解析组的核心,需传入组的起始Tag和组内所有字段的Tag列表,这些信息可从数据字典的FieldGroups中获取- 递归处理支持嵌套字段组(组内再包含组)的解析
- 若字典中未找到组定义,会降级保留原始Tag和值,避免解析中断
内容的提问来源于stack exchange,提问作者Atmo101
相关产品推荐
相关产品推荐

