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

XML 生成器

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.50/5 (2投票s)

2001年4月2日

4分钟阅读

viewsIcon

174430

downloadIcon

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 的辅助类/结构,该结构有两个名为 strNamestrValue 的成员变量。

两个成员变量的类型都是 _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 += "&lt!- ;
     strFinalString += strNode;
     strFinalString += ">";

   }
   return strFinalString;
}     

我想感谢 Morten Abrahamsen 提供的 _bstr_t 的包装类 CEnBSTR,我已将其用于字符串操作。

此类本身将生成非常简单的 XML。但对于复杂的层次结构,您需要从该类派生并根据需要重写方法。我在演示项目中使用了两个这样的类。代码将执行,除了我之前提到的数据库服务器名称。

欢迎任何评论和建议。祝您 XML 生成愉快。

© . All rights reserved.