利用MSXML解析XML文本(1)

來源:互聯網
上載者:User

利用MSXML解析XML文本(1)
XML DOM (文件物件模型)對象提供了一個標準的方法來操作儲存在XML文檔中的資訊,這就是DOM應用編程介面(API)函數。它是應用程式和XML文檔之間的橋樑。DOM包含兩個關鍵的抽象概念:一個是樹狀的階層,另一個是用來表示文檔內容和結構的節點集合。樹狀層次包括了所有節點,節點本身也可以包含其他的節點。這樣的好處是可以通過這個階層來找到並修改某一特定節點的資訊。

----微軟的MSXML解析器讀取一個XML文檔,然後把它的內容解析到一個抽象的資訊容器中,該資訊容器被稱為節點(NODES)。這些節點代表文檔的結構和內容,並允許應用程式來操作文檔中的資訊而不需要知道XML的語義。一個文檔被解析後,它的節點能夠在任何時候被瀏覽而不需要保持一定的順序。

----對開發人員來說,最重要的編程對象是DOMDocument。 DOMDocument對象通過暴露的屬性和方法來允許瀏覽、查詢和修改XML文檔的內容和結構。

----本文主要介紹DOM的結構和應用,同時用VC程式設計語言給出了通過MSXML進行XML解析的執行個體。

DOMDocument對象的結構和應用
----文檔對象的建立
   HRESULT hr;
   IXMLDomDocument* pXMLDoc;
   IXMLDOMNode* pXDN;
   //COM的初始化
   Hr=CoInitialize(NULL); 
/*得到關於IXMLDOMDocument
 介面的指標pXMLDOC*/
  hr=CoCreateInstance(CLSID_DOMDocument,NULL,
  CLSCTX_INPPROC_SERVER,IID_IXMLDOMDocument,
    (void**)&pXMLDoc);
  //得到關於IXMLDOMNode介面的指標pXDN
  hr=pXMLDoc->QueryInterface(IID_IXMLDOM
Node,(void**)&pXDN);

----在MSXML解析器的使用過程中,我們可以使用文檔中的CreateElement方法建立一個節點來裝載和儲存XML檔案,也可以通過Load或者是 LoadXML方法從一個指定的URL來裝載一個XML文檔。Load(LoadXML)方法帶有兩個參數:第一個參數xmlSource表示需要被解析的文檔,第二個參數isSuccessful表示文檔裝載是否成功。

----文檔對象的儲存

----Save方法是用來把文檔儲存到一個指定的位置。Save方法中參數destination用來表示需要被儲存的對象的類型,對象可以是一個檔案、一個ASP Response方法、一個XML文檔對象,或者是一個能夠支援持久儲存(persistence)的客戶對象。下面是使用Save方法的一個例子程式的部分代碼:

  BOOL DOMDocSaveLocation()
  {
     BOOL bResult = FALSE;
     IXMLDOMDocument *pIXMLDOMDocument = NULL;
     HRESULT hr;
     try
     {
        _variant_t varString = _T(“D:\\sample.xml");
        /* 這裡省略了建立一個DOMDocument
          對象和裝載XML文檔的代碼*/
       //將文檔儲存到D:\\sample.xml中去
      hr=pIXMLDOMDocument->save(varString);
      if(SUCCEEDED(hr))
          bResult = TRUE;
      }
      catch(...)
      {
         DisplayErrorToUser();
         /*這裡省略了釋放對IXMLDOMDocument
          介面的引用的代碼*/
      }
      return bResult;
  }

----設定解析標誌

----在解析過程中,我們需要得到和設定解析標誌。利用不同的解析標誌,我們可以用不同的方法來解析一個XML文檔。XML標準允許解析器驗證或者不驗證文檔,允許不驗證文檔的解析過程跳過對外部資源的提取,還可以設定標誌來表明是否要從文檔中移去多餘的空格。DOMDocument對象暴露了如下幾個屬性,允許使用者在啟動並執行時候利用它們改變解析器的行為。

Async屬性方法:get_Async和put_Async。
ValidateOnParse屬性方法:get_ValidateOnParse和 put_ValidateOnParse。
ResolveExternals屬性方法:get_ ResolveExternals和put_ ResolveExternals。
PreserveWhiteSpace屬性方法:get_ PreserveWhiteSpace和put_ PreserveWhiteSpace。
----每一個屬性可以接受或者返回一個Boolean值。預設情況下,Async、ValidateOnParse、ResolveExternals的值為TRUE,PreserveWhiteSpace的值跟 XML文檔的設定有關,如果XML文檔中設定了xml:space屬性的話,該值為FALSE。

----在文檔解析過程中可以收集到以下的資訊:

doctype(文件類型):是用來定義文檔格式的DTD檔案。如果XML文檔沒有相關的 DTD文檔的話,它就返回NULL。
implementation(實現):表示該文檔的實現,用來指出當前文檔所支援的XML的版本。
parseError(解析錯誤):指出在解析過程中最後所發生的錯誤。
readyState(狀態資訊):表示XML文檔的狀態資訊。readyState對於非同步使用微軟的XML 解析器來說重要的作用是提高了效能。當非同步裝載XML文檔的時候,程式可能需要檢查解析的狀態,MSXML提供了4個狀態,分別為正在狀態、已經狀態、正在解析和解析完成。
url(統一資源定位):表示正在被裝載和解析的XML文檔的URL的情況。如果該文檔是在記憶體中建立的話,這個屬性返回NULL值。
----節點的操作

---- 在得到文檔樹結構以後,我們可以操作樹中的每一個節點,一般通過兩個方法得到樹中的節點,分別為nodeFromID和getElementsByTagName。

---- nodeFromID包括兩個參數,第一個參數idString用來表示ID值,第二個參數node返回指向和該ID相匹配的節點的介面指標。根據XML的技術規定,每一個XML文檔中的ID值必須是唯一的,而且一個元素(element)只能和一個ID 相關聯。

----getElementsByTagName方法有兩個參數,第一個參數 tagName表示需要尋找的元素(Element)名稱,如果tagName為“*”則返迴文檔中所有的元素。第二個參數為resultList,它實際是指向介面IXMLDOMNodeList的指標,用來返回和 tagName(標籤名字)相關的所有節點的集合。

----下面是相關例子程式的部分代碼:

IXMLDOMDocument *pIXMLDOMDocument = NULL;
wstring strFindText (_T(“author"));
IXMLDOMNodeList *pIDOMNodeList = NULL;
IXMLDOMNode *pIDOMNode = NULL;
long value;
BSTR bstrItemText;
HRESULT hr;
try
{
/*此處省略建立一個DOMDocument
文檔對象並裝載具體文檔的代碼*/
/*下面的代碼用來得到一個和標籤名稱author相關的所有節點的集合*/
   //是否正確地得到了指向IDOMNodeList的指標
  hr=pIXMLDOMDocument->getElementsByTagName
  ((TCHAR*)strFindText.data(), &pIDOMNodeList);
   SUCCEEDED(hr) ? 0 : throw hr;
   //得到所包含的節點的個數                  
   hr = pIDOMNodeList->get_length(&value);
   if(SUCCEEDED(hr))
   {
       pIDOMNodeList->reset();
       for(int ii = 0; ii < value; ii++)
       {
           //得到具體的一個節點
           pIDOMNodeList->get_item(ii,&pIDOM
Node);
       if(pIDOMNode )
       {
           //得到該節點相關的文本資訊
pIDOMNode->get_text(&bstrItemText);
          ::MessageBox(NULL, bstrItemText,
          strFindText.data(), MB_OK);
          pIDOMNode->Release();
          pIDOMNode = NULL;
       }
   }
}
   pIDOMNodeList->Release();
   pIDOMNodeList = NULL;
}
catch(...)
{
   if(pIDOMNodeList)
       pIDOMNodeList->Release();
   if(pIDOMNode)
       pIDOMNode->Release();
   DisplayErrorToUser();
}

----可以通過方法CreateNode來建立一個新的節點。 CreateNode包括4個參數,第一個參數type表示要建立的節點的類型,第二個參數name表示新節點的nodeName的值,第三個參數namespaceURI表示和該節點相關的名字空間,第四個參數node表示新建立的節點。可以通過使用已經提供的類型(type)、名稱(name)和名字空間(nodeName)來建立一個新節點。

----當一個節點被建立的時候,它實際上是在一個名字空間範圍(如果已經提供了名字空間的話)內被建立的。如果沒有提供名字空間的話,它實際上是在文檔的名字空間範圍內被建立的。

解析XML
----為了說明如何在VC中使用XML DOM模型,這裡我們介紹一個簡單的Console Application執行個體程式。下面是主要的程式碼,用來在一個XML 文檔中定位一個特殊的節點,並插入一個新的子節點。
#include
/*下面的.h檔案是在安裝了最新的
XML Parser以後所包含的.h檔案*/
#include “C:\Program Files\Microsoft
  XML Parser SDK\inc\msxml2.h"
#include
void main()
{
   // 初始化COM介面
   CoInitialize(NULL);
/*在程式中,假定裝載的XML檔案名稱為
xmldata.xml,預設情況下它和可執行檔在同
 一個目錄中。該檔案的內容如下:
  
  
  
   Hello, World!
  

----程式將尋找名為“xmlnode”的節點,插入一個新的名稱為“xmlchildnode”的節點,然後它再去尋找一個名為“xmltext”的節點,然後提取包含在該節點中的文本並顯示它,最後它把新的改變過的XML文檔儲存在名稱為

“updatexml.xml”的文檔中。*/
   try {
       // 通過智能指標建立一個解析器的執行個體
CComPtrspXMLDOM;
HRESULT hr =spXMLDOM.CoCreateInstance
    (-uuidof(DOMDocument));
if ( FAILED(hr) ) throw “不能建立XML Parser對象";
if ( spXMLDOM.p == NULL ) throw
   “不能建立XML Parser對象";

// 建立成功,開始裝載XML文檔
VARIANT_BOOL bSuccess = false;
hr =spXMLDOM->load(CComVariant(
L“xmldata.xml"),&bSuccess);
if ( FAILED(hr) ) throw
 “不能夠在解析器中裝載XML文檔";
if ( !bSuccess ) throw
 “不能夠在解析器中裝載XML文檔";
// 檢查並搜尋“xmldata/xmlnode"
CComBSTR bstrSS(L“xmldata/xmlnode");
CComPtrspXMLNode;
       /*用介面IXMLDOMDocument的
       selectSingleNode方法定位該節點。*/
hr =spXMLDOM->selectSingleNode
    (bstrSS,&spXMLNode);
if ( FAILED(hr) ) throw
  “不能在XML節點中定位‘xmlnode’";
if ( spXMLNode.p == NULL ) throw
    “不能在XML節點中定位‘xmlnode' ";
       /*DOM對象“spXMLNode”
     現在包含了XML節點,
     所以我們可以在它下面建立一個子節點。*/
CComPtr spXMLChildNode;
       /*用介面IXMLDOMDocument的方法create
Node方法建立一個新節點。*/
hr = spXMLDOM->createNode(
           CComVariant(NODE_ELEMENT),
           CComBSTR(“xmlchildnode"),
           NULL,&spXMLChildNode);
       if ( FAILED(hr) ) throw “不能建立
       ‘xmlchildnode' 節點";
       if ( spXMLChildNode.p == NULL )
       throw “不能建立‘xmlchildnode' 節點";
//添加新節點到spXMLNode節點下
       CComPtr spInsertedNode;
hr =spXMLNode->appendChild
      (spXMLChildNode,&spInsertedNode);
if ( FAILED(hr) ) throw
    “不能建立‘xmlchildnode' 節點";
if ( spInsertedNode.p == NULL ) throw
    “不能移動‘xmlchildnode' 節點";
       //設定新節點屬性
CComQIPtr spXMLChildElement;
spXMLChildElement = spInsertedNode;
if ( spXMLChildElement.p == NULL )
     throw “不能在XML元素介面中查詢到
    ‘xmlchildnode' ";
       hr =spXMLChildElement->setAttribute
(CComBSTR(L“xml"),CComVariant(L“fun"));
if ( FAILED(hr) ) throw“不能插入新的屬性"; 
/*下面的程式段用來尋找一個節點
 並顯示該節點的相關資訊。*/
// 尋找“xmldata/xmltext"節點
// 釋放先前的節點
       spXMLNode = NULL;
bstrSS = L“xmldata/xmltext";
hr =spXMLDOM->selectSingleNode
    (bstrSS,&spXMLNode);
if ( FAILED(hr) ) throw “不能定位
   ‘xmltext'節點";
if ( spXMLNode.p == NULL ) throw
     “不能定位‘xmltext'節點";
       // 得到該節點包含的文本並顯示它
CComVariant varValue(VT_EMPTY);
hr =spXMLNode->get_nodeTypedValue
(&varValue);
if ( FAILED(hr) ) throw “不能提取‘xmltext'文本";
if ( varValue.vt == VT_BSTR ) {
/*顯示結果。注意這裡要把字串
   從形式BSTR轉化為ANSI。*/
   USES_CONVERSION;
   LPTSTR lpstrMsg = W2T(varValue.bstrVal);
   std::cout<< lpstrMsg << std::endl;
} // if
else {
   // 如果出現錯誤
   throw “不能提取‘xmltext'文本";
} // else
       //將修改過的XML文檔按指定的文檔名儲存
hr = spXMLDOM->save(CComVariant
   (“updatedxml.xml"));
if ( FAILED(hr) ) throw
   “不能儲存修改過的XML文檔";
std::cout << “處理完成..."  << std::endl << std::endl;
} // try
   catch(char* lpstrErr) {
// 出現錯誤
std::cout << lpstrErr << std::endl << std::endl;
   } // catch
   catch(...) {
// 未知錯誤
std::cout << “未知錯誤..." << std::endl << std::endl;
   } // catch
   // 結束對COM的使用
   CoUninitialize();
}

----因為XML文檔有比HTML更加嚴格的文法要求,所以使用和編寫一個XML解析器比編寫一個HTML的解析器要容易。同時因為XML文檔不僅標記文檔的顯示內容,更重要的是它標記了文檔的結構和包含資訊的特徵,所以我們可以方便地通過XML解析器來擷取特定節點的資訊並加以顯示或修改。

下面是我最近做的一個程式的儲存xml格式:存和讀取
存的時候用的SAX2.0 讀取的時候用的DOM
void CSysDrawDoc::CreateXmlDoc(CFile *pfile) 
{
 HRESULT hr;
    hr = CoInitialize(NULL);
 USES_CONVERSION;
 ISAXDTDHandlerPtr dtd=NULL;
 hr = pWr.CreateInstance(__uuidof(MXXMLWriter40));
 dtd = pWr;
 pWr->indent = VARIANT_TRUE;
 pWr->omitXMLDeclaration =VARIANT_TRUE;
 
    ISAXContentHandlerPtr spContentHandler=NULL;
    spContentHandler = pWr;
 
 //Start the document by adding the XML declaration.
 hr = spContentHandler->startDocument ();
 char szPI[]= "version='1.0' encoding='gb2312' standalone='no'";//iso-8859-1   encoding = 'utf-16'
 
 //Step 1: Create the XML declaration.
 hr = spContentHandler->processingInstruction(L"xml", 3, A2W(szPI), strlen(szPI));//xml版本聲明
 //   沒有加DTD驗證
 //   ISAXLexicalHandlerPtr lexh;
 //  lexh = pWr;
 //  lexh->startDTD(L"svg",3,L"-//W3C//DTD SVG 20001102//EN",28,L"http://www.w3.org/TR/2000/CR-SVG-20001102.dtd",45);
 //   lexh->endDTD();
 //   Step 2: Create the root ---svg  element.
 IMXAttributesPtr     pMXAttr = NULL;
 ISAXAttributesPtr    spAttributes = NULL;
 hr = pMXAttr.CreateInstance(__uuidof(SAXAttributes40));
 pMXAttr->addAttribute(L"",L"Width",L"Width","float","3200");
 pMXAttr->addAttribute(L"",L"Height",L"Height","float","2400");
 pMXAttr->addAttribute(L"",L"xmlns",L"xmlns","string","http://www.w3.org/2000/svg");
 spAttributes= pMXAttr;
 hr = spContentHandler->startElement(L"", 0, L"svg",3, L"svg",3,spAttributes);  
 //Step 3:  添加子類元素
 int num = 0;
 for (POSITION pos = m_objects.GetHeadPosition(); pos != NULL; )
 {
  CDrawObj* pObj = m_objects.GetNext(pos);
 // if((!pObj->IsKindOf(RUNTIME_CLASS(CDrawE_Label)))&&(!pObj->IsKindOf(RUNTIME_CLASS(CDrawE_Node))))
  {
   if(!pObj->m_bElemGroup)
   {
    pObj->WriteCont(pWr);
    VARIANT vtTemp = pWr->output;
    CString str= vtTemp.bstrVal;
    LPTSTR st = str.LockBuffer();
    int len = str.GetLength();
    pfile->Write(st,len);
    vtTemp.vt =VT_EMPTY;
    pWr->output = vtTemp;
   }
  }
 }
    //結束根項目,和文檔
    hr = spContentHandler->endElement(L"",0,L"svg",3, L"svg",3);
 hr = spContentHandler->endDocument();
 
 VARIANT vtTemp = pWr->output;
    CString str ="";
 str= vtTemp.bstrVal;
 LPTSTR st = str.LockBuffer();
 int len = str.GetLength();
 pfile->Write(st,len);
 vtTemp.vt =VT_EMPTY;
 pWr->output = vtTemp;
}

void  CSysDrawDoc::ReadDOMDoc(char *p)
{    
 CSysDrawApp *pApp = (CSysDrawApp *)AfxGetApp(); 
 HRESULT hr;
 CoInitialize(NULL);
 hr = pXMLDoc.CreateInstance(__uuidof(DOMDocument40));
 if(FAILED(hr))
  return;
 CString m_sys = p;
 _variant_t varOut((bool)TRUE);
 _variant_t varXml = m_sys;
 varOut = pXMLDoc->load(varXml);
 if((bool)varOut == FALSE )
 {
  AfxMessageBox("文檔格式不正確,不能夠載入xml文檔");
  return;
 }
 //      if ((bool)varOut == FALSE)//出錯資訊
 //     {
 //    IXMLDOMParseErrorPtr errPtr = pXMLDoc->GetparseError();
 //       _bstr_t bstrErr(errPtr->reason);
 //        _tprintf(_T("Error:\n"));
 //      _tprintf(_T("Code = 0x%x\n"), errPtr->errorCode);
 //    _tprintf(_T("Source = Line : %ld; Char : %ld\n"), errPtr->line, errPtr->linepos);
 //  _tprintf(_T("Error Description = %s\n"), (char*)bstrErr);
 
 //     }
 IXMLDOMNodePtr      pNode = NULL;
 IXMLDOMNodeListPtr  pNodeList = NULL;
 IXMLDOMElementPtr   pDOMElement = NULL;
 IXMLDOMNamedNodeMapPtr pAttributeMap = NULL;
 IXMLDOMNodePtr  pChildListNode = NULL;
 
 // IXMLDOMNodeList *pIXMLDOMNodelist = NULL;
 //     IXMLDOMNamedNodeMapPtr pAttributeMap = NULL;
 IXMLDOMNodePtr  pAttributeNode = NULL;
 hr = pXMLDoc->get_documentElement(&pDOMElement);
 if(pDOMElement == NULL)
 {
  
  AfxMessageBox("文檔解析失敗!");
  return;
 }
 pDOMElement->get_childNodes(&pNodeList);
 long num =pNodeList->length ;
 for (int i = 0;i < num ;i++)
 {
  pNodeList->get_item(i, &pNode);
  if(pNode)
  {
   //如果接點不為空白,解析類子項目接點line,bianyaqi
   _bstr_t str = pNode->nodeName;//root的子項目名稱
   _bstr_t name = _T("name");
   BSTR bstrAttributeName =name;
   IXMLDOMNode *pIXMLDOMNode = NULL;
   VARIANT varValue;
   pNode->get_attributes(&pAttributeMap);
   long length = pAttributeMap->length;  //
              /* char group[10];
              BOOL bgroup = FALSE;
              hr = pAttributeMap->get_item(1,&pIXMLDOMNode);
              if(pIXMLDOMNode)
              {
              _bstr_t s = pIXMLDOMNode->nodeName;
              pIXMLDOMNode->get_nodeValue(&varValue);
              strcpy(group,_bstr_t(&varValue));
              if(pApp->StringToBool(group))
              bgroup = TRUE;
  }*/
   hr = pAttributeMap->get_item(0,&pIXMLDOMNode);//返回name的屬性值
   if(pIXMLDOMNode)
   {
    _bstr_t s = pIXMLDOMNode->nodeName;
    pIXMLDOMNode->get_nodeValue(&varValue);
    char strin[30];
    strcpy(strin, _bstr_t(varValue) );
    CONT_TYPE  step;
    int i = arrayicmp(strin, objcmd);
                 ............省略
}

希望對樓主有所協助,
}
}

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.