3

私は自動テストアプリに取り組んでおり、現在、同一である必要があるがそうではない可能性がある2つの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>、2 つのドキュメントのタグを抽出し、それらの値を比較することです。その部分は私が行う方法を知っています。問題は抽出そのものです。

私は C++ で立ち往生しているので、MSXML を使用しており、データ形式を変更することにした場合に備えて、アプリが実際の XML 操作を抽象化できるようにするラッパーを作成しました。

そのラッパーである CSimpleXMLParser は、XML ドキュメントをロードし、その「トップ レコード」を XML ドキュメントのドキュメント要素に設定します。(CRecord は、そのサブクラスの 1 つである CXMLRecord を持つ抽象クラスであり、子レコードへの単独またはグループによるアクセスを提供し、Record の「値」へのアクセスも許可します (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 クエリ式で何か間違ったことをしているのかもしれないと思いましたが、考えられるすべての順列は喜びを与えません。このXML ファイルを処理しようとすると、MSXML::IXMLDOMNodeListPtr返されるIXMLDOMNodePtr::SelectNodes()は常に長さ 0 です。

これは私を夢中にさせています。

4

2 に答える 2

8

私は .NET の XmlDocument オブジェクトでこれを行うことに慣れていますが、ここでも効果は同じだと思います。

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

于 2008-11-12T17:48:28.643 に答える
0

ノードを選択しているときに名前空間への参照が表示されません。これが根本的な問題だと思います。

于 2008-11-12T17:46:10.613 に答える