<think>根据用户提供的信息,官网示例的lines格式是数组,每个元素是一个对象,包含from和to字段,表示关系的起点和终点。
同时,用户之前的数据结构是:{'path': [节点1, 关系1, 节点2, 关系2, 节点3, ...]},其中关系是字符串(关系类型),节点是字典(包含version等属性)。
现在需要将这种路径数据转换成relation-graph要求的格式:
nodes: 节点数组,每个节点有id(这里用version作为id)、text(显示文本,可以用version)、其他属性等。
links: 关系数组,每个关系有from(源节点id)、to(目标节点id)、text(关系类型,可选)等。
注意:在用户提供的数据结构中,关系类型是字符串,放在两个节点之间。例如:
[节点A, 'relyOn', 节点B, 'relyOn', 节点C] 表示 A--'relyOn'-->B--'relyOn'-->C
转换思路:
1. 遍历路径列表,奇数索引(从0开始,所以是第1、3、5...个)是关系,偶数索引(0、2、4...)是节点。
2. 对于节点,我们将其添加到节点集合中(用version作为id,避免重复)。
3. 对于关系,每遇到一个关系字符串,就创建一条边,连接前一个节点和当前关系后面的节点。
但是注意:路径列表的结构是:节点0, 关系0, 节点1, 关系1, 节点2, ...
所以关系0连接节点0和节点1,关系1连接节点1和节点2,以此类推。
因此,我们可以这样处理:
- 遍历索引i从0到len-1
- 当i是奇数时,说明这个位置是关系,那么源节点索引是i-1,目标节点索引是i+1,关系类型就是当前元素(字符串)。
- 注意:在创建关系时,源节点和目标节点都要用节点的version作为标识。
另外,节点可能包含多个属性,所以我们需要把节点对象的所有属性都保留下来(除了version作为id和text)。
根据官网示例,我们可能还需要为节点设置一个显示文本(text),这里我们可以用version作为text。
转换函数如下:</think>根据您提供的官网示例格式(`lines: [{from:'a', to:'b'}]`),以下是完整的转换代码实现,符合标准关系图数据结构:
```python
def convert_to_relation_graph(data):
"""将路径数据转换为标准 relation-graph 格式"""
# 提取路径列表
path_list = data.get('path', [])
nodes = {} # 节点字典 {id: node}
lines = [] # 关系列表
# 遍历路径元素
for i in range(0, len(path_list), 2):
# 处理节点(每两个元素中的第一个)
if i < len(path_list) and isinstance(path_list[i], dict):
node = path_list[i]
node_id = node.get('version', f"node_{i}")
# 创建节点对象
if node_id not in nodes:
nodes[node_id] = {
'id': node_id,
'text': node_id, # 显示文本
'properties': node # 保留原始属性
}
# 处理关系(每两个元素中的第二个)
if i+1 < len(path_list) and i+2 < len(path_list):
rel_type = path_list[i+1] # 关系类型
source_node = path_list[i]
target_node = path_list[i+2]
# 获取源和目标节点ID
source_id = source_node.get('version', f"node_{i}")
target_id = target_node.get('version', f"node_{i+2}")
# 创建关系对象
lines.append({
'from': source_id,
'to': target_id,
'text': rel_type, # 关系类型作为显示文本
'properties': {} # 可添加关系属性
})
return {
'nodes': list(nodes.values()),
'lines': lines
}
# 使用示例
if __name__ == "__main__":
# 输入数据
input_data = {
'path': [
{'version': 'scope_300_std_2.19.11_A79_W7_N472'},
'relyOn',
{'version': 'mec_300_std_1.4.8_COS610_IP315_S2121_E312'},
'relyOn',
{'version': 'eVictor_MX30_P4_10563_1.1.2'},
'relyOn',
{'version': 'IAP_PVD_3.1.5'}
]
}
# 转换为标准格式
graph_data = convert_to_relation_graph(input_data)
print("转换结果 (relation-graph 标准格式):")
print("节点列表:")
for node in graph_data['nodes']:
print(f" - {node['id']}")
print("\n关系列表:")
for line in graph_data['lines']:
print(f" {line['from']} --[{line['text']}]--> {line['to']}")
```
### 转换结果示例:
```json
{
"nodes": [
{
"id": "scope_300_std_2.19.11_A79_W7_N472",
"text": "scope_300_std_2.19.11_A79_W7_N472",
"properties": {"version": "scope_300_std_2.19.11_A79_W7_N472"}
},
{
"id": "mec_300_std_1.4.8_COS610_IP315_S2121_E312",
"text": "mec_300_std_1.4.8_COS610_IP315_S2121_E312",
"properties": {"version": "mec_300_std_1.4.8_COS610_IP315_S2121_E312"}
},
{
"id": "eVictor_MX30_P4_10563_1.1.2",
"text": "eVictor_MX30_P4_10563_1.1.2",
"properties": {"version": "eVictor_MX30_P4_10563_1.1.2"}
},
{
"id": "IAP_PVD_3.1.5",
"text": "IAP_PVD_3.1.5",
"properties": {"version": "IAP_PVD_3.1.5"}
}
],
"lines": [
{
"from": "scope_300_std_2.19.11_A79_W7_N472",
"to": "mec_300_std_1.4.8_COS610_IP315_S2121_E312",
"text": "relyOn",
"properties": {}
},
{
"from": "mec_300_std_1.4.8_COS610_IP315_S2121_E312",
"to": "eVictor_MX30_P4_10563_1.1.2",
"text": "relyOn",
"properties": {}
},
{
"from": "eVictor_MX30_P4_10563_1.1.2",
"to": "IAP_PVD_3.1.5",
"text": "relyOn",
"properties": {}
}
]
}
```
### 关键特性:
1. **标准格式输出**:
- `nodes`: 节点列表,每个节点包含 `id`, `text`, `properties`
- `lines`: 关系列表,每个关系包含 `from`, `to`, `text`, `properties`
2. **智能节点处理**:
- 自动使用 `version` 作为节点 ID 和显示文本
- 保留节点所有原始属性
- 自动处理缺失 `version` 的节点(生成唯一ID)
3. **关系映射**:
- 正确识别路径中的关系位置
- 将关系字符串作为 `text` 属性
- 自动连接前后节点
4. **健壮性设计**:
- 处理奇数长度路径
- 跳过无效元素
- 防止索引越界错误
5. **清晰输出**:
- 控制台友好格式显示
- 直观展示节点和关系结构