使用字典和数组将点符号字符串转换为嵌套的Python对象 [英] Convert Dot notation string into nested Python object with Dictionaries and arrays

查看:86
本文介绍了使用字典和数组将点符号字符串转换为嵌套的Python对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在某些背景下,我试图创建一个使用Python 3.5将工作表转换为API调用的工具

For some background, I'm trying to create a tool that converts worksheets into API calls using Python 3.5

为了将表格单元格转换为API调用所需的架构,我已经开始使用对电子表格中的标头使用javascript之类的语法的方法.例如:

For the conversion of the table cells to the schema needed for the API call, I've started down the path of using javascript like syntax for the headers used in the spreadsheet. e.g:

工作表标题(字符串)

dict.list[0].id

Python字典

{
  "dict":
    "list": [
      {"id": "my cell value"}
    ]
}

标题模式也可能具有嵌套的数组/字典:

It's also possible that the header schema could have nested arrays/dicts:

one.two[0].three[0].four.five[0].six

在创建每个对象时,我还需要将其添加到对象之后.

And I also need to append to the object after it has been created as I go through each header.

基于 https://stackoverflow.com/a/47276490/2903486 我能够获取嵌套字典设置使用one.two.three.four之类的值,并且在浏览行时能够附加到现有字典中,但是我无法添加对数组的支持:

Based on https://stackoverflow.com/a/47276490/2903486 I am able to get nested dictionaries setup using values like one.two.three.four and I'm able to append to the existing dictionary as I go through the rows but I've been unable to add in support for arrays:

def add_branch(tree, vector, value):
    key = vector[0]
    tree[key] = value \
        if len(vector) == 1 \
        else add_branch(tree[key] if key in tree else {},
                        vector[1:],
                        value)
    return tree

file = Worksheet(filePath, sheet).readRow()
rowList = []
for row in file:
    rowObj = {}
    for colName, rowValue in row.items():
        rowObj.update(add_branch(rowObj, colName.split("."), rowValue))
    rowList.append(rowObj)
return rowList

我自己的add_branch版本

import re, json
def branch(tree, vector, value):
    """
    Used to convert JS style notation (e.g dict.another.array[0].id) to a python object
    Originally based on https://stackoverflow.com/a/47276490/2903486
    """

    # Convert Boolean
    if isinstance(value, str):
        value = value.strip()

        if value.lower() in ['true', 'false']:
            value = True if value.lower() == "true" else False

    # Convert JSON
    try:
        value = json.loads(value)
    except:
        pass

    key = vector[0]
    arr = re.search('\[([0-9]+)\]', key)
    if arr:
        arr = arr.group(0)
        key = key.replace(arr, '')
        arr = arr.replace('[', '').replace(']', '')

        newArray = False
        if key not in tree:
            tree[key] = []
            tree[key].append(value \
                                 if len(vector) == 1 \
                                 else branch({} if key in tree else {},
                                             vector[1:],
                                             value))
        else:
            isInArray = False
            for x in tree[key]:
                if x.get(vector[1:][0], False):
                    isInArray = x[vector[1:][0]]

            if isInArray:
                tree[key].append(value \
                                     if len(vector) == 1 \
                                     else branch({} if key in tree else {},
                                                 vector[1:],
                                                 value))
            else:

                tree[key].append(value \
                                     if len(vector) == 1 \
                                     else branch({} if key in tree else {},
                                                 vector[1:],
                                                 value))

        if len(vector) == 1 and len(tree[key]) == 1:
            tree[key] = value.split(",")
    else:
        tree[key] = value \
            if len(vector) == 1 \
            else branch(tree[key] if key in tree else {},
                        vector[1:],
                        value)
    return tree

还有哪些需要帮助

添加了一些东西后,我的分支解决方案现在实际上运行良好,但是我想知道我是在这里做错了什么/乱七八糟的东西,还是有更好的方法来处理我在哪里编辑嵌套数组(尝试从在代码的if IsInArray部分中

我希望这两个标头可以编辑最后一个数组,但是我最终在第一个数组上创建了一个重复的字典:

I'd expect these two headers to edit the last array, but instead I end up creating a duplicate dictionary on the first array:

file = [{
    "one.array[0].dict.arrOne[0]": "1,2,3",
    "one.array[0].dict.arrTwo[0]": "4,5,6"
}]
rowList = []
for row in file:
    rowObj = {}
    for colName, rowValue in row.items():
        rowObj.update(add_branch(rowObj, colName.split("."), rowValue))
    rowList.append(rowObj)
return rowList

输出:

[
    {
        "one": {
            "array": [
                {
                    "dict": {
                        "arrOne": [
                            "1",
                            "2",
                            "3"
                        ]
                    }
                },
                {
                    "dict": {
                        "arrTwo": [
                            "4",
                            "5",
                            "6"
                        ]
                    }
                }
            ]
        }
    }
]

代替:

[
    {
        "one": {
            "array": [
                {
                    "dict": {
                        "arrOne": [
                            "1",
                            "2",
                            "3"
                        ],
                        "arrTwo": [
                            "4",
                            "5",
                            "6"
                        ]
                    }
                }
            ]
        }
    }
]

推荐答案

所以我不确定此解决方案是否有任何警告,但这似乎适用于我抛出的一些用例:

So I'm not sure if there are any caveats in this solution, but this appears to work for some of the use cases i'm throwing at it:

import json, re
def build_job():

    def branch(tree, vector, value):

        # Originally based on https://stackoverflow.com/a/47276490/2903486

        # Convert Boolean
        if isinstance(value, str):
            value = value.strip()

            if value.lower() in ['true', 'false']:
                value = True if value.lower() == "true" else False

        # Convert JSON
        try:
            value = json.loads(value)
        except:
            pass

        key = vector[0]
        arr = re.search('\[([0-9]+)\]', key)

        if arr:

            # Get the index of the array, and remove it from the key name
            arr = arr.group(0)
            key = key.replace(arr,'')
            arr = int(arr.replace('[','').replace(']',''))

            if key not in tree:

                # If we dont have an array already, turn the dict from the previous 
                # recursion into an array and append to it
                tree[key] = []
                tree[key].append(value \
                    if len(vector) == 1 \
                    else branch({} if key in tree else {},
                                vector[1:],
                                value))
            else:

                # Check to see if we are inside of an existing array here
                isInArray = False
                for i in range(len(tree[key])):
                    if tree[key][i].get(vector[1:][0], False):
                        isInArray = tree[key][i][vector[1:][0]]

                if isInArray:
                    # Respond accordingly by appending or updating the value
                    try:
                        tree[key][arr].append(value \
                            if len(vector) == 1 \
                            else branch(tree[key] if key in tree else {},
                                        vector[1:],
                                        value))
                    except:
                        # Make sure we have an index to attach the requested array to
                        while arr >= len(tree[key]):
                            tree[key].append({})

                        tree[key][arr].update(value \
                        if len(vector) == 1 \
                        else branch(tree[key][arr] if key in tree else {},
                                    vector[1:],
                                    value))
                else:
                    # Make sure we have an index to attach the requested array to
                    while arr >= len(tree[key]):
                        tree[key].append({})

                    # update the existing array with a dict
                    tree[key][arr].update(value \
                        if len(vector) == 1 \
                        else branch({} if key in tree else {},
                                    vector[1:],
                                    value))

            # Turn comma deliminated values to lists
            if len(vector) == 1 and len(tree[key]) == 1:
                tree[key] = value.split(",")
        else:
            # Add dictionaries together
            tree.update({key: value \
                if len(vector) == 1 \
                else branch(tree[key] if key in tree else {},
                            vector[1:],
                            value)})
        return tree

    file = [{
        "one.array[0].dict.dont-worry-about-me": "some value",
        "one.array[0].dict.arrOne[0]": "1,2,3",
        "one.array[0].dict.arrTwo[1]": "4,5,6",
        "one.array[1].x.y[0].z[0].id": "789"
    }]
    rowList = []
    for row in file:
        rowObj = {}
        for colName, rowValue in row.items():
            rowObj.update(branch(rowObj, colName.split("."), rowValue))
        rowList.append(rowObj)
    return rowList
print(json.dumps(build_job(), indent=4))

结果:

[
    {
        "one": {
            "array": [
                {
                    "dict": {
                        "dont-worry-about-me": "some value",
                        "arrOne": [
                            "1",
                            "2",
                            "3"
                        ],
                        "arrTwo": [
                            "4",
                            "5",
                            "6"
                        ]
                    }
                },
                {
                    "x": {
                        "y": [
                            {
                                "z": [
                                    {
                                        "id": 789
                                    }
                                ]
                            }
                        ]
                    }
                }
            ]
        }
    }
]

这篇关于使用字典和数组将点符号字符串转换为嵌套的Python对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆