Вопрос

Я работаю над приложением для автоматического тестирования и в настоящее время нахожусь в процессе написания функции, которая сравнивает значения между двумя файлами 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-документ и устанавливает его " top record " к элементу документа XML-документа. (CRecord является абстрактным классом с CXMLRecord одним из его подклассов, который предоставляет доступ к дочерним записям по отдельности или по группам, а также предоставляет доступ к & Quot; value & Quot; Record (значения для дочерних элементов или атрибуты, в случае CXMLRecord.) CXMLRecord содержит MSXML :: MSXMLDOMNodePtr и указатель на экземпляр CSimpleXMLParser.) Оболочка также содержит служебные функции для возврата дочерних элементов, которые CXMLRecord использует для возврата своих дочерних записей.

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

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));
}

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

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

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

Это было полезно?

Решение

Я привык делать это с объектами .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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top