XML 生成器






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

174430

2668
从任何数据源生成 XML
必备组件
必须了解 ATL、ADO 和 XML。
引言
这是一篇关于 XML 以及如何生成 XML 的文章。我有一个项目,其设计采用“n”层形式,应用程序要求使用 XSLT 显示数据。XSLT 的输入是 XML 数据。项目的所有数据都存储在 SQL Server 7.0 中,我们需要检索数据,将其转换为 XML,然后以 XSLT 转换的形式提供给后续处理。我们需要输出各种层次结构。
数据库
演示中使用的数据库是老牌的 pubs 数据库,这是 SQL Server 安装的标准数据库之一。
您需要在演示中更改数据库服务器的名称。这是一个在 stdafx.h 中定义的常量。需要更改的行如下:
#define CONNECTION_STRING L"Provider=sqloledb;Data Source=[your database server name here];Initial Catalog=pubs;"
类
现在来说说这个类。类的名称是 CXMLGenerator
。
由于项目设计,整个类被封装在一个 ATL 对象中。它有一个成员变量、一些静态函数以及其他虚拟函数,以便于 XML 生成,这样更灵活。
所有数据类型都与自动化兼容,以便于脚本语言调用这些对象。
此类使用一个名为 ATTRIBUTE
的辅助类/结构,该结构有两个名为 strName
和 strValue
的成员变量。
两个成员变量的类型都是 _bstr_t
。
以下是类的所有成员列表:
1. 成员变量
类中只有一个私有成员变量,用于存储 DWORD
类型的数据。这在 XML 生成中很有用,如果我们希望 XML 的生成依赖于某些条件。
DWORD m_lParam;
2. 静态函数
函数定义如下:
BSTR CreateElement(BSTR strElementName,ATTRIBUTE * AttributeList, BOOL bHasValue, BSTR strElementValue);
上述函数用于实际创建 XML 文档中的元素。第一个参数是创建元素的名称,第二个参数是该属性可以拥有的属性列表。如果元素不需要任何属性,则此值必须为 NULL
。
第三个参数用于检查元素是否有值。如果将此参数传递为 false,则将忽略最后一个参数,并且元素是自结束的或空的标签。否则,如果第三个参数为 true,则将最后一个参数作为元素的值,然后以元素名称结束标签。
例如,CreateElement ("author",NULL,false,"")
将返回 <author/>
。
而如果使用类型为 strName = "ID"
和 strValue = "003"
的 ATTRIBUTE
,并将最后一个参数设为 "Shobha De"
来调用同一个函数,CreateElement ("author",attributeList, true,"Shobha De")
,则输出将如下所示:<author id="003">ShobhaDe</author>
。
BSTR XMLEncode(BSTR strEncode);
用于根据 XML 标准对数据进行编码。
3. 虚拟函数
以下是虚拟函数列表:
BSTR PostContent(_RecordsetPtr RS);
此函数用于在 XML 元素的内容生成后、元素关闭前进行一些后处理。
BSTR PreContent(_RecordsetPtr RS);
此函数用于在 XML 元素的内容生成前、元素定义后进行一些预处理。
BSTR BeforeEnd();
此函数用于在为给定记录集生成 XML 后,如果需要,添加更多 XML 数据。
BSTR AfterStart();
此函数用于在为给定记录集生成 XML 前,如果需要,添加更多 XML 数据。
BOOL HasValue(BSTR strElementName, BSTR strFieldValue);
此函数根据元素是否应具有值或元素应为空或自结束来返回 true 或 false。
BSTR GetValue(BSTR strElementName, BSTR strFieldValue);
此函数提供了更改元素值的灵活性,如果需要,否则返回传递给函数的值。
ATTRIBUTE * GetAttributeList(BSTR ElementName, _RecordsetPtr RS);
如果此处需要属性,此函数将返回该元素的 ATTIRBUTE 数组。属性以名称-值对的形式存在。
BSTR GetElementName(BSTR FieldName);
此函数返回元素名称,如果我们想根据传递的参数更改名称。
BSTR GenerateXML(_RecordsetPtr RS,BSTR strRootNode, BSTR strChildNode, DWORD lParam)
此函数是 XML 生成的实际主力。
该函数代码如下:
BSTR CXMLGenerator::GenerateXML(_RecordsetPtr RS, BSTR strRootNode, BSTR strChildNode, DWORD lParam)
{
CEnBSTR *strFieldName;
_bstr_t strNode;
_bstr_t strFinalString = _bstr_t("");
if(SysStringLen(strRootNode) != 0)
{
// Append RootNode in the String
strFinalString = "<";
strFinalString += strRootNode;
strFinalString += ">";
// Get the RootNodeName from whole string with Attributes.
strNode = GetNodeName(strRootNode);
}
// store the Param in member variable
m_lParam = lParam;
// Give one chance to AfterStart Function
strFinalString += AfterStart();
long nFldCount = RS->Fields->GetCount();
strFieldName = new CEnBSTR[nFldCount];
// Store all the FieldName in an Array.
for(long i=0; i < nFldCount; i++)
{
strFieldName[i] = RS->Fields->Item[i]->Name;
strFieldName[i].lower();
}
// Contains Final Element
_bstr_t strFinalElement;
// For each Record in in the RecordSet here each record means eg. Author
while(!RS->ADOEOF)
{
strFinalElement = "";
// Get the Attribute of the Child Node.
ATTRIBUTE * ChildAttribute = GetAttributeList(strChildNode,RS);
// Give a Chance to PreContent
strFinalElement = PreContent(RS);
// Now for each Element in ChildNode e.g Cycle Get the Name and Attribute List
for(long i=0; i < nFldCount; i++)
{
_bstr_t strElement = GetElementName(strFieldName[i]);
if(SysStringLen(strElement) != 0)
{
_variant_t temp1, temp2;
// Get the Attribute List fpr Elements.
ATTRIBUTE * EleAttribute = GetAttributeList(strElement,RS);
temp1 = RS->Fields->GetItem(i)->Value;
_bstr_t strElementValue;
if(temp1.vt != VT_NULL)
{
HRESULT hr = VariantChangeType (&temp2,&temp1, VARIANT_NOUSEROVERRIDE | VARIANT_ALPHABOOL,VT_BSTR); if (FAILED(hr))
{
return _bstr_t ("");
}
strElementValue = temp2.bstrVal ;
}
else
strElementValue = _bstr_t("");
BOOL bHasValue = HasValue(strElement,strElementValue);
if(bHasValue)
{
strElementValue = GetValue(strElement,strElementValue);
}
// Add to Final String
strFinalElement += CreateElement(strElement,EleAttribute,bHasValue,strElementValue);
if (EleAttribute)
delete [] EleAttribute;
}
}
// Give a Chance to PostContent
strFinalElement += PostContent(RS);
// Create the Child Node & add it in Final XML String
strFinalString += CreateElement(strChildNode,ChildAttribute,SysStringLen(strFinalElement) ? TRUE : FALSE, strFinalElement);
if (ChildAttribute)
delete [] ChildAttribute;
RS->MoveNext();
}
// Give a chance to BeforeEnd.
strFinalString += BeforeEnd();
if(SysStringLen(strRootNode) != 0)
{
// Append the Closing RootNode.
strFinalString += "<!- ;
strFinalString += strNode;
strFinalString += ">";
}
return strFinalString;
}
我想感谢 Morten Abrahamsen 提供的 _bstr_t
的包装类 CEnBSTR,我已将其用于字符串操作。
此类本身将生成非常简单的 XML。但对于复杂的层次结构,您需要从该类派生并根据需要重写方法。我在演示项目中使用了两个这样的类。代码将执行,除了我之前提到的数据库服务器名称。
欢迎任何评论和建议。祝您 XML 生成愉快。