C++处理XML文件

选择一:市面上的XML lib还是有几个的,最有名的当然是libXML。

选择二:MS的MSXML,可以查看下MSDN文档。

选择三:使用开源类CMarkup,今天主要讲这个。

网上有Cmarkup的源代码,你可以下载后在里面include你的头文件,然后创建一个Cmarkup的对象,然后就可以调用里面的成员函数对你所希望操作的XML文件进行操作了。

下面是CMarkup的类成员函数使用方法。这些函数的设计都是基于源EDOM的。

创建一个XML文档

对于创建一个XML文档,需要实例化一个CMarkup对象,并调用AddElem创建根元素。.在这个位置,如果你调用AddElem(“ORDER”) ,你的文档会简单的装一个空ORDER元素. 然后调用AddChildElem 在根元素的下面创建元素 (例如:“进入”根元素内部,层次表示).下面的示例代码创建一个XML文档并返回它(的内容)到一个字符串中。

CMarkup xml;
xml.AddElem( "ORDER" );
xml.AddChildElem( "ITEM" );
xml.IntoElem();
xml.AddChildElem( "SN", "132487A-J" );
xml.AddChildElem( "NAME", "crank casing" );
xml.AddChildElem( "QTY", "1" );
CString csXML = xml.GetDoc();

这些代码产生了下面的XML,这个根结点是ORDER元素;注意它的开始标签 在开头,结束标签在结尾。当一个元素是在一个父下面(深入或被包含),这个父元素的开始标签要在它之前,结束标签要在它之后。ORDER元素包含一个ITEM元素,而ITEM元素包含了三个字子元素:SN、NAME和QTY;

132487A-J

crank casing

1

如例子中所显示的,你也能够在一个子元素下创建新元素,这需要调用IntoElem 移动你的当前主位置到当前子元素位置,然后你就可以在这下面增加一个子元素了。CMarkup在索引中保持了一个当前位置指针,以保证你的源码更加短和更简单,当导航文件时,相同的逻辑位置也会被使用。

导航XML文档

上面的例子所创建的XML字符串,用SetDoc方法加入到CMarkup对象中能够被解析,你也可以引导它正确的进入被创建的同一个CMarkup对象中,如果你要设置当前位置到文档的开始时,需要调用ResetPos.

在下面的例子中,从csXML字符串生成CMarkup对象后,我们循环ORDER元素下的所有ITEM元素,并得到每个项目的序号和数量。

CMarkup xml;
xml.SetDoc( csXML );
while ( xml.FindChildElem("ITEM") )
{
    xml.IntoElem();
    xml.FindChildElem( "SN" );
    CString csSN = xml.GetChildData();
    xml.FindChildElem( "QTY" );
    int nQty = atoi( xml.GetChildData() );
    xml.OutOfElem();
}

对于我们发现的每个元素,在查询它了子元素之前要调用IntoElem,查询完之后再调用OutOfElem ,当你习惯于这种导航类型时,你将知道,检查你的循环时,要确定每个IntoElem 调用都有一个与之对应的OutOfElem 调用 。

增加元素和属性

上面创建文档的例子中仅创建了一个ITEM元素,现在这个例子是创建多个项目,从前一个内容加裁后,再增加数据源,加上SHIPMENT信息元素中有一个属性,这段代码也演示了你能调用调用IntoElem和AddElem来代替AddChildElem,函数调用。虽然这意味着更多的调用,但许多人认为这样更直观。

CMarkup xml;
xml.AddElem( "ORDER" );
xml.IntoElem(); // inside ORDER
for ( int nItem=0; nItem
{
    xml.AddElem( "ITEM" );
    xml.IntoElem(); // inside ITEM
    xml.AddElem( "SN", aItems[nItem].csSN );
    xml.AddElem( "NAME", aItems[nItem].csName );
    xml.AddElem( "QTY", aItems[nItem].nQty );
    xml.OutOfElem(); // back out to ITEM level
}
xml.AddElem( "SHIPMENT" );
xml.IntoElem(); // inside SHIPMENT
xml.AddElem( "POC" );
xml.SetAttrib( "type", csPOCType );
xml.IntoElem(); // inside POC
xml.AddElem( "NAME", csPOCName );
xml.AddElem( "TEL", csPOCTel );

这段代码产生了下面的XML,根元素ORDER包含两个ITEM元素和一个SHIPMENT元素,ITEM元素全都包含SN、NAME、和QTY元素,SHIPMENT元素包含一个带有属性类型的POC元素,和NAME及TEL子元素。

132487A-J

crank casing

1

4238764-A

bearing

15

John Smith

555-1234

查找元素

FindElem 和 FindChildElem方法用于到下一个兄弟元素。如果可选的标签名被指定,那么它们将到下一个与标签名相匹配的元素,被发现的元素是当前元素,并且下次调用Find将会到当前位置后的下一个兄弟或下一个匹配兄弟。

当你无法判断元素的索引时,在调用两个Find方法之间,一定要复位当前位置。看上面的例子中ITEM元素,如果是别的人创建的XML文件,你不能确定SN元素在QTY元素之前,那么在查找QTY元素之前就要调用ResetChildPos();

对于用一个特定的序号去查找元素,你需要完全循环ITEM元素,并比较SN元素的数据和你正在搜索的序号。这个例子不同于先前导航的例子,它调用IntoElem 进入到ORDER元素,并且用FindElem(“ITEM”)替换FindChildElem(“ITEM”);其实两种方式都挺好。需要注意的是,在Find方法中指定ITEM元素的标签名,我们会忽略所有其它的兄弟元素,例如SHIPMENT元素。

CMarkup xml;
xml.SetDoc( csXML );
xml.FindElem(); // ORDER element is root
xml.IntoElem(); // inside ORDER
while ( xml.FindElem("ITEM") )
{
    xml.FindChildElem( "SN" );
    if ( xml.GetChildData() == csFindSN )
        break; // found
}

编码

ASCII编码引用了我们所依靠的字符码128以下的字符,如用英语编程。如果你只使用ASCII码,很方便,UTF-8编程与你拉公共ASCII集相同。

如果你所使用的字符集不在Unicode编码集(UTF-8,UTF-16,UCS-2)中,那么出于交互性以及在IE中很好的显示,你真的需要在XML声明中进行描述。像ISO-8859-1(西欧)字符集指定字符值在一个比特且在128到255之间。以便每个字符仍然使用一个比特。Windows双字节字符集像GB2312,Shift_JIS和EUC-KR,每个字符都是用一个或两个字节,对于这些Windows字符集,在你的预处理中需要定义_MBCS ,并要确定用户的操作系统设置到合适的编码页。

关于用一个XML描述的XML文档前缀,像,需要通过用SetDoc或Cmarkup的构造函数来传递。在结尾要包括回车符,这样根结点会显示在下一行。

xml.SetDoc( "/r/n" );
xml.AddElem( "island", "Curaçao" );

Tonitech版权所有 | 转载请注明出处: http://www.tonitech.com/?p=948

在网页中调用C++接口

    最近在公司做一个关于在网页中调用C++接口的项目,现在项目已经做完。在这期间花了一段时间去学了关于这方面的知识,和大家一起分享下。

    首先是在windows客户端中网页的生成,在这期间需要用到IWebBrowser2接口。早期, IWebBrowser2 继承自 IWebBrowser 和 IWebBrowserApp, 还提供不包含在着两个接口中的功能. 所以你应当使用 IWebBrowser2 接口替代 来操纵WebBrowser 控件或者 Internet Explorer.该块知识用到了windows的COM 技术,具体可查看MSDN。IWebBrowser2 接口有4个方法和8个属性,其中最终要的方法就是Navigate2,Navigate2的功能基于Navigate 方法,不同在于 Navigate2 允许你导航到飞URL表达的地方,例如Windows shell folder. (Windows shell folder 是指向标示符指针, 或者windows shell命名空间中的 PIDL,)。该方法最终的参数是第一个,本地HTML文件所在的位置。

   在调用方法后,你就可以看到你自己写的WEB页面了。下面的代码是我的测试页面:

<html>
<script>
function onBtn1(obj)
{
    var aaaa    = external.closeApp();
}
</script>
<body>
<input type="button" name="btn1" value="btn1" onClick="onBtn1(this)" />
</body>
</html>
WEB页面上只有一个Button,点下按钮调用C++里面的closeApp()函数。
那在客户端中CloseApp这个函数如何写?下面会有详细的说明:

1.首先在头文件中声明函数:

void_closeApp();

2.在CPP文件中写函数的具体实现。

3.对函数进行DISP_FUNCTION。代码如下:

DISP_FUNCTION(CHxBrowser, "closeWindow", _closeWindow, VT_NULL, VTS_NONE);

DISP_FUNCTION参数:

theClass 类的名字。

pszName 函数的外部名字。

pfnMember 成员函数的名字。

vtRetVal 指定了函数返回类型的值。

vtsParams 指定了函数参数表的一个或多个常量的用空格分隔的列表。

说明:

DISP_FUNCTION宏被在调度映射中使用,用来定义一个OLE自动化函数。

vtRetVal参数属于VARTYPE类型。这个参数的可能取值来自VARENUM枚举,如下:

符号 返回类型

VT_EMPTY void

VT_I2 short

VT_I4 long

VT_R4 float

VT_R8 double

VT_CY CY

VT_DATE DATE

VT_BSTR BSTR

VT_DISPATCH LPDISPATCH

VT_ERROR SCODE

VT_BOOL BOOL

VT_VARIANT VARIANT

VT_UNKNOWN LPUNKNOWN

 

vtsParams参数是VTS_ 常量中取值的用空格分隔的列表。有空格分隔的一个或多个取值的列表指定了函数的参数列表。例如:

VTS_I2 VTS_PI2

指定了包含一个短整数以及后面的短整数指针的列表。

VTS_ 常量及其含义如下:

符号 参数类型

VTS_I2 short

VTS_I4 long

VTS_R4 float

VTS_R8 double

VTS_CY Const CY or CY*

VTS_DATE DATE

VTS_BSTR LPCSTR

VTS_DISPATCH LPDISPATCH

VTS_SCODE SCODE

VTS_BOOL BOOL

VTS_VARIANT Const VARIANT* or VARIANT&

VTS_UNKNOWN LPUNKNOWN

VTS_PI2 short*

VTS_PI4 long*

VTS_PR4 float*

VTS_PR8 double*

VTS_PCY CY*

VTS_PDATE DATE*

VTS_PBSTR BSTR*

VTS_PDISPATCH LPDISPATCH*

VTS_PSCODE SCODE*

VTS_PBOOL BOOL*

VTS_PVARIANT VARIANT*

VTS_PUNKNOWN LPUNKNOWN*

OK,所有的步骤已经完成,你就可以在你自己写的网页上调用客户端里面的函数对客户端进行操作了!

C++的STL标准库使用的12条忠告

第1条:慎重选择容器类型。

标准STL序列容器:vector、string、deque和list。

标准STL关联容器:set、multiset、map和multimap。

非标准序列容器slist和rope。slist是一个单向链表,rope本质上是一“重型”string。

非标准的关联容器hash_set、hase_multiset、hash_map和hash_multimap。

vector 作为string的替代。(见第13条)

vector作为标准关联容器的替代。(见第23条)

几种标准的非STL容器,包括数组、bitset、valarray、stack、queue和priority_queue。

你是否关心容器中的元素是如何排序的?如果不关心,选择哈希容器.

容器中数据的布局是否需要和C兼容?如果需要兼容,就只能选择vector。(见第16条)

元素的查找速度是否是关键的考虑因素?如果是,就要考虑哈希容器、排序的vector和标准关联容器-或许这就是优先顺序。

对插入和删除操作,你需要事务语义吗?如果是,只能选择list。因为在标准容器中,只有list对多个元素的插入操作提供了事务语义。

deque是唯一的、迭代器可能会变为无效(插入操作仅在容器末尾发生时,deque的迭代器可能会变为无效)而指向数据的指针和引用依然有效的标准STL容器。

第2条:不要试图编写独立于容器类型的代码。

如果你想编写对大多数的容器都适用的代码,你只能使用它们的功能的交集。不同的容器是不同的,它们有非常明显的优缺点。它们并不是被设计用来交换使用的。

你无法编写独立于容器的代码,但是,它们(指客户代码)可能可以。

第3条:确保容器中的对象拷贝正确而高效。

copy in,copy out,是STL的工作方式,它总的设计思想是为了避免不必要的拷贝。使拷贝动作高效并且防止剥离问题发生的一个简单办法是使容器包含指针而不是对象。

第4条:调用empty而不是检查size()是否为0。

理由很简单:empty对所有的标准容器都是常数时间操作,而对一些list的实现,size耗费线性时间。

第5条:区间成员函数优先于与之对应的单元素成员函数。

区间成员函数写起来更容易,更能清楚地表达你的意图,而且它们表现出了更高的效率。

第6条:当心C++编译器最烦人的分析机制。

把形参加括号是合法的,把整个形参的声明(包括数据类型和形参名字)用括号括起来是非法的。

第7条:如果容器中包含了通过new操作创建的指针,切记在容器对象析构前将指针delete掉。

STL很智能,但没有智能到知道是否该删除自己所包含的指针所指向的对象的程度。为了避免资源泄漏,你必须在容器被析构前手工删除其中的每个指针,或使用引用计数形式的智能指针(比如Boost的sharedprt)代替指针。

第8条:切勿创建包含auto_ptr的容器对象。

拷贝一个auto_ptr意味着改变它的值。例如对一个包含auto_ptr的vector调用sort排序,结果是vector的几个元素被置为NULL而相应的元素被删除了。

第9条:慎重选择删除元素的方法。

要删除容器中指定值的所有对象:

如果容器是vector、string或deque,则使用erase-remove习惯用法。

SeqContainer c;

c.erase(remove(c.begin(),c.end(),1963),c.end());

如果容器是list,则使用list::remove。

如果容器是一个标准关联容器,则使用它的erase成员函数。

要删除容器中满足特定条件的所有对象:

如果容器是vector、string或deque,则使用erase-remove_if习惯用法。

如果容器是list,则使用list::remove_if。

如果容器是一个标准关联容器,则使用remove_copy_if和swap,或者写一个循环遍历容器的元素,记住当把迭代器传给erase时,要对它进行后缀递增。

AssocCOntainer c;

AssocContainer goodValues;

remove_copy_if(c.begin(), c.end(), inserter(goodValues, goodValues.end()),badValue);

c.swap(goodValues);

for(AssocContainer::iterator i = c.begin();i !=c.end();/* do nothing */){

if(badValue(*i)) c.erase(i++);

else ++i;

}

要在循环内部做某些(除了删除对象之外的)操作:

如果容器是一个标准序列容器,则写一个循环来遍历容器中的元素,记住每次掉用erase时,要用它的返回值更新迭代器。

如果容器是一个标准关联容器,则写一个循环来遍历容器中的元素,记住每次把迭代器传给erase时,要对迭代器做后缀递增。

第10条:了解分配子(allocator)的约定和限制。

第11条:理解自定义分配子的合理用法。

第12条:切勿对STL容器的线程安全性有不切实际的依赖。

对一个STL实现你最多只能期望:

多个线程读是安全的。

多个线程对不同的容器写入操作是安全的。

你不能期望STL库会把你从手工同步控制中解脱出来,而且你不能依赖于任何线程支持。

 

Tonitech版权所有 | 转载请注明出处: http://www.tonitech.com/?p=501

浅谈C++与PHP中的构造函数与析构函数

        第一次接触构造函数和析构函数,是学C++的时候,然而一年多没接触C++,似乎对于这两个“类中函数”,早已忘得差不多了。这几天在学PHP,又遇到了这两函数,由于对于构造函数和析构函数的了解不深,今天就好好研究了一下下。

      先说说在C++中的构造函数和析构函数。C++中提供了构造函数来处理对象的初始化,但是不能说构造函数的主要作用是用来对对象进行初始化。构造函数是一种特殊的成员函数,不需要用户调用,在建立对象时,构造函数就会自动执行。而且构造函数的名字必须与类名相同。注意,不能由用户任意命名。有时候也会在想,我们都是在什么时候调用构造函数的?其实,在类对象进入其作用域是就调用了构造函数。构造函数没有返回值,所以也不需要在定义构造函数时声明函数类型,这是构造函数和一般函数的一个不同之处。在定义构造函数的时候,可以带参数,也可以不带参数。但是呢,带参数的构造函数有一个很大的优点:采用带参数的构造函数,在调用不同对象的构造函数时,可以将不同的数据从外面传递给构造函数,以实现不同的初始化。不过这时候要注意几点。首先,我们已经知道用户是不能调用构造函数的,所以不能像常规的调用函数的方法来对构造函数给出实参。在C++中,构造函数的实参是在定义对象时给出的。

        不过这时候我们也会在想,如果用户没有定义构造函数,那会有构造函数么?其实,如果用户没有自己定义构造函数,则C++系统会自动生成一个构造函数。在了解构造函数的时候,我们还得知道一个名词:重载。构造函数的重载,通俗来说就是定义很多个不同的构造函数,但是,函数名必须相同,其中不相同的是,构造函数的参数的个数和参数的类型不同。还需明白的一点是:构造函数的参数的值既可以通过实参传递,也可指定为某些默认值。不过,一般不应同时使用构造函数的重载还有默认参数的构造函数。

        析构函数是什么?我们可以这样理解,析构函数是与构造函数作用相反的函数。从析构函数的名字也可以看出。数学中,数A的相反数是-A。所以可以映射到C++中,构造函数A的作用相反的函数就是析构函数~A。注意,不是-A!就像我们不能说构造函数的主要作用是用来对对象进行初始化一样,析构函数的作用并不是删除对象,而是在撤销对象占用的内存之前完成一些清理工作。同构造函数一样,析构函数没有返回值,没有函数类型。不过析构函数也没有函数参数。可以说析构函数是“三无函数”。因为没有函数参数,所以析构函数不能被重载。因此只有一个析构函数!要切记。在使用构造函数和析构函数时,其顺序可以简单记为:先构造的后析构,后构造的先析构。就好比栈操作,先进后出。

        简单了解完C++中的构造函数和析构函数后,现在来说说PHP中的构造函数与析构函数。在PHP4中,构造函数是类中的一个特殊函数,构造函数与类同名。当使用 new 操作符创建一个类的实例时,构造函数将会自动调用。如果一个类没有构造函数,则调用基类的构造函数,前提是基类有构造函数。然而,在PHP5引入了一个声明构建函数的标准方法: __construct()。这里需要提醒的是:construct()函数前的下划线“_”是两个!!!如果少写一个“_”,结果就错了。见Example1

 Example1:

 Code:

<?php 

	/*类的实例4:实现Iterator接口的迭代  */
		class MyIterator implements Iterator
		{
			private $var = array();
			public function _constuct($array)
			{
				if(is_array($array))
				{
					$this-&gt;var = $array;
				}
			}

			public function rewind()
			{
				echo "rewinding\n";
				reset($this-&gt;var);
			}

			public function current()
			{
				$var = current($this-&gt;var);
				echo "current:$var\n";
				return $var;
			}

			public function key()
			{
				$var = key($this-&gt;var);
				echo "key:$var\n";
				return $var;
			}

			public function next()
			{
				$var = next($this-&gt;var);
				echo "next:$var\n";
				return $var;
			}

			public function valid()
			{
				$var = $this-&gt;current() !== false;
				echo "valid:{$var}\n";
				return $var;
			}
		}

		$values = array(1,2,3);
		$it = new MyIterator($values);

		foreach ($it as $a =&gt; $b)
		{
			print "$a:$b\n";
		}

输出结果: 

 

 

Example2:

Code:

<?php 
	/*类的实例4:实现Iterator接口的迭代  */
		class MyIterator implements Iterator
		{
			private $var = array();
			public function __constuct($array)
			{
				if(is_array($array))
				{
					$this-&gt;var = $array;
				}
			}

			public function rewind()
			{
				echo "rewinding\n";
				reset($this-&gt;var);
			}

			public function current()
			{
				$var = current($this-&gt;var);
				echo "current:$var\n";
				return $var;
			}

			public function key()
			{
				$var = key($this-&gt;var);
				echo "key:$var\n";
				return $var;
			}

			public function next()
			{
				$var = next($this-&gt;var);
				echo "next:$var\n";
				return $var;
			}

			public function valid()
			{
				$var = $this-&gt;current() !== false;
				echo "valid:{$var}\n";
				return $var;
			}
		}

		$values = array(1,2,3);
		$it = new MyIterator($values);

		foreach ($it as $a =&gt; $b)
		{
			print "$a:$b\n";
		}

输出结果:

 

但是,如果没有定义构造函数__construct()怎么办?此时,系统会自动查找是否有与类同名的函数,如果有,此时,构造函数将会变成与类同名的函数。如Example2。

如果同时存在__construct()函数和与类同名的函数,如example3,此时,两个函数是一样的,只执行一个函数。

Example3:

Code: 

<?php 

	/*类的实例4:实现Iterator接口的迭代  */
		class MyIterator implements Iterator
		{
			private $var = array();
			public function __construct($array)
			{
				if(is_array($array))
				{
					$this-&gt;var = $array;
				}
			}

			public function MyIterator($array)
			{
				if(is_array($array))
				{
					$this-&gt;var = $array;
				}
			} 

			public function rewind()
			{
				echo "rewinding\n";
				reset($this-&gt;var);
			}

			public function current()
			{
				$var = current($this-&gt;var);
				echo "current:$var\n";
				return $var;
			}

			public function key()
			{
				$var = key($this-&gt;var);
				echo "key:$var\n";
				return $var;
			}

			public function next()
			{
				$var = next($this-&gt;var);
				echo "next:$var\n";
				return $var;
			}

			public function valid()
			{
				$var = $this-&gt;current() !== false;
				echo "valid:{$var}\n";
				return $var;
			}
		}

		$values = array(1,2,3);
		$it = new MyIterator($values);

		foreach ($it as $a =&gt; $b)
		{
			print "$a:$b\n";
		}

输出结果:

        对于析构函数,在PHP4中,析构函数是不存在的。但是,PHP5中有析构函数。其他的与C++中的一样。记得析构函数是没有参数的。

C#中textBox中文本的换行方法

今天编了一个C#的窗口程序,想使用TextBox输出一系列的数据,可是,我在string变量后面+”\n”都无济于事。后来,我发现TextBox中的换行符是”\r\n”。

Tonitech版权所有 | 转载请注明出处: http://www.tonitech.com/?p=398