C++ Builder 11中XML的FindNode与Nodes[]行为不一致问题排查
C++ Builder 11中TXMLDocument节点查找异常的根源与解决方法
问题根源
你混淆了IXMLNodeList->Nodes[]索引器的实际行为:
- 传入整数索引时,
Nodes[int]返回对应位置的单个IXMLNode节点 - 传入字符串节点名时,
Nodes[UnicodeString]等价于FindNode(),仅返回第一个匹配名称的单个节点,根本不是所有同名节点的列表
你的代码错误地把单个节点的接口赋值给_di_IXMLNodeList类型变量,导致接口转换失败,最终返回NULL。这也是为什么FindNode能正常找到单个节点,但Nodes[节点名]赋值给列表变量后返回空的原因。
正确获取所有同名节点的方法
方法1:用SelectNodes直接获取(推荐)
调用节点的SelectNodes方法,传入XPath表达式就能拿到所有匹配节点:
// 替换原代码中获取recipientNodes的行 _di_IXMLNodeList recipientNodes = rootNode->SelectNodes(L"Recipient");
如果XML涉及命名空间,需要先设置xmlDoc->NamespaceAware = true,并在XPath中指定对应命名空间前缀。
方法2:手动遍历筛选
不想用XPath的话,直接遍历所有子节点,收集名称匹配的节点:
// 手动收集所有Recipient节点 TList* recipientList = new TList(); try { for (int i = 0; i < rootNode->ChildNodes->Count; i++) { _di_IXMLNode childNode = rootNode->ChildNodes->Nodes[i]; if (childNode->NodeName == L"Recipient") { recipientList->Add((void*)childNode); } } ShowMessage(L"Found " + IntToStr(recipientList->Count) + L" Recipient nodes."); // 遍历处理每个Recipient节点 for (int i = 0; i < recipientList->Count; i++) { _di_IXMLNode recipientNode = (_di_IXMLNode)recipientList->Items[i]; ShowMessage(L"Recipient: " + recipientNode->Text); } } __finally { delete recipientList; }
方法3:用Filter属性筛选节点
通过设置ChildNodes的Filter属性,过滤出指定名称的节点:
rootNode->ChildNodes->Filter = L"Recipient"; _di_IXMLNodeList recipientNodes = rootNode->ChildNodes; // 此时recipientNodes只包含名称为Recipient的节点 if (recipientNodes->Count > 0) { ShowMessage(L"Found " + IntToStr(recipientNodes->Count) + L" Recipient nodes."); // 处理节点逻辑... } // 使用后清空Filter,避免影响后续节点操作 rootNode->ChildNodes->Filter = L"";
测试代码验证
把原代码中获取recipientNodes的代码替换成SelectNodes调用后,就能正确识别到两个Recipient节点,不会再触发“No Recipient nodes found”提示。
内容的提问来源于stack exchange,提问作者w0wbagger
相关产品推荐
相关产品推荐

