Узлы выбора MSXML не работают

Я работаю над приложением для автоматического тестирования, и в настоящее время я пишу функцию, которая сравнивает значения двух XML-файлов, которые должны быть идентичными, но могут не совпадать. Вот образец XML, который я пытаюсь обработать:

<?xml version = "1.0" encoding = "utf-8"?>
<report xmlns = "http://www.**.com/**">
  <subreport name = "RBDReport">
    <record rowNumber = "1">
      <field name = "Time">
        <value>0</value>
      </field>
      <field name = "Reliability">
        <value>1.000000</value>
      </field>
      <field name = "Unreliability">
        <value>0.000000</value>
      </field>
      <field name = "Availability">
        <value> </value>
      </field>
      <field name = "Unavailability">
        <value> </value>
      </field>
      <field name = "Failure Rate">
        <value>N/A</value>
      </field>
      <field name = "Number of Failures">
        <value> </value>
      </field>
      <field name = "Total Downtime">
        <value> </value>
      </field>
    </record>

(Обратите внимание, что может быть несколько элементов <subreport>, а внутри них - несколько элементов <record>.)

Я бы хотел извлечь теги <value> из двух документов, а затем сравнить их значения. Эту часть я умею делать. Проблема в самой добыче.

Поскольку я застрял в C++, я использую MSXML и написал оболочку, позволяющую моему приложению абстрагироваться от фактических манипуляций с XML, на случай, если я когда-нибудь решу изменить свой формат данных.

Эта оболочка, CSimpleXMLParser, загружает XML-документ и устанавливает его «верхнюю запись» в элемент документа XML-документа. (CRecord является абстрактным классом с CXMLRecord одним из его подклассов, который предоставляет доступ к дочерним записям по отдельности или по группам, а также разрешает доступ к «значению» записи (значения для дочерних элементов или атрибутов в случае CXMLRecord .) CXMLRecord содержит MSXML :: MSXMLDOMNodePtr и указатель на экземпляр CSimpleXMLParser.) Оболочка также содержит служебные функции для возврата дочерних элементов, которые CXMLRecord использует для возврата своих дочерних записей.

В моем коде я делаю следующее (пытаюсь вернуть все узлы <subreport>, чтобы посмотреть, работает ли это):

CSimpleXMLParser parserReportData;
parserReportData.OpenXMLDocument(strPathToXML);
bool bGetChildrenSuccess = parserReportData.GetFirstRecord()->GetChildRecords(listpChildren, _T("subreport"));

Это всегда возвращает false. Основа реализации CXMLRecord :: GetChildRecords () в основном

MSXML2::IXMLDOMNodeListPtr pListChildren = m_pParser->SelectNodes(strPath, m_pXMLNode);

if (pListChildren->Getlength() == 0)
{
    return false;
}

for (long l = 0; l < pListChildren->Getlength(); ++l)
{
    listRecords.push_back(new CXMLRecord(pListChildren->Getitem(l), m_pParser));
}

return true;

И CSimpleXMLParser :: SelectNodes ():

MSXML2::IXMLDOMNodeListPtr CSimpleXMLParser::SelectNodes(LPCTSTR strXPathFilter, MSXML2::IXMLDOMNodePtr pXMLNode)
{
    return pXMLNode->selectNodes(_bstr_t(strXPathFilter));
}

При запуске верхняя запись определенно устанавливается правильно для элемента <report>. Я могу делать с ним все, что угодно, например, получать его дочерние узлы (через интерфейс MSXML, а не через мою оболочку) или его имя и т. д. Я знаю, что моя оболочка может работает, потому что я использую ее в другом месте приложения для синтаксического анализа. файл конфигурации XML, и он работает безупречно.

Я подумал, что, может быть, я что-то сделал неправильно с выражением запроса XPath, но каждая перестановка, о которой я мог подумать, не приносит радости. MSXML::IXMLDOMNodeListPtr, возвращаемый IXMLDOMNodePtr::SelectNodes(), всегда имеет длину 0, когда я пытаюсь обработать этот XML-файл.

Это сводит меня с ума.

Замечу, что если я заменю здесь XML-документ одним из моих файлов конфигурации и попытаюсь выбрать его узлы, он будет работать отлично. Есть ли что-то искаженное в этом XML-файле?

Brock Greman 12.11.2008 20:48
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
1
6 411
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Я не вижу ссылки на пространство имен, когда вы выбираете узлы. Я ожидал, что это основная проблема.

Ответ принят как подходящий

Я привык делать это с объектами .NET XmlDocument, но думаю, что эффект здесь тот же:

Если XML-документ включает пространство имен - даже безымянное - тогда запрос Xpath также должен использовать его. Итак, вам нужно будет добавить пространство имен в XMLDoument, которому вы также можете дать имя в коде, и включить префикс в запрос XPATH (не имеет значения, что префиксы различаются между XML-документом и xpath, если пространства имен сортируют его)

Итак, пока вы используете XPath, например /report/subreport/record/field/value, вам действительно нужно сначала установить пространство имен вашего документа:

  pXMLDoc->setProperty(_bstr_t("SelectionNamespaces"),
                       _bstr_t("xmlns:r = "http://www.**.com/**"));

а затем selectNodes() с использованием /r:report/r:subreport/r:record/r:field/r:value

Джеймс, я попробовал этот метод (после изменения указателя XMLDoc на IXMLDOMDocument2Ptr), но при попытке вызвать этот метод setProperty я получаю сообщение об ошибке COM.

Brock Greman 12.11.2008 22:51

Упс, в моем объявлении пространства имен отсутствовали кавычки. Исправлено, и все работает нормально. Спасибо!

Brock Greman 12.11.2008 22:58

Другие вопросы по теме