LibreOffice宏生成树形CSV自定义ID:子节点ID生成失败修正
问题:树形结构CSV生成规则ID的宏代码修正
我有一个树形结构的CSV文件,行数据通过Id(A列)与ParentId(B列)字段对应父子节点关系。需要在H列生成符合规则的ID:
- 含“RecordGrp”(E列)的行生成以“2022-54-”开头的递增ID
- 其子节点也按顺序生成连续递增的ID
当前使用的宏代码无法为子节点正确生成ID,期望的输出示例如下(H列为生成的目标ID):
ID290,ID11,..\Phase2-fusionner_dossiers\Dossiers\TA30\Dossier n° 1300254\T30_1300254_69402_accuse reception courrier.pdf,..\Phase2-fusionner_dossiers\Dossiers\TA30\Dossier n° 1300254\T30_1300254_69402_accuse reception courrier.pdf,Item,T30_1300254_69402_accuse reception courrier.pdf,,2022-54-2 ID293,ID11,..\Phase2-fusionner_dossiers\Dossiers\TA30\Dossier n° 1300254\T30_1300254_69417_accuse reception courrier.pdf,..\Phase2-fusionner_dossiers\Dossiers\TA30\Dossier n° 1300254\T30_1300254_69417_accuse reception courrier.pdf,Item,T30_1300254_69417_accuse reception courrier.pdf,,2022-54-3 ID11,ID10,..\Phase2-fusionner_dossiers\Dossiers\TA30\Dossier n° 1300254,,RecordGrp,Dossier n° 1300254,,2022-54-1 ID333,ID294,..\Phase2-fusionner_dossiers\Dossiers\TA30\Dossier n° 1300826\T30_1300826_53417_accuse reception courrier.pdf,..\Phase2-fusionner_dossiers\Dossiers\TA30\Dossier n° 1300826\T30_1300826_53417_accuse reception courrier.pdf,Item,T30_1300826_53417_accuse reception courrier.pdf,,2022-54-5 ID336,ID294,..\Phase2-fusionner_dossiers\Dossiers\TA30\Dossier n° 1300826\T30_1300826_59180_accuse mise a disposition courrier.pdf,..\Phase2-fusionner_dossiers\Dossiers\TA30\Dossier n° 1300826\T30_1300826_59180_accuse mise a disposition courrier.pdf,Item,T30_1300826_59180_accuse mise a disposition courrier.pdf,,2022-54-6 ID339,ID294,..\Phase2-fusionner_dossiers\Dossiers\TA30\Dossier n° 1300826\T30_1300826_59390_accuse reception courrier.pdf,..\Phase2-fusionner_dossiers\Dossiers\TA30\Dossier n° 1300826\T30_1300826_59390_accuse reception courrier.pdf,Item,T30_1300826_59390_accuse reception courrier.pdf,,2022-54-7 ID294,ID10,..\Phase2-fusionner_dossiers\Dossiers\TA30\Dossier n° 1300826,,RecordGrp,Dossier n° 1300826,,2022-54-4 ID400,ID340,..\Phase2-fusionner_dossiers\Dossiers\TA30\Dossier n° 1300897\T30_1300897_69841_accuse mise a disposition courrier.pdf,..\Phase2-fusionner_dossiers\Dossiers\TA30\Dossier n° 1300897\T30_1300897_69841_accuse mise a disposition courrier.pdf,Item,T30_1300897_69841_accuse mise a disposition courrier.pdf,,2022-54-9 ID403,ID340,..\Phase2-fusionner_dossiers\Dossiers\TA30\Dossier n° 1300897\T30_1300897_69858_accuse reception courrier.pdf,..\Phase2-fusionner_dossiers\Dossiers\TA30\Dossier n° 1300897\T30_1300897_69858_accuse reception courrier.pdf,Item,T30_1300897_69858_accuse reception courrier.pdf,,2022-54-10 ID340,ID10,..\Phase2-fusionner_dossiers\Dossiers\TA30\Dossier n° 1300897,,RecordGrp,Dossier n° 1300897,,2022-54-8
原宏代码
Dim oSheet As Object Dim oCursor As Object Dim lastRow As Long Dim currentId As String Dim counter As Long Dim parentMap As Object Dim row As Long ' Initialiser la feuille active et les variables oSheet = ThisComponent.CurrentController.ActiveSheet oCursor = oSheet.createCursor() oCursor.gotoEndOfUsedArea(True) lastRow = oCursor.RangeAddress.EndRow Set parentMap = CreateObject("Scripting.Dictionary") counter = 1 currentId = "2022-54-" ' Parcourir les lignes For row = 1 To lastRow Dim title As String Dim descriptionLevel As String Dim parentId As String Dim id As String Dim newId As String title = oSheet.getCellByPosition(5, row).String ' Colonne F : Content.Title descriptionLevel = oSheet.getCellByPosition(4, row).String ' Colonne E : Content.DescriptionLevel id = oSheet.getCellByPosition(0, row).String ' Colonne A : Id parentId = oSheet.getCellByPosition(1, row).String ' Colonne B : ParentId If descriptionLevel = "RecordGrp" Then ' Nouvel identifiant pour les "RecordGrp" newId = currentId & counter parentMap.Add id, newId oSheet.getCellByPosition(7, row).String = newId ' Colonne H pour l'ID counter = counter + 1 ElseIf parentMap.exists(parentId) Then ' Utiliser l'identifiant du parent pour les enfants newId = currentId & counter oSheet.getCellByPosition(7, row).String = newId ' Colonne H pour l'ID counter = counter + 1 Else ' Si aucun parent trouvé, signaler une erreur oSheet.getCellByPosition(7, row).String = "Erreur : Parent introuvable" End If Next row MsgBox "Identifiants générés avec succès dans la colonne H !" End Sub
问题分析
原代码的核心问题是遍历顺序错误:当前按行号顺序遍历,但示例中RecordGrp父节点(如ID11)在其子节点之后,导致处理子节点时父节点的ID还未存入parentMap,触发错误。此外,原代码仅存储RecordGrp节点的映射,未覆盖所有节点,无法处理多层级树形结构的情况。
修正后的宏代码
Dim oSheet As Object Dim oCursor As Object Dim lastRow As Long Dim currentIdPrefix As String Dim globalCounter As Long Dim nodeMap As Object Dim row As Long ' 初始化工作表和变量 oSheet = ThisComponent.CurrentController.ActiveSheet oCursor = oSheet.createCursor() oCursor.gotoEndOfUsedArea(True) lastRow = oCursor.RangeAddress.EndRow Set nodeMap = CreateObject("Scripting.Dictionary") ' 存储所有节点的原始ID到新ID的映射 globalCounter = 1 currentIdPrefix = "2022-54-" ' 第一步:先遍历所有行,将所有节点ID存入映射(占位符后续填充) For row = 1 To lastRow Dim id As String id = oSheet.getCellByPosition(0, row).String ' 读取A列的原始ID If Not nodeMap.exists(id) Then nodeMap.Add id, "" ' 初始化空值,后续填充新ID End If Next row ' 第二步:遍历所有行,优先处理RecordGrp节点,再处理子节点 For row = 1 To lastRow Dim descriptionLevel As String Dim parentId As String Dim newId As String descriptionLevel = oSheet.getCellByPosition(4, row).String ' E列:Content.DescriptionLevel id = oSheet.getCellByPosition(0, row).String ' A列:Id parentId = oSheet.getCellByPosition(1, row).String ' B列:ParentId If descriptionLevel = "RecordGrp" Then ' 为RecordGrp生成新ID newId = currentIdPrefix & globalCounter nodeMap(id) = newId oSheet.getCellByPosition(7, row).String = newId ' 写入H列 globalCounter = globalCounter + 1 Else ' 处理子节点:检查父节点是否已有映射 If nodeMap.exists(parentId) And nodeMap(parentId) <> "" Then newId = currentIdPrefix & globalCounter nodeMap(id) = newId oSheet.getCellByPosition(7, row).String = newId ' 写入H列 globalCounter = globalCounter + 1 Else ' 父节点未处理或不存在,标记错误 oSheet.getCellByPosition(7, row).String = "Erreur : Parent introuvable" End If End If Next row MsgBox "Identifiants générés avec succès dans la colonne H !" End Sub
修正说明
- 两次遍历逻辑:第一次遍历先将所有节点ID存入
nodeMap,确保无论行顺序如何,父节点都能被追踪;第二次遍历优先处理RecordGrp节点生成初始ID,再按顺序处理子节点。 - 全局计数器:使用全局递增计数器,保证所有ID(包括RecordGrp和子节点)按顺序连续生成,符合示例要求。
- 完善映射覆盖:
nodeMap存储所有节点的ID映射,支持多层级树形结构的子节点处理。
内容的提问来源于stack exchange,提问作者Pick
相关产品推荐
相关产品推荐

