C++ Builder 11 - XML FindNode 的工作方式与 Nodes[] 不同

问题描述 投票:0回答:1

我正在尝试在 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);
}
c++ xml c++builder-11-alexandria
1个回答
0
投票
// 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
,正如您已经发现的那样。

© www.soinside.com 2019 - 2024. All rights reserved.