MSXML 선택 노드가 작동하지 않습니다
-
08-07-2019 - |
문제
자동화 된 테스트 앱에서 작업 중이며 현재 동일하지만 두 개의 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 문서를로드하고 XML 문서의 문서 요소로 "Top Record"를 설정합니다. (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()
이 XML 파일을 처리하려고 할 때 항상 길이 0입니다.
이것은 나를 미치게합니다.
해결책
.NET의 XMLDocument 객체 로이 작업을 수행하는 데 익숙하지만 효과가 동일하다고 생각합니다.
XML 문서에 이름이없는 네임 스페이스가 포함 된 경우 XPath 쿼리도 사용해야합니다. 따라서 코드에 이름을 제공 할 수있는 XMLDoument에 네임 스페이스를 추가해야하며 XPATH 쿼리에 접두사를 포함시켜야합니다 (접두사가 XML 문서와 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
다른 팁
노드를 선택할 때 네임 스페이스에 대한 언급이 없습니다. 나는 이것이 근본적인 문제라고 기대한다.