visual Получение имени дочернего узла в xml возвращает #text Переполнение стека

Я пытаюсь получить имя тега дочернего узла в документе XML. Мой XML-документ выглядит примерно так:

<?xml version="1.0" encoding="utf-8"?>
<Parent>
<child1>
<grandchild1>someinfo1</grandchild1>
<grandchild2>someinfo2</grandchild2>
</child1>
<child2>
<grandchild3>someinfo3</grandchild3>
<grandchild4>someinfo4</grandchild4>
</child2>
</Parent>

Мне нужно зациклить и найти имена тегов, такие как child1 grandchild1 и т. Д.

Мой код для выполнения следующих действий:

IXMLDOMDocument *pXMLDom = NULL;
IXMLDOMNodeList *pNodes = NULL;
IXMLDOMNode *pNode = NULL;

pXMLDom->put_async(VARIANT_FALSE);
pXMLDom->put_validateOnParse(VARIANT_TRUE);
pXMLDom->put_resolveExternals(VARIANT_FALSE);
pXMLDom->put_preserveWhiteSpace(VARIANT_TRUE);

BSTR parentNode = SysAllocString(L"//Parent/*");

pXMLDom->selectNodes(parentNode, &pNodes);
pNodes->get_length(&length);

for (int i = 0; i < length; i++)
{
pNodes->get_item(i, &pNode);
BSTR temp = NULL;
pNode->get_xml(&temp);
printf("Node (%d), <%S>:\n", i, temp); // works fine until this point

IXMLDOMNode *firstChild;
pNode->get_firstChild(&firstChild);

IXMLDOMNodeList *childNodes;
pNode->get_childNodes(&childNodes);

firstChild->get_nodeName(&temp); // Does not work
firstChild->get_baseName(&temp); // Does not work
}

Обратите внимание, что я предоставил только очень минималистскую версию своего кода для простоты. Если понадобятся какие-либо дополнительные разъяснения или код, я буду рад предоставить. Любые указатели в правильном направлении будут полезны. Большая часть кода была написана с помощью msdn.

0

Решение

XML состоит из узлов, и существует много разных видов узлов (элементы, атрибуты, текст, пространства имен, инструкции по обработке, комментарии, документы и т. Д.).

Узел элемента XML, содержащий текстовое содержимое, будет иметь дочерний узел с именем #text, Это продиктовано спецификацией XML. Итак, в вашем примере, grandchild1, grandchild2, grandchild3, а также grandchild4 у всех есть ребенок #text узел, например:

Документ
|
| _ PI: <? xml version = "1.0" encoding = "utf-8"?>
|
| _ Элемент: "Родитель" |
| _ Элемент: "child1" | |
| | _ Элемент: "grandchild1" | | |
| | | _ #text "someinfo1" | |
| | _ Элемент: "grandchild2" | |
| | _ #text "someinfo2" |
| _ Элемент: "child2" |
| _ Элемент: "grandchild3" | |
| | _ #text: "someinfo3" |
| _ Элемент: "grandchild4" |
| _ #text: "someinfo4"

Даже пробелы между элементами, даже если это просто разрывы строк, сохраняются как дополнительные текстовые узлы (потому что вы устанавливаете preserveWhiteSpace вариант true), например:

Документ
|
| _ PI: <? xml version = "1.0" encoding = "utf-8"?>
|
| _ #text "\ r \ n" |
| _ Элемент: "Родитель" |
| _ #text "\ r \ n" |
| _ Элемент: "child1" | |
| | _ #text "\ r \ n" | |
| | _ Элемент: "grandchild1" | | |
| | | _ #text "someinfo1" | |
| | _ #text "\ r \ n" | |
| | _ Элемент: "grandchild2" | |
| | _ #text "someinfo2" |
| _ #text "\ r \ n" |
| _ Элемент: "child2" | |
| | _ #text "\ r \ n" | |
| | _ Элемент: "grandchild3" | | |
| | | _ #text: "someinfo3" | |
| | _ #text "\ r \ n" | |
| | _ Элемент: "grandchild4" | | |
| | | _ #text: "someinfo4" | |
| | _ #text "\ r \ n" |
| _ #text "\ r \ n"

XPath ищет все узлы, но * Подстановочный знак соответствует только узлам элемента. Но вы вручную сверляете дочерние элементы найденных элементов, поэтому вы столкнетесь с #text узлы. Для того, что вы пытаетесь сделать, отключите сохранение пробелов, чтобы удалить ненужные текстовые узлы пробелов, а затем сосредоточьтесь только на дочерних узлах элемента, например:

IXMLDOMDocument *pXMLDom = NULL;
IXMLDOMNodeList *pNodes = NULL;
IXMLDOMNode *pNode = NULL;
long length = 0;

// create pXMLDom as needed ...
pXMLDom->put_async(VARIANT_FALSE);
pXMLDom->put_validateOnParse(VARIANT_TRUE);
pXMLDom->put_resolveExternals(VARIANT_FALSE);
pXMLDom->put_preserveWhiteSpace(VARIANT_FALSE); // <--

BSTR parentNode = SysAllocString(L"//Parent/*");
HRESULT hRes = pXMLDom->selectNodes(parentNode, &pNodes);
SysFreeString(parentNode);

if (SUCCEEDED(hRes))
{
pNodes->get_length(&length);

for (int i = 0; i < length; ++i)
{
hRes = pNodes->get_item(i, &pNode);
if (SUCCEEDED(hRes))
{
BSTR name = NULL;
hRes = pNode->get_nodeName(&name);
if (SUCCEEDED(hRes))
{
printf("Node (%d), <%S>:\n", i, name);
SysFreeString(name);
}

IXMLDOMNode *pChild = NULL;
hRes = pNode->get_firstChild(&pChild);
if (hRes == S_OK)
{
do
{
DOMNodeType type;
hRes = pChild->get_nodeType(&type);
if ((SUCCEEDED(hRes) && (type == NODE_ELEMENT))
{
hRes = pNode->get_nodeName(&name);
if (SUCCEEDED(hRes))
{
printf("  %S\n", name);
SysFreeString(name);
}
}

IXMLDOMNode *pSibling = NULL;
hRes = pChild->get_nextSibling(&pSibling);
if (hRes != S_OK) break;

pChild->Release();
pChild = pSibling;
}
while (true);

pChild->Release();
}

pNode->Release();
}
}

pNodes->Release();
}

...

pXMLDom->Release();

Если вам нужно пройти более 2 уровней, вам следует вместо этого установить рекурсивный цикл, например:

void processNode(IXMLDOMNode *pNode)
{
BSTR name = NULL;
hRes = pNode->get_nodeName(&name);
if (SUCCEEDED(hRes))
{
printf("%S\n", name);
SysFreeString(name);
}

IXMLDOMNode *pChild = NULL;
hRes = pNode->get_firstChild(&pChild);
if (hRes == S_OK)
{
do
{
DOMNodeType type;
hRes = pChild->get_nodeType(&type);
if ((SUCCEEDED(hRes) && (type == NODE_ELEMENT))
processNode(pChild);

IXMLDOMNode *pSibling = NULL;
hRes = pChild->get_nextSibling(&pSibling);
if (hRes != S_OK) break;

pChild->Release();
pChild = pSibling;
}
while (true);

pChild->Release();
}
}

...

IXMLDOMDocument *pXMLDom = NULL;
IXMLDOMNodeList *pNodes = NULL;
IXMLDOMNode *pNode = NULL;
long length = 0;

// create pXMLDom as needed ...
pXMLDom->put_async(VARIANT_FALSE);
pXMLDom->put_validateOnParse(VARIANT_TRUE);
pXMLDom->put_resolveExternals(VARIANT_FALSE);
pXMLDom->put_preserveWhiteSpace(VARIANT_FALSE); // <--

BSTR parentNode = SysAllocString(L"//Parent/*");
HRESULT hRes = pXMLDom->selectNodes(parentNode, &pNodes);
SysFreeString(parentNode);

if (SUCCEEDED(hRes))
{
pNodes->get_length(&length);

for (int i = 0; i < length; ++i)
{
hRes = pNodes->get_item(i, &pNode);
if (SUCCEEDED(hRes))
{
processNode(pNode);
pNode->Release();
}
}

pNodes->Release();
}

...

pXMLDom->Release();
0

Другие решения

После того, как я разместил вопрос, я получил то, что искал!

Несохраняющие пробелы работы:

pXMLDom->put_preserveWhiteSpace(VARIANT_FALSE);
0

По вопросам рекламы [email protected]