XML 设置






3.54/5 (9投票s)
2005年2月5日
3分钟阅读

79927

676
使用 XML 存储设置。
引言
这有点奇怪,不是吗?我的意思是,XML 的整个东西——一个由尖括号和纯文本组成的奇特组合——确实改变了 IT 世界。 关于 XML 有很多传言,但我认为这是一项有价值的技术——特别是,当与 XSLT 的强大功能结合使用时。 然而,这只是一个介绍性的东西。 这是主要思路。
程序员过去常常使用系统注册表来保存程序设置等等。 啊,我忘了。 一开始有 INI 文件——好东西,但是没有 INI 解析器(与现在可用的各种 XML 解析器相反),没有验证和转换的可能性,而且它们不是分层的。 总的来说,它们很好,仅此而已。 之后,程序开始利用系统注册表——它具有某种“内置”的验证和层次结构支持。 但这仍然不够。 首先,对于没有经验的用户来说,没有简单的方法来导出程序设置(除非该功能由程序本身提供),这由于定期的系统重新安装而很糟糕。 其次,注册表总是被认为是一种野兽。 它总是可能变得损坏,它总是很乱,这很糟糕。 所以,剩下的唯一一件事是,不出所料,XML。
背景
在我 XML 时代的开始,我使用显式代码来读取属性、写入属性、验证等等。 这很混乱,因此编写一组可以为我处理所有常规任务的类是很自然的。 说到做到。
内部
该库非常简单。 它结合使用了 Microsoft XML 解析器、STL、COM 支持类和 MFC,我认为这不太好,但对于初学者来说已经足够了。 代码本身大约 200 行长,所以我最好在这里引用它。
namespace Xml { // // Variants map // typedef std::map<CSTRING, _variant_t> CONTAINER_MVARIANT; // // Represents a single Element in the XML Settings file // class XmlSettingsElement { // Element name CString m_strName; // Items container CONTAINER_MVARIANT m_mvItems; public: // // Default constructor XmlSettingsElement(void) { } // // Constructor XmlSettingsElement(const CString &strName) : m_strName(strName) { } // // Destructor ~XmlSettingsElement(void) { } // // Indexing _variant_t& operator [] (const CString &strItem) { return m_mvItems[strItem]; } // // Sets name void SetName(const CString &strName) { m_strName = strName; } // // Gets name CString GetName(void) const { return m_strName; } // // Saves Element contents MSXML2::IXMLDOMElementPtr Save(const MSXML2::IXMLDOMDocument2Ptr &xmlDoc) const { MSXML2::IXMLDOMElementPtr xmlElement = xmlDoc->createElement((LPCTSTR)m_strName); // // Adding attributes for(CONTAINER_MVARIANT::const_iterator mxvci = m_mvItems.begin(); mxvci != m_mvItems.end(); ++mxvci) { xmlElement->setAttribute(_bstr_t(mxvci->first), mxvci->second); } // for return xmlElement; } // // Loading Element contents void Load(const MSXML2::IXMLDOMElementPtr& xmlElement) { // // Loading items // for(long lItem = 0; lItem < xmlElement->attributes->length; ++lItem) { m_mvItems.insert(std::make_pair( (LPCTSTR)xmlElement->attributes->item[lItem]->nodeName, xmlElement->attributes->item[lItem]->nodeValue)); } } }; // // XML Settings Elements map // typedef std::map<CString, XmlSettingsElement> CONTAINER_MXMLSETTINGSELEMENT; // // XML Settings class // class XmlSettings { // Container CONTAINER_MXMLSETTINGSELEMENT m_mxseElements; public: XmlSettings() { } ~XmlSettings() { } // // Indexing XmlSettingsElement& operator [] (const CString &strElement) { // // Return existing one, or create a new element m_mxseElements[strElement].SetName(strElement); return m_mxseElements[strElement]; } // // Save contents MSXML2::IXMLDOMElementPtr Save( const MSXML2::IXMLDOMDocument2Ptr &xmlDoc, const CString& strName) { MSXML2::IXMLDOMElementPtr xmlElement = xmlDoc->createElement((LPCTSTR)strName); // // Saving all Elements in the container for(CONTAINER_MXMLSETTINGSELEMENT::const_iterator mxseci = m_mxseElements.begin(); mxseci != m_mxseElements.end(); ++mxseci) { xmlElement->appendChild(mxseci->second.Save(xmlDoc)); } // for return xmlElement; } // // Save contents to the XML file void Save(const CString& strElementName, const CString& strFileName) { MSXML2::IXMLDOMDocument2Ptr xmlDoc(__uuidof(MSXML2::DOMDocument30)); xmlDoc->appendChild(Save(xmlDoc, strElementName)); xmlDoc->save((LPCTSTR)strFileName); } // // Load contents void Load(const MSXML2::IXMLDOMElementPtr& xmlElement) { // // Loading elements for(long lItem = 0; lItem < xmlElement->childNodes->length; ++lItem) { MSXML2::IXMLDOMElementPtr xmlItem = xmlElement->childNodes->item[lItem]; XmlSettingsElement xse(_variant_t(xmlItem->nodeName)); xse.Load(xmlItem); m_mxseElements[_variant_t(xmlItem->nodeName)] = xse; } // for } // // Load contents from the XML file (from the document element) void Load(const CString& strFileName) { MSXML2::IXMLDOMDocument2Ptr xmlDoc(__uuidof(MSXML2::DOMDocument30)); if(VARIANT_FALSE == xmlDoc->load((LPCTSTR)strFileName)) return; Load(xmlDoc->documentElement); } }; } // namespace Xml
Using the Code
使用起来非常简单。 您加载文件,您使用设置,您保存文件。 就这样。
这就是我们加载的方式
// // Should be member variable, I guess Xml::XmlSettings xsSettings; // // Note the CString thing xsSettings.Load(CString("Settings.xml"));
就是这样。 如果文件未加载,它不会引发任何异常——它只会将所有内部数据结构初始化为空的。 请注意,std::map
在整个类中使用——它有很多含义,但稍后会对此进行详细介绍。 现在,是时候加载设置了。
// // Loading settings int integerValue = xsSettings["runtimeSettings"]["integerValue"]; double doubleValue = xsSettings["runtimeSettings"]["doubleValue"]; CString stringValue = xsSettings["server"]["stringValue"]; // // Saving settings xsSettings["runtimeSettings"]["integerValue"] = 123; xsSettings["runtimeSettings"]["doubleValue"] = 123.355; xsSettings["server"]["stringValue"] = _bstr_t("https://codeproject.org.cn");
现在我必须注意一个简单的事实。 std::map
的索引运算符(C++ 术语中的 operator []
)首先检查 map 中是否存在这样的元素。 如果存在,则返回它。 如果没有,首先它使用默认构造函数创建它(值得庆幸的是,_variant_t
的默认构造函数将所有字段初始化为零),然后返回这个新创建的对象。 因此,例如,如果 Settings 元素和 Attribute 都不存在,它将创建这两个对象并返回对空 _variant_t
的引用。 就是这样。
最后一步。 保存 XML 文件。
xsSettings.Save(_T("settings"), CString("Settings.xml"));
对内部 map 所做的所有更改都将保存到 XML 文件中。
关注点
正如我已经说过的,我在整个类中使用几个不同的类,所以这将是我的首要问题。 如果您有任何建议或意见,请在此处留下。 提前致谢。
历史
- 2005 年 2 月 5 日。版本 1.0。
初始发布。