如何在VBA生成XML时检索并编辑已存在的同名Section节点
解决VBA生成XML时非连续同名Section节点的追加问题
我看到你遇到的问题了——当前代码只能处理连续的同名Section行,非连续的同名项会重复创建节点,而且XPath查询失败是因为XML默认命名空间的问题,这是VBA操作带命名空间XML的常见坑。下面给你一步步解决的方案:
1. 关键问题:XML命名空间的XPath查询
你的XML使用了默认命名空间urn:Riwo.Pcs.Localization,直接用//Section这种XPath是找不到节点的——DOMDocument不知道这个前缀对应的命名空间。需要先给命名空间绑定一个前缀(比如ns),再用前缀来写XPath。
2. 修改后的完整代码
Sub RPCTranslatesCombinedInfoBackwardsChecking() Set oXMLDoc = CreateObject("MSXML2.DOMDocument.6.0") '用6.0版本更稳定,支持命名空间处理 oXMLDoc.SetProperty "SelectionNamespaces", "xmlns:ns='urn:Riwo.Pcs.Localization'" '绑定命名空间前缀 oXMLDoc.SetProperty "SelectionLanguage", "XPath" '指定用XPath查询 oXMLDoc.async = False '同步处理,确保节点创建后立即能查询到 '创建XML声明 Set oPI = oXMLDoc.createProcessingInstruction("xml", "version=""1.0"" encoding=""UTF-8""") '创建根节点及属性 Set oRoot = oXMLDoc.CreateNode(1, "Translations", "urn:Riwo.Pcs.Localization") With oRoot .SetAttribute "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" .SetAttribute "xmlns:xsd", "http://www.w3.org/2001/XMLSchema" .SetAttribute "code", "nl" .SetAttribute "description", "Dutch" End With oXMLDoc.AppendChild oRoot oXMLDoc.InsertBefore oPI, oXMLDoc.ChildNodes.Item(0) With ActiveSheet lRow = 2 '从第2行开始处理 Do While .Cells(lRow, 4).Value <> "" sLineName = .Cells(lRow, 1).Value sSectionPrefix = Right(sLineName, Len(sLineName) - 1) sSectionName = .Cells(lRow, 4).Value Dim fullSectionName As String fullSectionName = sSectionPrefix & "." & sSectionName '构建完整的Section name属性值 '1. 先查询是否已存在该Section节点 Dim xPathQuery As String xPathQuery = "//ns:Section[@name='" & fullSectionName & "']" '用绑定的前缀ns来查询 Set oElmSection = oXMLDoc.SelectSingleNode(xPathQuery) If oElmSection Is Nothing Then '2. 不存在则新建Section节点 Set oElmSection = oXMLDoc.CreateNode(1, "Section", "urn:Riwo.Pcs.Localization") oElmSection.SetAttribute "name", fullSectionName oXMLDoc.DocumentElement.AppendChild oElmSection '新建对应的Translation节点(key=Info) Set oElmTranslation = oXMLDoc.CreateNode(1, "Translation", "urn:Riwo.Pcs.Localization") oElmTranslation.SetAttribute "key", "Info" oElmSection.AppendChild oElmTranslation Else '3. 存在则找到对应的Translation节点 Set oElmTranslation = oElmSection.SelectSingleNode("ns:Translation[@key='Info']") End If '处理当前行的内容,拼接成要追加的文本 sInfoDescription_1 = .Cells(lRow, 1).Value sInfoDescription_2 = .Cells(lRow, 2).Value sInfoDescription_3 = .Cells(lRow, 3).Value sInfoDescription_5 = .Cells(lRow, 5).Value Dim sInfo As String '如果是该Section的第一条记录,直接拼接;否则加<br/>分隔 If oElmTranslation.Text = "" Then sInfo = sInfoDescription_1 & sInfoDescription_2 & sInfoDescription_3 & " " & sInfoDescription_5 Else sInfo = " <br/> " & sInfoDescription_1 & sInfoDescription_2 & sInfoDescription_3 & " " & sInfoDescription_5 End If '追加文本到Translation节点 oElmTranslation.AppendChild oXMLDoc.createTextNode(sInfo) lRow = lRow + 1 Loop End With MsgBox oXMLDoc.XML oXMLDoc.Save "C:\Users\thomas.RIWO\Desktop\Translations\RPC test\test2.xml" End Sub
3. 核心改进点说明
- 命名空间处理:通过
SetProperty "SelectionNamespaces"绑定前缀,XPath查询时必须带上前缀(比如ns:Section),这样才能正确匹配到带默认命名空间的节点。 - 先查询再创建:每次处理行时,先通过
SelectSingleNode查询是否已存在对应name的Section节点,避免重复创建。 - 灵活追加内容:判断Translation节点的文本是否为空,来决定是直接写入还是加
<br/>分隔后追加,不管行是否连续都能正确合并内容。 - 使用稳定的DOM版本:改用
MSXML2.DOMDocument.6.0,比早期版本对XPath和命名空间的支持更完善。
内容的提问来源于stack exchange,提问作者thordijk
相关产品推荐
相关产品推荐

