简体   繁体   中英

Convert a nested Python OrderedDict into a QJSValue

I have some nested python OrderedDicts, eg

# 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])
    ]
)

And I need to convert this into a QJSValue.

The function that does this can be given a QJSValue prototype if needed. Here is a prototype for the above value. This might makes things easier, especially when it comes to converting the list parts.

# 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())

The OrderedDict could have any depth.

I keep trying to write a function that creates a QJSValue from the OrderedDict, or populates the prototype values, but I cannot figure out how to do either. It needs to work with any OrderedDict (any OrderedDict of primatives or other OrderedDicts).

How could I write this function?

Here is one of my attempts:

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

but this makes the result flat, and doesn't populate the lists.

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

Either a solution with or without using the prototype will be fine.

One possible solution is to convert the dictionary to string json using json.dumps() , and then the string to objects using 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))
)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM