如何利用Xerces C++解析包含中文字符的XML文档

Xerces-C++是目前广泛使用的XML解析器,在利用它编写XML应用以处理包含中文字符的XML文档时会出现字符编码错误,如何正确解决这个问题,对于我们开发XML的应用程序非常有用。本文给出了正确处理的方法和实现类的代码,希望能对大家有所帮助。

1.背景介绍
随着XML技术的普及应用,我国的各行各业有可能会生成大量的包含中文字符的XML文档。尽管基于Java技术的XML Parser能较好处理这些XML文档,但是,它不能解决所有的问题,原因是应用开发的复杂性,尤其在我国更为明显.我们知道,企业的许多应用系统的开发采用了C、C++、VB、Delphi、FoxPro等等语言,这些应用不可能用Java语言重新实现,那么,问题就出现了,如何让这些应用也能处理 XML文档,甚至是包含中文字符的XML文档呢?

目前有关XML Parser C++语言的实现,非常著名的有Apache组织的Xerces和IBM的XML4C。Aparche的Xerces来源于IBM的XML4C,所以,它们的编程接口是一致的。二者关键的不同在于字符编码。Apache的Xerces1.6目前只支持少数的字符编码,如ASCII, UTF-8, UTF-16, UCS4, EBCDIC IBM037 和 IBM1140, ISO-8859-1 和Windows-1252。因而,采用Apache的Xerces C++解析器不能处理包含中文字符的XML文档。IBM的XML4C支持多达100种字符编码,它将Xerces和International Components for Unicode (ICU)结合了起来。因而,我们可以选用XML4C作为XML的解析器。在使用XML4C之前,我们需要首先确认XML4C的bin目录是否包含在系统的Path之中,bin目录必须要有这些dll:xerces-c_1_6_0D.dll,icudt20.dll,icuuc20.dll,icuuc20d.dll

2. 问题描述
在XML4C应用过程中,我发现调用XML4C提供的一些API并不能很好解决中文问题。如解析XML时生成DOM_Document, 并利用DOM方法得到某一DOM_Node节点时,为了获得DOM_Node的名字或值,需要调用DOM_Node类的getNodeName()或 getNodeValue()方法,并得到DOMString对象。根据API文档描述,DOMString类的transcode()方法,返回字符串的拷贝,并依照本地代码页对此字符串进行编码处理。因而,我在解析图1的XML文档并试图获得"爱国的人们"节点的名字时,transcode方法返回不完整的节点名"爱国",而不是完整的"爱国的人们",这样,我们就无法利用这些信息来进行字符串比较等等操作,XML的处理就会出现问题。因而, DOMString的transcode方法并不能处理XML的中文字符。

<?xml version='1.0' encoding='GB2312' ?>… …        <爱国的人们>		… …</爱国的人们>    …  …
图 1

3.解决的方法
针对这种情况,我仔细分析了XML4C提供的DOMPrint例子,此例子能顺利解析含中文字符的XML文档,并能打印出XML解析后生成的DOM_Document。它利用了Xerces的XMLFormatter和XMLFormatTarget类:

  • XMLFormatter类,提供基本的格式化字符串功能,将解析器生成的基于Unicode的XML数据转换为非Unicode环境中使用的数据,如本地字符编码等;
  • XMLFormatTarget类,为XMLFormatter格式化字符串提供目的地,它需要派生,并利用它的writeChars()方法得到格式化后的字符串。

 

基于以上分析,我改进了DOMPrint的例子程序,实现了一个XMLFormatTarget类的子类,代码如下:

 //类定义
#include <framework/XMLFormatter.hpp>
class StrFormatTarget : public XMLFormatTarget
{
public:
 char * GetResult();
    StrFormatTarget()  {};
    ~StrFormatTarget () {};
    void writeChars(const   XMLByte* const  toWrite,
                    const   unsigned int    count,
                     XMLFormatter * const formatter);
private:
    char * buffer;
    StrFormatTarget (const StrFormatTarget & other);
    void operator=(const StrFormatTarget & rhs);
};
//类的实现
void StrFormatTarget::writeChars(const   XMLByte* const  toWrite,
                    const   unsigned int    count,
                    XMLFormatter * const formatter)
{
 buffer = (char *)malloc(count + 1);
 memset(buffer,0,count+1);
 memcpy(buffer, (char *) toWrite, count);
};
char * StrFormatTarget::GetResult()
{
 char * ret = (char *)malloc(strlen(buffer) +1);
 strcpy(ret, buffer);
 ret[strlen(buffer)] = 0;
 free(buffer);
 return ret;
}

XML文档的编码定义由文档头<?xml version='1.0' encoding='…' ?>给出,支持中文字符编码,我们选用'GB2312'。Encoding信息的获取可以有两种方式,第一,可以直接分析xml字符串,得到 encoding的值;第二,利用DOMParser解析XML文档时,设定parser能创建XMLDeclType节点,即:

DOMParser parser;
......
parser.setToCreateXMLDeclTypeNode(true).

在利用XML4C编程时,我们常遇见的类型是DOMString,XMLCh *,我们需要将这些类型的数据都转换为char *,然后,进行字符串的各种处理。我这里给出了一个类StrTransformer,专门解决有关字符编码的问题,它不仅仅支持中文字符编码,而且,可支持XML4C的其它字符编码。核心代码如下:

// header file
class StrTransformer 
{
public:
 char * ChangeStr(const DOMString& s);
        char * ChangeStr(const XMLCh * str);
 StrTransformer (char * encoding);
 XMLFormatter * format;
 StrFormatTarget * target;
 ~StrTransformer();
 DOMString * m_dom;
};
// implement file
#include "StrTransformer.h"
#include <stdlib.h>
#include <util/XMLString.hpp>
// Construction/Destruction
StrTransformer::StrTransformer(char * encoding)
{
    target = new StrFormatTarget();
    m_dom = new DOMString(encoding);
    format = new XMLFormatter(m_dom->rawBuffer(), target,
    XMLFormatter::NoEscapes, XMLFormatter::UnRep_CharRef);
}
StrTransformer::~StrTransformer()
{
    delete target;
    delete m_dom;
    delete format;
}
char * StrTransformer::ChangeStr(const DOMString &s)
{
     unsigned int lent = s.length();
     if (lent <= 0)
  return NULL;
    XMLCh*  buf = new XMLCh[lent + 1];
    XMLString::copyNString(buf, s.rawBuffer(), lent);
    buf[lent] = 0;
    *format<< buf;
    delete [] buf;
 return target->GetResult();
}
char * StrTransformer::ChangeStr(const XMLCh * str)

    DOMString dom(str);
    return ChangeStr(dom);

4 结束语
正确处理含有中文字符的XML文档,对于我们开发XML的应用程序非常有用,希望我的方法能为你提供帮助,如果有其它建议或疑问,欢迎与我联系(f_jian@sina.com)。

5 参考资料

 

 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值