将嵌套的 Python OrderedDict 转换为 QJSValue

Convert a nested Python OrderedDict into a QJSValue

我有一些嵌套的 python OrderedDicts,例如

# The Object we need to convert

od = OrderedDict(
    [
        ('header', OrderedDict(
            [
                ('stamp', OrderedDict(
                    [
                        ('sec', 42),
                        ('nanosec', 99)
                    ]
                )
                ),
                ('frame_id', 'world')
            ]
        )
        ),
        ('name', ['x', 'y', 'z']),
        ('position', [1.0, 2.0, 3.0]),
        ('velocity', [0.0, 0.0, 0.0]),
        ('effort', [0.0, 0.0, 0.0])
    ]
)

我需要将其转换为 QJSValue。

如果需要,可以为执行此操作的函数提供 QJSValue 原型。这是上述值的原型。这可能会使事情变得更容易,尤其是在转换列表部分时。

# A JS Prototype that has the feilds and types, and just needs its values populating

app = QCoreApplication()
engine = QJSEngine()
joint_state_msg_js = engine.newObject()
header_msg_js = engine.newObject()
stamp_msg_js = engine.newObject()
stamp_msg_js.setProperty('sec',0)
stamp_msg_js.setProperty('nanosec',0)
header_msg_js.setProperty('stamp', stamp_msg_js)
header_msg_js.setProperty('frame_id', '')
joint_state_msg_js.setProperty('header', header_msg_js)
joint_state_msg_js.setProperty('name', engine.newArray(3))
joint_state_msg_js.setProperty('position', engine.newArray(3))
joint_state_msg_js.setProperty('velocity', engine.newArray(3))
joint_state_msg_js.setProperty('effort', engine.newArray(3))

prototype = joint_state_msg_js
print(prototype.toVariant())

OrderedDict 可以有任何深度。

我一直在尝试编写一个从 OrderedDict 创建 QJSValue 或填充原型值的函数,但我不知道该怎么做。它需要与任何 OrderedDict(原始类型或其他 OrderedDicts 的任何 OrderedDict)一起使用。

这个函数怎么写?

这是我的尝试之一:

def to_qjs_value(od: OrderedDict, prototype: QJSValue) -> QJSValue:

    for field_name in od:
        inner_dict_or_value = od[field_name]
        if isinstance(inner_dict_or_value, OrderedDict):
            inner_dict = inner_dict_or_value
            inner_dict_js = to_qjs_value(inner_dict, prototype) # recursion
            prototype.setProperty(field_name, inner_dict_js)            
        else:
            inner_value = inner_dict_or_value
            if isinstance(inner_value, list):
                jslist = QJSValue()
                i=0
                for inner_list_value in inner_value:
                    jslist.setProperty(i, inner_list_value)
                    i=i+1
                prototype.setProperty(field_name, jslist)
            else:
                prototype.setProperty(field_name, inner_value)
    return prototype

但这会使结果变平,并且不会填充列表。

{
    'effort': None,
    'frame_id': 'world',
    'header': {},
    'name': None,
    'nanosec': 99,
    'position': None,
    'sec': 42,
    'stamp': {},
    'velocity': None
}

使用或不使用原型的解决方案都可以。

一种可能的解决方案是使用 json.dumps() 将字典转换为字符串 json,然后使用 JSON.Parse:

将字符串转换为对象
app = QCoreApplication()
engine = QJSEngine()

od_json = json.dumps(od)
converter = engine.evaluate("JSON.parse")
qjsvalue = converter.call([QJSValue(od_json)])


assert (
    qjsvalue.property("header").property("stamp").property("sec").equals(QJSValue(42.0))
)