Pergunta

Eu estou trabalhando em um aplicativo de teste automatizado, e estou atualmente no processo de escrever uma função que compara valores entre dois arquivos XML que devem ser idênticos, mas pode não ser. Aqui está uma amostra do XML Eu estou tentando processo:

<?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>

(Nota pode haver múltiplos elementos <subreport> e aqueles dentro de, vários elementos <record>.)

O que eu gostaria é extrair as tags <value> de dois documentos e então comparar seus valores. Essa parte eu sei como fazer. O problema é a própria extração.

Desde que eu estou preso em C ++, eu estou usando MSXML, e ter escrito um invólucro para permitir que meu aplicativo para abstrair a manipulação XML real, no caso de eu decidir que quer mudar o meu formato de dados.

Esse invólucro, CSimpleXMLParser, carrega um documento XML e define seu "recorde top" para o elemento do documento do documento XML. (CRecord sendo uma classe abstrata com CXMLRecord uma de suas subclasses, e que dá acesso a registros filho individualmente ou por grupo, e também permitindo o acesso ao "valor" do registro (valores para elementos filhos ou atributos, no caso de CXMLRecord .) a CXMLRecord contém um MSXML :: MSXMLDOMNodePtr e um ponteiro para uma instância de um CSimpleXMLParser.) o invólucro também contém funções de utilidade para as crianças que retornam, que o CXMLRecord usa para retornar seus registros filho.

No meu código, eu faço o seguinte (tentando retornar todos os nós <subreport> só para ver se ele funciona):

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

Este é sempre retornar false. A carne da implementação do CXMLRecord :: GetChildRecords () é basicamente

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;

E CSimpleXMLParser :: SelectNodes () é:

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

Quando executado, o registro superior é definitivamente a ser definida como o elemento <report> corretamente. Eu posso fazer todos os tipos de coisas com ele, como a obtenção de seus nós filho (através da interface do MSXML, não através do meu invólucro) ou seu nome, etc. Eu sei que o meu invólucro pode trabalho, porque eu uso -lo em outras partes do aplicativo para analisar um arquivo de configuração XML, e que funciona perfeitamente.

Eu pensei que talvez eu estava fazendo com defeito algo com a expressão de consulta XPath, mas todas as permutações que eu poderia pensar não dá nenhuma alegria. O MSXML::IXMLDOMNodeListPtr retornado por IXMLDOMNodePtr::SelectNodes() é sempre de comprimento 0, quando eu tentar lidar com esse arquivo XML.

Este é me deixando louco.

Foi útil?

Solução

Eu estou acostumado a fazer isso com objetos XmlDocument do .NET, mas acho que o efeito é o mesmo aqui:

Se o documento XML inclui um espaço de nomes - mesmo um sem nome - em seguida, a consulta XPath tem de usar um bem. Assim, você terá que adicionar o namespace ao XMLDoument que assim como você pode dar um nome no código, ea incluir o prefixo na consulta XPath (não importa que os prefixos são diferentes entre o documento XML e o XPath, enquanto os namespaces classificar a)

Assim, quando você estiver usando um XPath como /report/subreport/record/field/value, você realmente precisa primeiro set o namespace do seu documento:

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

e, em seguida, selectNodes() usando /r:report/r:subreport/r:record/r:field/r:value

Outras dicas

Não vejo nenhuma referência a um namespace quando você está selecionando os nós. Eu esperaria que este seja o problema fundamental.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top