求助:递归打印xmltodict解析后的复杂字典为树形结构
解析UML XMI为树形结构的递归打印方案
问题说明
我已经用xmltodict把UML XMI格式的XML文件解析成字典了,代码如下:
with open(xml_file, "r") as f: xml_content = f.read() dct = xmltodict.parse(xml_content)
自己写递归函数打印树形结构时,卡在了层级计数器重置和列表处理上,现有代码逻辑有问题:
def p(d, counter = 0, c = 0): for k, v in d.items(): print("|___"*counter, k) if isinstance(v, dict): c = len(v) if(c > counter): counter += 1 else: counter = 0 p(v, counter, c) elif isinstance(v, list): for i, v2 in enumerate(v): print("|___" * counter, k) p(v2, counter)
想要的输出是类似这样的树形结构:
xmi |_Model |_packagedElement (Root 2) | _ packagedElement (Package1) | - packagedElement (Package2) | _ packagedElement (Package2.1) | _ packagedElement (Package2.2) | _ ownedComment (Note) | _ ...
要求通用,不能用XPATH。
修正后的解决方案
原函数的问题在于用字典长度判断层级完全不合理,而且列表处理时会重复打印键值。下面是修正后的递归函数,核心是传递当前层级深度,针对列表元素做区分标记,还能自动提取UML元素的名称作为后缀:
def print_tree(data, depth=0, indent=""): if isinstance(data, dict): for key, value in data.items(): # 打印当前节点的键,若值是列表则显示列表长度 print(f"{indent}{'|_ ' if depth > 0 else ''}{key}", end="") print(f" (Root {len(value)})\n" if isinstance(value, list) else "\n") # 计算下一层的基础缩进 new_indent = indent + ("| " if depth > 0 else "") if isinstance(value, dict): # 递归处理子字典 print_tree(value, depth + 1, new_indent) elif isinstance(value, list): # 遍历列表中的每个元素 for idx, item in enumerate(value): is_last = idx == len(value) - 1 # 用不同符号区分最后一个列表项 symbol = "- " if is_last else "_ " # 尝试提取元素的name属性作为后缀(符合UML XMI结构) item_label = "" if isinstance(item, dict) and "@name" in item: item_label = f" ({item['@name']})" # 打印列表项 print(f"{new_indent}| {symbol}{key}{item_label}") # 计算列表项子节点的缩进 item_indent = new_indent + (" " if is_last else "| ") # 递归处理列表项的内容 print_tree(item, depth + 2, item_indent) else: # 处理字符串等基础类型值 print(f"{new_indent}|_ {value}")
使用方法
直接把解析得到的字典传进去就行:
print_tree(dct)
关键优化点
- 用层级深度替代原函数的错误计数器逻辑,缩进更准确
- 列表节点自动显示长度(比如
packagedElement (Root 2)) - 列表项区分最后一个元素,用
-和_标记,结构更清晰 - 自动提取UML元素的
@name属性作为后缀,贴合XMI格式特点 - 缩进用
|和区分是否有后续节点,树形结构更直观
内容的提问来源于stack exchange,提问作者brian k.
相关产品推荐
相关产品推荐

