Skip to content

Instantly share code, notes, and snippets.

@ImN1
Created March 4, 2022 06:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ImN1/cbcbfabb9ed2f277c926427f4598bbb7 to your computer and use it in GitHub Desktop.
Save ImN1/cbcbfabb9ed2f277c926427f4598bbb7 to your computer and use it in GitHub Desktop.
python xpath string/text convert to nested dict
import json
def xpath2Dict(xpaths, nested:bool=True, sep:str='/')->Dict:
'''
xpaths: String | Iterable,前者按 splitlines 拆分为后者\n
可以包含或不包含枝节点,例如:\n
topnode/node\n
topnode/node/leaf\n
两条同时存在,或者仅有第二条,都能构建树状 dict。\n
分隔符在开头或结尾都会舍弃,相应的首节点、末节点按照处理后的 xpath 计算\n
leaf 将优先视为 json 格式,按 json.loads 处理,不能处理才按 string 构建末节点的值\n
如果 leaf 只有单值(整数、小数或字符串等),字典的值为一维列表\n
如果 leaf 为列表等对象,则值为二维列表(整数、小数或字符串等转为单元素列表)\n
nested: bool, default True\n
True: 返回格式 {'topnode': {'node': leaf}}\n
False: 返回格式 {'topnode/node': leaf}
'''
def tryJson(item):
try:
return json.loads(item)
except:
return item
if isinstance(xpaths, (str, bytes)):
xpaths = xpaths.splitlines()
# xpaths = sorted(xpaths.splitlines())
# xpaths = sorted(xpaths, key=lambda x: x.count(sep), reverse=True)
fd0 = (x.strip(sep).rsplit(sep, 1) for x in xpaths)
# fd = dict((x[0], tryJson(x[1])) for x in fd)
fd = {}
dims = False
for x in fd0:
key = x[0]
v = tryJson(x[1])
if isinstance(v, (int, float, complex, str, bytes, type(None))):
v = [v]
else:
dims = True
if key in fd:
value = fd[key]
value.append(v)
else:
value = [v]
fd[key] = value
if not dims:
fd = {k:list(chain.from_iterable(v)) for k,v in fd.items()}
if not nested:
return fd
def insert(dct, lst):
for x in lst[:-2]:
dct[x] = dct = dct.get(x, dict())
dct.update({lst[-2]: lst[-1]})
d = {}
lsts = ([*k.split(sep), v] for k, v in fd.items())
for lst in lsts:
insert(d, lst)
return d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment