2008-11-12 5 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> 노드를 반환하려고) 다음을 수행 : 이것은 항상 false를 반환

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 쿼리 식에서 문제가있는 것으로 생각했지만 모든 순열은 생각할 수 없었습니다. IXMLDOMNodePtr::SelectNodes()에 의해 반환 된 MSXML::IXMLDOMNodeListPtr은이 XML 파일을 처리하려고 할 때 항상 길이가 0입니다.

이것은 나를 미치게합니다.

+0

여기서 XML 문서를 내 구성 파일 중 하나로 대체하면 노드를 선택하려고하면 완벽하게 작동합니다. 이 XML 파일에 잘못된 형식이 있습니까? –

답변

6

내가 .NET의을 XmlDocument 객체와이 일을하는 데 사용 해요,하지만 효과는 여기에 같은 생각 : XML 문서 네임 스페이스가 포함 된 경우

- 심지어 익명의 하나 - 다음 XPath 쿼리를 하나도 사용해야합니다.따라서 네임 스페이스를 XMLDoument에 추가해야합니다. XMLDoument는 코드에서 이름을 지정하고 XPATH 쿼리에서 접두사를 포함합니다 (접두사가 xml 문서와

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

다음 selectNodes()가 사용 : XPath는, 한 네임 스페이스 당신이 /report/subreport/record/field/value 같은 XPath를 사용하는 동안, 당신이 실제로 첫 번째 문서의 네임 스페이스를 설정해야합니다

SO) 그것을 밖으로 정렬 /r:report/r:subreport/r:record/r:field/r:value

+0

James, (이 XMLDoc 포인터를 IXMLDOMDocument2Ptr로 변경 한 후)이 메서드를 시도했지만이 setProperty 메서드를 호출 할 때 COM 오류가 발생했습니다. –

+0

아, 내 네임 스페이스 선언에 전달 된 일부 인용 부호가 누락되었습니다. 그걸 해결하고 모든 게 잘 작동합니다. 감사! –

+0

+1 나는 정확히 똑같은 문제에 부딪쳤다. –

0

노드를 선택할 때 네임 스페이스에 대한 참조가 없습니다. 나는 이것이 이것이 근본적인 문제라고 기대한다.