You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 12:24:53