office 文档解析

来源:互联网 发布:泗阳网络问政123456 编辑:程序博客网 时间:2024/06/05 04:57

最近在项目维护过程中涉及到了office各种文档的解析,捣鼓了好长时间,有点点收货,记下来。

涉及文档:doc、docx、xls、xlsx、pptx。

语言:VC

 

下面对不同的文档进行简单解析:

一、word文档

1、首先想到的方法就是ado,网上一找一大片,下面给几个连接:http://www.docin.com/p-355819700.html ,,,http://huguangchaoren.blog.163.com/blog/static/888341502010922924154/ ,,,,http://blog.csdn.net/dancewyr/article/details/7674558,操作很简单,如果自己安装了office,在vs中找到项目下的类向导,添加“类型库中的mfc类”,在office目录下找到msword.olb,导入。下面简单写下自己的测试代码:

#include "CApplication.h"
#include "CDocuments.h"
#include "CDocument0.h"
#include "CRange.h"

void CdocxtestDlg::OnBnClickedButton1()
{
 // TODO: 在此添加控件通知处理程序代码
 CString strFileName;
 WCHAR chPath[MAX_PATH] = {0};
 GetModuleFileName(NULL, chPath, MAX_PATH);
 WCHAR * ptrPath = wcsstr(chPath,L"demo.exe");
 *ptrPath = '\0';
 strFileName.Format(L"%s\\111.doc",chPath);
 CApplication app;
 app.CreateDispatch(L"Word.Application");
 OutputDebugStringA("CreateDispatch ok");
 app.put_Visible(false);
 OutputDebugStringA("put_Visible ok");
 app.put_DisplayAlerts(false);
 OutputDebugStringA("put_DisplayAlerts ok");
 CDocuments docs = app.get_Documents();
 COleVariant vTrue((short)TRUE),vFalse((short)FALSE),vOpt((long)DISP_E_PARAMNOTFOUND,VT_ERROR);
 CDocument0 doc = docs.Open(COleVariant(strFileName),vFalse,vTrue,vFalse,vOpt,vOpt,vOpt,vOpt,vOpt,vOpt,vOpt,vOpt,vOpt,vOpt,vOpt,vOpt);
 OutputDebugStringA("Open ok");
 CRange range = doc.Range(vOpt,vOpt);
 CString strs = range.get_Text();
 OutputDebugStringW(strs);
 range.ReleaseDispatch();
 doc.ReleaseDispatch();
 docs.ReleaseDispatch();
 VARIANT SaveChanges,OriginalFormat,RouteDocument;
 SaveChanges.vt = VT_BOOL;
 SaveChanges.boolVal= VARIANT_FALSE;
 ::VariantInit(&OriginalFormat);
 RouteDocument.vt = VT_EMPTY;
 app.Quit(&SaveChanges,&OriginalFormat,&RouteDocument);
 app.ReleaseDispatch();
}

以上程序可以简单的读取doc和docx类型的文档,即:ado方式可以读取doc和docx格式的word文档,但是缺陷也是有的,这种方法对office组件(库文件)依赖性很高,所以在没有安装office的操作系统中,此方法运行到app.CreateDispatch(L"Word.Application");会失败,若个人理解有误,请大牛指点,在此感谢。

 

 

 

2、在网上找到了一个word数据解析库tractText.dll,支持word数据的读取,下面给一个连接:http://www.pdfhome.com.cn/Article.aspx?CID=bf51a5b6-78a5-4fa3-9310-16e04aee8c78&AID=621ca553-48ee-43ee-b248-3d63787963cc ,代码在连接里面有详细描述,但是也是有缺陷,首先要注册tractText.dll组件,其次,这个dll不支持docx数据的读取,我自己的demo读取出来的是空,如果哪位大牛用这个dll读取到了docx文档数据,请告诉小弟一下,在此感谢。

 

 

3、对于doc文档的读取,我选择了tractText.dll,对于docx文档的读取,我选择了文档结构解析,下面给一个连接:http://www.codeproject.com/Articles/20529/Using-DocxToText-to-Extract-Text-from-DOCX-Files  ,上面给了一个docx文档解析的一个新思路,docx可以理解为zip压缩文件,在压缩文件中有很多xml类型文件记录着docx文档的格式和数据,那我们要做的就是找到记录着docx文档数据的xml文件进行读取就可以了。。。下面看一张图片 ,我们把docx文档后缀变成.zip,双击打开,这就是里面的东东,

 

其中,[content_types].xml中记载着所有xml文档的路径及作用,下面我们来看看这个文档的内容:

其中,document.xml文档就是我们要找的文档,这个文档中记载着docx文档中的所有数据,但是,为啥不能直接在word路径下找呢?office软件在生成docx的时候会把document.xml放到word目录下,但是其他可以生成docx文档的软件不一定会把document.xml放到这个目录,所以要先找[content_types].xml,在[content_types].xml中把document.xml的位置读出来,然后再去找document.xml。

document.xml是有自己的xml格式的,若不懂xml格式,可以去网上简单的学学,下面给一个连接:http://wenku.baidu.com/view/efd94ddfce2f0066f53322e7.html ,,如果我们需求苛刻,可以根据不同节点的属性解析各种docx数据,包括文字,数字,回车换行,空格,图片,表格等等……我这里只需要字符串,所以解析的时候只获取<w:t>数据</w:t>

中的数据即可,下面贴下来document.xml格式:

在用这种方式读取docx文档的时候要用到压缩文件解析类和xml文档解析类,这个过程中注意:xml文档是utf-8编码、document.xml中不同节点有不同意义、最好使用支持xpath()函数的xml解析类,这样就不用逐个遍历<w:t>了。

我自己使用的压缩文件解析类为unzip,下面给一个连接:http://www.codeproject.com/Articles/7530/Zip-Utils-clean-elegant-simple-C-Win32 ,,在操作的过程中遇到了一个问题,用Unzip解压文件到内存时中文为乱码,我只能将其解压到指定目录再读取,这样效率可想而知,我估计是编码问题,暂时解决不了,哪位大牛如果有好的解决办法,请指点一下,在此感谢。

我自己使用的xml解析类为pugixml库,下面给一个连接:http://blog.csdn.net/yukin_xue/article/details/7540011 ,,http://blog.csdn.net/jdzfjfhnui/article/details/6672532  ,,以前用的CMakeUp类,但是没有xpath接口,处理麻烦。

 

二、excel

1、还是ado方法,代码思路与解析word文档一样,但是缺陷也一样。

 

2、odbc方法,这种方法比ado方法更基础一些,其不再利用office组件,但是依赖office相关驱动,这个驱动似乎操作系统都提前预安装了,下面给一个连接:http://wenku.baidu.com/view/fb6ae796daef5ef7ba0d3c9b.html  ,其大致思路是,先判断相关驱动是否存在,然后构造查询函数,然后执行就可以了,但是缺陷是无法读取excel第一行数据,我发现,执行函数有相关判断是否查询第一行数据的参数,在运行查询函数时,函数调用底层驱动,底层驱动忽略了这个变量,仍然没有查询第一行。。。

 

3、BasicExcel,BasicExcel是一个第三方开源库,提供了xls文档解析功能,还是给一个连接:http://www.codeproject.com/Articles/13852/BasicExcel-A-Class-to-Read-and-Write-to-Microsoft ,但是据网上说这个库还不支持xlsx文档的解析,不知是否属实,如果哪位大牛知道,请指点一下,谢谢。

 

4、libxl.dll,第三方库,提供了xls和xlsx文档的解析,可以读取所有行,下面给一个连接:http://blog.csdn.net/lbd2008/article/details/8332345  ,下面附上部分个人代码:

 

#include "libxl.h"

using namespace  libxl;

bool ReadXLSXData(wchar_t *ch)
{
 bool bResult = true;

//Book* book = xlCreateBook();//Excel xls版本

 Book* book = xlCreateXMLBook();//excel 07版本以上的文档
 if(book->load(ch))//加载
 { 
  int iSheetCount = book->sheetCount();//获取页数
  for (int i=0; i<iSheetCount; i++)//逐个遍历页数
  {
   Sheet * sheet = book->getSheet(i); 
   if(sheet)
   { 

    for (int row=sheet->firstRow(); row<sheet->lastRow(); row++)//逐行读取数据
    {
     for (int col=sheet->firstCol(); col<sheet->lastCol(); col++)//具体到某行的某列
     {
      CellType cellType = sheet->cellType(row, col);
      std::wcout << "(" << row << ", " << col << ") = ";
      if(sheet->isFormula(row, col))//判断单元格是否为公式
      {
       //如果是公式,读取并输出
       const wchar_t* s = sheet->readFormula(row, col);
       std::wcout << (s ? s : L"null") << " [formula]";
      }
      else
      {
       //如果不是公式,获取数据格式并输出
       switch(cellType)
       {
       case CELLTYPE_EMPTY://空
        {
         std::wcout << "[empty]";
         break;
        }
       case CELLTYPE_NUMBER://整数
        {
         double d = sheet->readNum(row, col);
         std::wcout << d << " [number]";
         break;
        }
       case CELLTYPE_STRING://字符串
        {
         const wchar_t* s = sheet->readStr(row, col);

         cout << s<< " [string]";
         break;       
        }
       case CELLTYPE_BOOLEAN://真假
        {
         bool b = sheet->readBool(row, col);
         std::wcout << (b ? "true" : "false") << " [boolean]";
         break;
        }
       case CELLTYPE_BLANK:
        {
         std::wcout << "[blank]";
         break;
        }
       case CELLTYPE_ERROR:
        {
         std::wcout << "[error]";
         bResult = false;
         break;
        }
       default:
        {
         break;
        }
       }
      }
      std::wcout << std::endl;
     }
    }
   } 
   else
   {
    bResult = false;
   }
  }
 } 
 else
 {
  std::wcout << "load file error";
  bResult = false;
 }

 book->release();
 return bResult;
}

 

 

三、ppt文档

1、pptx文档的解析思路与docx文档解析思路类似,不过,pptx中把每个页ppt都放到了不同的slides里。

2、由于没有解析ppt文档需求,我暂时没有尝试,不过网上也是很多,这里不说了。

 

以上都是个人测试后的总结,由于技术能力原因,部分内容可能有出入,如有出入请指点,仅供总结和参考。