MSXML

微軟XML核心服務（MSXML）提供了一組服務，使使用者可以使用JScript、VBScript和其它微軟的開發工具開發基於XML的本機應用程式。它支持XML 1.0、DOM、SAX、XSLT 1.0，並提供了包括XSD和XDR在內的XML schema、XMLHttpRequest、XPath、SOM等技術。

## 版本歷史

MSXML是不同產品的合集。可從此處枚舉各個版本：

### 現行有效版本

- MSXML 6.0 MSXML6是最新版本。與MSXML3一起隨Microsoft SQL Server 2005、Visual Studio 2005、.NET Framework 3.0、Windows Vista、Windows XP Service Pack 3發行。支持64位本地環境。版本6可以替代版本4，但不能替代版本3。MSXML 6不支持Windows 9x。
- MSXML 3.0對應於msxml3.dll。MSXML 3.0 SP2隨Windows XP、Internet Explorer 6.0與MDAC 2.7發行。Windows XP SP2包含MSXML 3.0 SP5，作為MDAC 2.81的一部分。Internet Explorer 版本6.0、7.0、8.0使用MSXML 3解析XML文檔。MSXML 3.0 SP7是Windows 95支持的最高版本。Windows XP SP3包含MSXML 3.0 SP9。Windows Vista包含MSXML 3.0 SP10。

### 過時版本

- MSXML 5.0隨Microsoft Office 2003與Office 2007發布。Microsoft沒有發布5.0的文檔，因為MSXML 5僅為Office 2003與2007內部使用。Office 2010不包含MSXML 5.0。
- MSXML 4.0隨獨立的、可下載的SDK發布，不能完全兼容版本3.0。只有32位版本。MSXML 4.0 SP3是最高版本。並於2014年4月過期。
- MSXML 2.6隨Microsoft SQL Server 2000與MDAC 2.6發布，對應於msxml2.dll，最後版本為 KB887606 .
- MSXML 2.5隨Windows 2000中的Internet Explorer 5.01 與MDAC 2.5發布。對應於msxml.dll
- MSXML 2.0a隨Internet Explorer 5.0發布
- MSXML 1.0隨Internet Explorer 4.0發布

## DOM

MSXML以COM接口（Interface）的形式提供了一套XML的分析器（parser），從而實現了DOM。

常用的接口：

### IXMLDOMDocument

IXMLDOMDocument是XML文檔接口，是DOM樹結構的根結點。

```cpp
//声明并创建一个IXMLDOMDocument的智能指针：
MSXML2::IXMLDOMDocumentPtr pXmlDoc;
HRESULT hr = pXmlDoc.CreateInstance( __uuidof(MSXML2::DOMDocument60), NULL, CLSCTX_INPROC_SERVER);
if( FAILED(hr))
        printf("Failed to create DOM document interface pointer.\n");

//加载xml文件代码为： 
try
{
        pXmlDoc->async = VARIANT_FALSE; // 使用阻塞式同步加载xml文件。默认是异步方式加载，还需要检查IXMLDOMDocument的ReadyState，这特别适用于从网络上加载。 
        pXmlDoc->validateOnParse = VARIANT_FALSE;//加载xml文件时，是否依据xml文件中指明的DTD或schema检查xml文件的结构
        pXmlDoc->resolveExternals = VARIANT_FALSE;//分析xml时，外部定义或ocument type definition(DTD)等不被处理
        if( pXmlDoc->load("test.xml") != VARIANT_TRUE)
        {
            printf("Fail reason: %s\n", (LPCSTR)pXmlDoc->parseError->Getreason());
       }
       else
       {
            // success
       }
}
catch(_com_error errorObject)
{
        printf("Exception, HRESULT = 0x%08x", errorObject.Error());
} 

//保存xml文件：
try
{   
        if( FAILED( pXmlDoc->save(L"myData.xml")))
        {
              printf("Fail reason: %s\n", (LPCSTR)pXmlDoc->parseError->Getreason());
         }
         else
         { 
             // success
          }
}
catch(_com_error errorObject)
{
          printf("Exception, HRESULT = 0x%08x", errorObject.Error());
}
```

### IXMLDOMNode

IXMLDOMNode是通用的節點接口，各種類型節點接口都從它派生，包括IXMLDOMDocument。節點類型包括：

節點類型｜示例

NODE_ELEMENT｜The Offspring

NODE_ATTRIBUTE｜>The Offspring

NODE_TEXT｜The Offspring

NODE_CDATA_SECTION｜示例

NODE_ENTITY_REFERENCE｜示例

NODE_ENTITY｜示例

NODE_PROCESSING_INSTRUCTION

NODE_COMMENT｜示例

NODE_DOCUMENT｜示例

NODE_DOCUMENT_TYPE

NODE_DOCUMENT_FRAGMENT｜示例

NODE_NOTATION｜示例

獲取根節點的一種方法：

```cpp
MSXML2::IXMLDOMNodePtr pRootNode, pTempNode;
pXmlDoc->get_firstChild(&pRootNode);
while( pRootNode)
{
         MSXML2::DOMNodeType type;
         pRootNode->get_nodeType(&type);
         if(type==NODE_ELEMENT)  // 如果是element节点，而不是注释、回车符等
              break;                            //找到了根节点
         pTempNode = pRootNode;
         pTempNode->get_nextSibling(&pRootNode);
}  
```

### IXMLDOMNodeList

IXMLDOMNodeList是節點列表的接口，表示一組兄弟（sibling）節點的列表。可以通過index從0開始遍歷列表。列表中的元素還是動態的，會隨著XML文檔的改變而更新。

### IXMLDOMNamedNodeMap

IXMLDOMNamedNodeMap是命名節點的無序集合的接口。該接口常用於表示節點的屬性集，並且是動態的。

### IXMLDOMElement

IXMLDOMElement是元素的接口，一般用來表示一個節點及其屬性。

```cpp
//获取文档根节点的方法一：
MSXML2::IXMLDOMElementPtr pRootNode = pXmlDoc->documentElement;
//获取文档根节点的方法二：
MSXML2::IXMLDOMElementPtr pRootNode2;
pXmlDoc->get_documentElement(&pRootNode2);
```

### IXMLDOMAttribute

IXMLDOMAttribute是節點屬性的接口。

### IXMLDOMText

IXMLDOMText是節點的文本的接口。

### IXMLDOMComment

IXMLDOMComment是XML文檔的注釋的接口。

### IXMLDOMParseError

IXMLDOMParseError是XML分析時語法出錯的接口，包括了錯誤的詳細資訊。

### IXMLDOMCharacterData

IXMLDOMCharacterData是字符數據的接口。也是一批基於字符的接口的基類。

### IXMLDOMCDATASection

IXMLDOMCDATASection是CDATA類型的文本的接口。

### 各種智能指針

DOM的各種接口一般都有相應的智能指針接口，通常為接口名加上Ptr。例如IXMLDOMDocument的智能指針接口為IXMLDOMDocumentPtr。

## C++語言使用

需要在源程序中加入這行：

```C++
#import <msxml6.dll> raw_interfaces_only
```

這使得在工程（Project）的編譯文件夾下生成msxml6.tlh和msxml6.tli兩個文件，分別相當於COM接口的頭文件與實現文件。「raw_interfaces_only」屬性使得生成的msxml6.tlh中，各個結構中只包含返回類型為HRESULT的接口函數，並且接口函數名省去了raw_前綴；如果不用該屬性，則默認是在各個結構中聲明了一套帶raw_前綴的返回HRESULT類型的接口函數以及不帶raw_前綴的返回各種VARIANT_類型的wrapper接口函數。

也可以通過連接輸入庫文件msxml6.lib來使用。

作為COM庫，在線程的開頭與結束之處需要分別調用COM環境的初始化與去初始化函數：CoInitialize、CoUninitialize。

MSXML的各種資源都放在了MSXML2名字空間（namespace）中。

## Visual Basic使用

首先在Visual Basic的Project上打開Add Reference對話框，在COM標籤頁（tab）中，增加「Microsoft, v6.0」的引用。也可以選擇4.0或5.0版本的引用。

然後，在原始碼中輸入：

```basic
Dim xDoc As MSXML.DOMDocument 
Set xDoc = New MSXML.DOMDocument

'If xDoc.Load("http://www.develop.com/hp/brianr/cds.xml") Then
If xDoc.Load("C:\My Documents\cds.xml") Then
   ' The document loaded successfully.
   ' Now do something intersting.
Else
    ' The document failed to load.
   Dim strErrText As String
   Dim xPE As MSXML.IXMLDOMParseError
   ' Obtain the ParseError object
   Set xPE = xDoc.parseError
   With xPE
      strErrText = "Your XML Document failed to load" & _
        "due the following error." & vbCrLf & _
        "Error #: " & .errorCode & ": " & .reason & _
        "Line #: " & .Line & vbCrLf & _
        "Line Position: " & .linepos & vbCrLf & _
        "Position In File: " & .filepos & vbCrLf & _
        "Source Text: " & .srcText & vbCrLf & _
        "Document URL: " & .url
    End With

    MsgBox strErrText, vbExclamation

End If

Set xDoc = Nothing
```

## VBScript使用

```
Set objParser = CreateObject( "Microsoft.XMLDOM" )
```

## 參考文獻

- MSDN:Microsoft XML Team Blog