我正在尝试在 C++ Builder 11 (Alexandria) 中导航 TXMLDocument。一切都进展顺利,但我却陷入了停滞。出于这个问题的目的,我已经将问题简化以简化它,但我无法理解发生了什么
// 代码片段..
ParentNode = node->ChildNodes->FindNode(Name);
String recipientNodeName = "Recipient"; // This comes from a variable in the original code. Debugger shows that it does not change in value between the two following calls.
_di_IXMLNode RecipientNode = ParentNode->ChildNodes->FindNode(recipientNodeName); // This works, RecipientNode is properly found
_di_IXMLNodeList RecipientNodes = ParentNode->ChildNodes->Nodes[recipientNodeName]; // This does *not* work, RecipientNodes is NULL
从我能找到的所有文档来看,这两个应该都找到相同的节点。第一个觉得还好。第二个(应该生成一个或多个节点的列表 - 在本例中只有一个)失败,并且不会生成单个项目列表。
有人知道为什么会发生这种情况吗?我是否误解了如何导航 DOM?预先感谢您提供的任何帮助。
我尝试过递归地遍历树,它看起来完全应该是这样的。即使我使用相同的节点名(命名空间相同),它似乎也没有创建列表。
新: 我编写了这个简单的程序,虽然它正确地迭代每个节点(我看到两个节点调用“收件人”),但recipientNodes仍然是NULL(“找不到收件人节点”)触发器。我想我必须假设我的环境或 RAD Studio 11.4 有问题导致此失败。我将仅迭代节点来获取重复数据。如果有人发现我正在尝试做的事情存在根本缺陷,请告诉我,因为我更愿意使用记录的函数而不是编写自己的函数。感谢迄今为止以及未来的任何帮助。 (代码如下)
// Create a new XML Document
_di_IXMLDocument xmlDoc = NewXMLDocument();
// XML string to parse
UnicodeString xmlStr = L"<CommunicationMetaData>"
L"<ApplicationReferenceID>12345</ApplicationReferenceID>"
L"<Recipient>ID1</Recipient>"
L"<Recipient>ID2</Recipient>"
L"<SomeOtherNode>Data</SomeOtherNode>"
L"</CommunicationMetaData>";
xmlDoc->LoadFromXML(xmlStr);
xmlDoc->Active = true; // Ensure the document is active
// Get the root node (CommunicationMetaData)
_di_IXMLNode rootNode = xmlDoc->DocumentElement;
if (rootNode)
{
ShowMessage("Root node loaded successfully.");
// Debugging: Output the names of all child nodes under the root node
for (int i = 0; i < rootNode->ChildNodes->Count; i++) {
_di_IXMLNode childNode = rootNode->ChildNodes->Nodes[i];
ShowMessage("Child node name: " + childNode->NodeName);
}
// Attempt to retrieve all Recipient nodes
_di_IXMLNodeList recipientNodes = rootNode->ChildNodes->Nodes["Recipient"];
if (recipientNodes && recipientNodes->Count > 0)
{
ShowMessage("Found " + IntToStr(recipientNodes->Count) + " Recipient nodes.");
// Iterate through each Recipient node
for (int i = 0; i < recipientNodes->Count; i++)
{
_di_IXMLNode recipientNode = recipientNodes->Nodes[i];
if (recipientNode)
{
ShowMessage("Recipient: " + recipientNode->Text);
}
else
{
ShowMessage("Failed to load Recipient node at index: " + IntToStr(i));
}
}
}
else
{
ShowMessage("No Recipient nodes found.");
}
}
else
{
ShowMessage("Failed to load the root node.");
}
}
catch (const Exception& e)
{
ShowMessage("Exception occurred: " + e.Message);
}
// Attempt to retrieve all Recipient nodes _di_IXMLNodeList recipientNodes = rootNode->ChildNodes->Nodes["Recipient"];
这是错误的。
Nodes[]
属性不会像您所期望的那样返回匹配节点的列表。它仅返回单个节点 (_di_IXMLNode
)。
根据文档:
__property _di_IXMLNode Nodes[const System::OleVariant IndexOrName] = {read=GetNode/*, default*/};
标识所需的节点。它可以是:IndexOrName
节点的索引,其中0是第一个节点的索引,1是第二个节点的索引,以此类推。
属性提供了您可以指定的索引的上限。Count
列表中节点的
属性。LocalName
换句话说,当您从 Nodes[]
请求节点
by name时,仅返回第一个匹配的节点。不是匹配节点的列表。
您正在将返回的
_di_IXMLNode
并将其分配给 _di_IXMLNodeList
。因此,在节点上查询 IXMLNodeList
接口,但失败了,因为单个节点不是节点列表。这就是为什么你最终会得到一个 NULL 指针。
话虽这么说,
IXMLNode/List
界面根本不具备您正在寻找的功能。要完成您正在尝试的任务,您需要使用 XPath 查询。您可以查询父级 IXMLNode
的 DOMNode
属性以获取 IDOMNodeSelect
接口,如果成功,则调用其 selectNodes()
方法,该方法返回匹配 IDOMNodeList
s 的 IDOMNode
。
否则,您只需手动迭代
IXMLNode
,正如您已经发现的那样。