使用新的 ATL CString 类通过 MSXML 读取 XML 文件





3.00/5 (2投票s)
2001 年 4 月 20 日
4分钟阅读

100286

1040
使用 MSXML 和新的 ATL/MFC 共享 CString 类读取 XML 文件的简单应用程序
背景
这个项目和文章的起因是尝试编写一个使用新的 _ATL_DEBUG_INTERFACES
宏的示例应用程序。然而,我在 VS.NET Beta1 中遇到了一个障碍,因为 _com_ptr_t
模板目前不支持该宏,并且它不适用于已编译的接口。因此,我有一个几乎完整的应用程序,我不想就这样扔掉。我决定完成它,并尝试使用新的 CString
类。
我希望从中获得什么
我的目标是让你获得一些关于使用 IXMLDOM*
接口的有用信息,一些关于 ATL 的 CString
类用法的知识,在控制台应用程序中使用 ATL 支持的经验,以及对 .NET 框架中的命名空间的一些了解。
.NET 命名空间示例
“.NET 命名空间”应用程序非常直接。它将一个名为 Namespaces.XML
的 XML 文件加载到一个 IXMLDOMDocument
智能指针中。然后,它从 DOMDocument
指针获取文档元素,并解析剩余的树。当应用程序解析树时,它会按照 XML 文档中定义的层次结构生成一个命名空间列表。当遇到 Namespace
元素时,它会获取 Name
属性值,并将其附加到父路径并显示。如果 Namespace
节点不包含子 Namespace
节点,它将获取该节点的文本并显示该文本(附加到父路径),如果其长度大于零。这表示 Namespace
包含更多命名空间,但未在 XML 文档中定义。

图 1: DotNetNamespace.exe 的输出
Namespaces.XML
下面是 Namespaces XML 文件的布局,应用程序的实现将基于此。
<?xml version="1.0"?>
<Namespaces>
<Namespace Name="System">
<Namespace Name="CodeDOM">
<Namespace Name="Compiler"/>
</Namespace>
<Namespace Name="Collections">
<Namespace Name="Bases"/>
</Namespace>
<Namespace Name="ComponentModel">
<Namespace Name="Design">
<Namespace Name="CodeModel"/>
</Namespace>
</Namespace>
<!-- ... SNIPPED ... -->
<Namespace Name="Core">[...]</Namespace>
<!-- ... SNIPPED ... -->
</Namespace>
</Namespaces>
DotNetNamespace.CPP
我想用一段话来描述一些 CString
的用法以及我在开发应用程序时遇到的问题。
下面我们可以看到,我们使用 CAtlStringW
来定义我们正在处理的 xml 文件的名称。然后,我们将其作为参数传递给 XMLDOMDocument
对象的 load 方法,该对象首先被包装在一个 <code>_variant_t
对象中。如果加载成功,我们将继续;否则,我们将向标准输出写入一条消息,表示我们无法加载文件。在这里遇到的一個问题是,在写入输出流时,CString
对象上的 PCXSTR
操作符(根据 MSDN 文档和示例)不起作用。如果你尝试使用它,它将编译出错,并提示标识符未定义。但如果你使用 GetString
,它返回一个 PCXSTR
,就可以工作。希望这个问题在 Beta2 中能得到修复。可能有一个必需的包含文件,但我没有花时间去查找,因为 GetString
可以工作,我想 PCXSTR
应该是可用和已定义的。
LoadAndParse()
中的代码片段。// build path to tip of the day xml file CAtlStringW strFileName("Namespaces.xml"); VARIANT_BOOL vbLoaded = VARIANT_FALSE; // Load the XML file. hr = ptrNamespacesXML->load(_variant_t(strFileName), &vbLoaded); if (SUCCEEDED(hr) && vbLoaded == VARIANT_TRUE) { // ... Code Snipped } else { wcout << L"Problem: Unable to load, " << strFileName.GetString() << endl; // *** PCXSTR is undefined so must use GetString in Beta1 //wcout << L"Problem: Unable to load, " << (PCXSTR)strFileName << endl; }
接下来,我们展示一些你可以用来更轻松地构建字符串的新方法。通过使用 AppendFormat
方法,你可以使你的代码更具可读性,并让模板类为你完成相关工作,同时节省需要生成的代码量。同样,我们使用 GetString
方法,原因与前一段描述的相同。
DisplayNamespaces()
中的代码片段,从获取 Namespace
节点的 Name
属性后开始。// ... Code Snipped BSTR bstrName = NULL; hr = ptrName->get_text(&bstrName); if (SUCCEEDED(hr) && bstrName) { if (strPath.GetLength() == 0) { strPath = bstrName; } else { strPath.AppendFormat(L".%s", bstrName); } SysFreeString(bstrName), bstrName = NULL; wcout << strPath.GetString() << endl; } // ... Code Snipped
如果我们愿意,我们可以使用 CString
类的 MakeUpper
或 MakeLower
方法将命名空间转换为某种标准,以防 XML 文档中意外地插入了大写字母。要做到这一点,我们可以修改上面的代码片段,使其如下所示。
// ... Code Snipped BSTR bstrName = NULL; hr = ptrName->get_text(&bstrName); if (SUCCEEDED(hr) && bstrName) { if (strPath.GetLength() == 0) { strPath = bstrName; } else { strPath.AppendFormat(L".%s", bstrName); } SysFreeString(bstrName), bstrName = NULL; strPath.MakeUpper(); // "System.CodeDOM" --> "SYSTEM.CODEDOM" wcout << strPath.GetString() << endl; } // ... Code Snipped
我们还可以做一些更巧妙的事情,调用 MakeReverse
方法,它会为我们反转字符串,然后将字符串写出去,一切都会从右到左反向读取。
留给读者的练习
虽然 Namespaces.xml 文件已经开始,但远未完成。如果你想进一步扩展它,可以完善 Namespaces.XML 文件,使其包含命名空间内的其他附加命名空间和类。你还可以构建树来显示每个命名空间级别中包含的子项数量。将这些构建到现有的应用程序中将能增强你使用 IXMLDOM*
接口和 CAtlString
(CString
) 类的经验。该应用程序和 XML 文件还可以进一步扩展,以在基于 UI 的应用程序中显示每个命名空间的作用的描述。