2008-11-12 3 views
3

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

<?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")); 

Это всегда возвращается ложь. Мясо реализации 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-файлом.

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

+0

Замечу, что если я заменил XML-документ здесь одним из моих файлов конфигурации и попробуйте выбрать его узлы, он отлично работает. Есть ли что-то неправильное в этом XML-файле? – 2008-11-12 17:48:32

ответ

6

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

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

SO, в то время как вы используете 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

+0

James, Я пробовал этот метод (после изменения указателя XMLDoc на IXMLDOMDocument2Ptr), но я получаю сообщение об ошибке COM при попытке вызвать этот метод setProperty. – 2008-11-12 19:51:45

0

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

 Смежные вопросы

  • Нет связанных вопросов^_^