65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconemptyStarIconemptyStarIcon

3.00/5 (2投票s)

2001 年 4 月 20 日

4分钟阅读

viewsIcon

100286

downloadIcon

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 的应用程序中显示每个命名空间的作用的描述。

© . All rights reserved.