IEP项目对Word文件的操作分析
2011-06-22 20:37
309 查看
在NPDS中,需要对word进行操作,由于在网上查的资料都不怎么有用,所以,我决定今天好好分析下孙伟以前在IEP项目中的操作办法,希望能得到一些启示,以下是我对孙伟的代码的分析:
项目结构如下:
如到导出功能的就主要是划红线的四个部分,下面我们来分别看下里面的内容,首先从IEP.Exportword的内容
展开项目后发现里面只有一个文件,找开该文件,首先看到的是USING处,多了几个不常见的东西
通过在网上查询发现,aspose是一个收费的第三方插件,我估计现在我们用的可能是破解版,因为在网上有破解版提供下载。aspose是一个专业插件开发公司提供的用于制图,写电子邮件,拼写检查,创建条形码,生成各种文档等的组件。Aspose.Words是一款先进的类库,使您可以直接在各个应用程序中执行各种文档处理任务。Aspose.Words支持DOC,OOXML,RTF,HTML,OpenDocument, PDF, XPS, EPUB和其他格式。使用Aspose.Words,您可以生成,更改,转换,渲染和打印文档而不使用Microsoft Word。
接下来是定义了三个私有字段
//用于取得模板文件的存放路径
private static string tmpPath = HttpContext.Current.Server.MapPath("~/" + System.Configuration.ConfigurationManager.AppSettings["WordTmp"]);
//用于取得XML文件的存放路径
private static string xmlPath = HttpContext.Current.Server.MapPath("~/" + System.Configuration.ConfigurationManager.AppSettings["WordData"]);
//取得导出文件的文件名称
private static string outName =HttpContext.Current.Server.UrlDecode(System.Configuration.ConfigurationManager.AppSettings["WordName"]);
tmpPath对应的文件版段如下:
其中黄色部分就是需要替换的地方,还有个XMLPATH是用来做什么 的呢?让我们来看看片断或许就明白了。
我们看到,这个xml的格式如上图,每个words节点下都有,k、t、v、m四个子节点,其中k代表我们需要替换的内容,比较红框中的#*1-9月*#,就代表,凡是在word中出在#*1-9月*#的地方,我们都需要用
<m>GetValue</m>中的方法来替换,那这个方法又从哪里来呢? <v>IMonthly</v> 没错,从IMonthly对应的接口来。这个接口的定义就在项目IEP.Iexport中,如下图:
看到红色框的部分了吧,在这个文件中只有一个接口的定义
public interface IMonthly {
string GetValue();
}
这个接口又在什么地方被实现呢?没错就是IEP.ExportData项目中如下
文件中的类实现了对于接口的定义
public class Monthly : IMonthly {
public string GetValue() {
string ret = string.Empty;
//实现
//ret = "1-9月";
ret = OutCondition.GetReportCondition("GenerateMonth", "StartMonth") + "-" + OutCondition.GetReportCondition("GenerateMonth", "EndMonth") + "月";
return ret;
}
}
好,搞清了数据的具体来源,我们再回过头来看IEP.ExportWord中的代码。第一个方法是导出word报表函数的OutWords()方法,具体代码如下
/// <summary>
/// 导出Word报表函数
/// </summary>
public static void OutWords() {
//bool ret = false;
Document doc = new Document(tmpPath);//说明:这里的Document对象就是aspose插件提供的
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(xmlPath);//说明:这里是把xml中的内容加载到XmlDocument 对象中去
XmlNodeList nodeList = xmlDoc.SelectSingleNode("IEP").ChildNodes;//说明:取得xml文件中的所有Words节点集合然后通过遍历就能知道每个需要替换的文字片断,以及这个地方需要从那个接口提供的什么方法来取得值,同时,这个值是什么类型。
foreach (XmlNode xn in nodeList)//遍历所有Words子节点
{
XmlNodeList nod = xn.ChildNodes;
string k = nod[0].InnerText;//说明:需要替换的关键字
string t = nod[1].InnerText;//说明:替换类型,1是word文字,2是table,3是图片
string v = nod[2].InnerText;//说明:从那个接口获取数据
string m = nod[3].InnerText;//说明:需要调用接口中的那个方法
v = IEP.ExportFactory.FactoryBuild.GetValues(v, m);
/*---------------------------------以下为说明-----------------------------
上面一句代码的作用是获取具体的值,可以看到这个地方使用了IEP.ExportFactory.FactoryBuild.GetValues(v, m)其实,IEP.ExportFactory.FactoryBuild是一个工厂类,根据传入的接口和方法生成来调用IEP.ExportData中的具体方法,以得到返回值。代码如下
//下面这句代码是创建一个IMonthly 接口的实例,创建具体内容在IEP.ExportFactory.ExpFactory中创建的具体方法如下
private static readonly IEP.IExport.IMonthly monthly = IEP.ExportFactory.ExpFactory.CreateMonthLy();
/// <summary>
/// 反射调用方法,取得返回值string
/// </summary>
/// <param name="title">实例Type</param>
/// <param name="methodName">方法名称</param>
/// <returns></returns>
private static string GetMethodRetValue(Type title, string methodName)
{
string ret = string.Empty;
try
{
if (!String.IsNullOrEmpty(methodName))
{
MethodInfo method = title.GetMethod(methodName);//说明:methodinfo是发现方法并提供对方法的访问,这里的title实现上是一个具体的类,通过GetMthod方法,可以找到指定的方法
if (method != null)
{
//说明:下面这句的意思是能过Activator.CreateInstance(title) 创建当前titel的具体对象,然后用method.Invoke的方法来调用这个对象的methodname方法。返回的结果是一个object对象
object retK = method.Invoke(Activator.CreateInstance(title), null);
if (retK != null)
ret = (string)retK;
}
}
}
catch (Exception)
{
//IEP
}
return ret;
}
/// <summary>
/// 获取对应的工厂实体
/// </summary>
/// <param name="key">接口名称</param>
/// <returns>具体实体</returns>
public static string GetValues(string key, string methodName)
{
string ret = string.Empty;
switch (key)
{
case "IMonthly"://说明:通过传入的key找到接口,并调用GetMethodRetValue方法返回具体内容
ret = GetMethodRetValue(monthly.GetType(), methodName);
break;
case "IPicOne":
ret = GetMethodRetValue(picone.GetType(), methodName);
break;
default:
ret = "";
break;
}
return ret;
}
---------------------------------------------------------------------------*/
try {
switch (t) {
case "1"://说明:以下是调用对文字的替换,传入三个参数,此时的V为最终的返回结果。具体代码如后所示
RepWords(doc, k, v);
break;
case "2"://说明:以下是调用对table的替换,传入三个参数,此时的V为最终的返回结果。具体代码如后所示
RepTable(doc, k, v);
break;
case "3"://说明:以下是调用对图片的替换,传入三个参数,此时的V为最终的返回结果。具体代码如后所示
k = k.Replace("#*", "");
k = k.Replace("*#", "");
RepIamges(doc, k, v);
break;
}
}
catch (System.Exception ex) {
throw ex;
}
}
//return ret;
doc.Save(outName, SaveFormat.Doc, SaveType.OpenInWord, HttpContext.Current.Response);
//说明:doc.save(保存的文件名,保存格式,保存类型,当前请求)
//保存为doc,并打开
}
/// <summary>
/// 替换Word文档文字
/// </summary>
/// <param name="doc">当前上下文doc文档</param>
/// <param name="key">文档中定义的标记(如:#*2010*#)</param>
/// <param name="val">替换值</param>
private static void RepWords(Document doc, string key, string val) {
//bool ret = false;
try {
doc.Range.Replace(key, val, false, false);//说明:aspose提供的方法具体解释如下图
}
catch (System.Exception ex) {
throw ex;
}
//return ret;
}
/// <summary>
/// 替换word文档表格内容
/// </summary>
/// <param name="doc">当前上下文word对象</param>
/// <param name="key">当前定义表的前缀(如:#*TB1_L1_1*#只在xml原始数据中定义TB1)</param>
/// <param name="val">表格数据值(キ隔离每行,ぐ隔离每行中的每列数据)</param>
private static void RepTable(Document doc, string key, string val) {
//bool ret = false;
try {
//doc.Range.Replace(key, val, false, false);
string curKey = string.Empty;
string[] lineData = val.Split('キ');
int lines = lineData.Length;
//string colData = string.Empty;
for (int l = 0; l < lines; l++) {
string[] colData = lineData[l].Split('ぐ');
for (int c = 0; c < colData.Length; c++) {
curKey = key + "_L" + (l + 1) + "_" + (c + 1);
doc.Range.Replace(curKey, colData[c], false, false);
}
}
}
catch (System.Exception ex) {
throw ex;
}
//return ret;
}
/// <summary>
/// 替换Word文档内图片
/// </summary>
/// <param name="doc">当前上下文文档</param>
/// <param name="key">文档中定义的书签(Word书签名)位置</param>
/// <param name="val">图片相对站点根路径|在word中显示的长度|在word中显示的宽度</param>
private static void RepIamges(Document doc, string key, string val) {
//bool ret = false;
DocumentBuilder builder = new DocumentBuilder(doc);
try {
string[] p = val.Split('キ');
string imgPath = HttpContext.Current.Server.MapPath("~/" + p[0]);
if (!System.IO.File.Exists(imgPath))
{
return;
}
System.Drawing.Image image = System.Drawing.Image.FromFile(imgPath);
if (builder.MoveToBookmark(key)) {
if (imgPath.ToLower().IndexOf("rpttempimg") > -1)
{
builder.InsertImage(image, double.Parse(p[1]), double.Parse(p[2]));
}
else
{
int width = 460;
int height = Convert.ToInt32((Convert.ToDouble(image.Height) / image.Width) * width);
builder.InsertImage(image, width, height);
}
builder.Writeln();
}
}
catch (System.Exception ex) {
throw ex;
}
//return ret;
}
通过以上代码,我们了解到,所有操作都是以aspose为核心,那么这个东西是否也能满足我合并多个word文件的需求呢? 于是我再通过互联网进行查询发现,document这个对象有个apppnedDocument方法。于是我准备建一个测试项目。
引入了aspose.words然后增加一个OpreateWord.aspx页面。前台不写任何代码,后台代码如下
相信都看的明白,只是需要说明下
doc2.AppendDocument(DOC,ImportFormatMode.KeepSourceFormatting);
P它的详细定义如下:
可以看到这个方法要求输入两个参数,一个是需要追加的文档,另一个是IMportFormatMode接口的实现,我们可以使用枚举ImportFormatMode来选择
第一个选择是指保持原格式,第二个是指使用目标样式。也就是说我们把文档doc加入到doc2的时候是保留原格式还是使用目标格式。
看看运行结果如何?
哇,结果出来了,还不错,基本是把两个文件完整合并到一起了。
关于aspose的使用,以后再继续讲,尽请关注。
项目结构如下:
如到导出功能的就主要是划红线的四个部分,下面我们来分别看下里面的内容,首先从IEP.Exportword的内容
展开项目后发现里面只有一个文件,找开该文件,首先看到的是USING处,多了几个不常见的东西
通过在网上查询发现,aspose是一个收费的第三方插件,我估计现在我们用的可能是破解版,因为在网上有破解版提供下载。aspose是一个专业插件开发公司提供的用于制图,写电子邮件,拼写检查,创建条形码,生成各种文档等的组件。Aspose.Words是一款先进的类库,使您可以直接在各个应用程序中执行各种文档处理任务。Aspose.Words支持DOC,OOXML,RTF,HTML,OpenDocument, PDF, XPS, EPUB和其他格式。使用Aspose.Words,您可以生成,更改,转换,渲染和打印文档而不使用Microsoft Word。
接下来是定义了三个私有字段
//用于取得模板文件的存放路径
private static string tmpPath = HttpContext.Current.Server.MapPath("~/" + System.Configuration.ConfigurationManager.AppSettings["WordTmp"]);
//用于取得XML文件的存放路径
private static string xmlPath = HttpContext.Current.Server.MapPath("~/" + System.Configuration.ConfigurationManager.AppSettings["WordData"]);
//取得导出文件的文件名称
private static string outName =HttpContext.Current.Server.UrlDecode(System.Configuration.ConfigurationManager.AppSettings["WordName"]);
tmpPath对应的文件版段如下:
其中黄色部分就是需要替换的地方,还有个XMLPATH是用来做什么 的呢?让我们来看看片断或许就明白了。
我们看到,这个xml的格式如上图,每个words节点下都有,k、t、v、m四个子节点,其中k代表我们需要替换的内容,比较红框中的#*1-9月*#,就代表,凡是在word中出在#*1-9月*#的地方,我们都需要用
<m>GetValue</m>中的方法来替换,那这个方法又从哪里来呢? <v>IMonthly</v> 没错,从IMonthly对应的接口来。这个接口的定义就在项目IEP.Iexport中,如下图:
看到红色框的部分了吧,在这个文件中只有一个接口的定义
public interface IMonthly {
string GetValue();
}
这个接口又在什么地方被实现呢?没错就是IEP.ExportData项目中如下
文件中的类实现了对于接口的定义
public class Monthly : IMonthly {
public string GetValue() {
string ret = string.Empty;
//实现
//ret = "1-9月";
ret = OutCondition.GetReportCondition("GenerateMonth", "StartMonth") + "-" + OutCondition.GetReportCondition("GenerateMonth", "EndMonth") + "月";
return ret;
}
}
好,搞清了数据的具体来源,我们再回过头来看IEP.ExportWord中的代码。第一个方法是导出word报表函数的OutWords()方法,具体代码如下
/// <summary>
/// 导出Word报表函数
/// </summary>
public static void OutWords() {
//bool ret = false;
Document doc = new Document(tmpPath);//说明:这里的Document对象就是aspose插件提供的
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(xmlPath);//说明:这里是把xml中的内容加载到XmlDocument 对象中去
XmlNodeList nodeList = xmlDoc.SelectSingleNode("IEP").ChildNodes;//说明:取得xml文件中的所有Words节点集合然后通过遍历就能知道每个需要替换的文字片断,以及这个地方需要从那个接口提供的什么方法来取得值,同时,这个值是什么类型。
foreach (XmlNode xn in nodeList)//遍历所有Words子节点
{
XmlNodeList nod = xn.ChildNodes;
string k = nod[0].InnerText;//说明:需要替换的关键字
string t = nod[1].InnerText;//说明:替换类型,1是word文字,2是table,3是图片
string v = nod[2].InnerText;//说明:从那个接口获取数据
string m = nod[3].InnerText;//说明:需要调用接口中的那个方法
v = IEP.ExportFactory.FactoryBuild.GetValues(v, m);
/*---------------------------------以下为说明-----------------------------
上面一句代码的作用是获取具体的值,可以看到这个地方使用了IEP.ExportFactory.FactoryBuild.GetValues(v, m)其实,IEP.ExportFactory.FactoryBuild是一个工厂类,根据传入的接口和方法生成来调用IEP.ExportData中的具体方法,以得到返回值。代码如下
//下面这句代码是创建一个IMonthly 接口的实例,创建具体内容在IEP.ExportFactory.ExpFactory中创建的具体方法如下
private static readonly IEP.IExport.IMonthly monthly = IEP.ExportFactory.ExpFactory.CreateMonthLy();
/// <summary>
/// 反射调用方法,取得返回值string
/// </summary>
/// <param name="title">实例Type</param>
/// <param name="methodName">方法名称</param>
/// <returns></returns>
private static string GetMethodRetValue(Type title, string methodName)
{
string ret = string.Empty;
try
{
if (!String.IsNullOrEmpty(methodName))
{
MethodInfo method = title.GetMethod(methodName);//说明:methodinfo是发现方法并提供对方法的访问,这里的title实现上是一个具体的类,通过GetMthod方法,可以找到指定的方法
if (method != null)
{
//说明:下面这句的意思是能过Activator.CreateInstance(title) 创建当前titel的具体对象,然后用method.Invoke的方法来调用这个对象的methodname方法。返回的结果是一个object对象
object retK = method.Invoke(Activator.CreateInstance(title), null);
if (retK != null)
ret = (string)retK;
}
}
}
catch (Exception)
{
//IEP
}
return ret;
}
/// <summary>
/// 获取对应的工厂实体
/// </summary>
/// <param name="key">接口名称</param>
/// <returns>具体实体</returns>
public static string GetValues(string key, string methodName)
{
string ret = string.Empty;
switch (key)
{
case "IMonthly"://说明:通过传入的key找到接口,并调用GetMethodRetValue方法返回具体内容
ret = GetMethodRetValue(monthly.GetType(), methodName);
break;
case "IPicOne":
ret = GetMethodRetValue(picone.GetType(), methodName);
break;
default:
ret = "";
break;
}
return ret;
}
---------------------------------------------------------------------------*/
try {
switch (t) {
case "1"://说明:以下是调用对文字的替换,传入三个参数,此时的V为最终的返回结果。具体代码如后所示
RepWords(doc, k, v);
break;
case "2"://说明:以下是调用对table的替换,传入三个参数,此时的V为最终的返回结果。具体代码如后所示
RepTable(doc, k, v);
break;
case "3"://说明:以下是调用对图片的替换,传入三个参数,此时的V为最终的返回结果。具体代码如后所示
k = k.Replace("#*", "");
k = k.Replace("*#", "");
RepIamges(doc, k, v);
break;
}
}
catch (System.Exception ex) {
throw ex;
}
}
//return ret;
doc.Save(outName, SaveFormat.Doc, SaveType.OpenInWord, HttpContext.Current.Response);
//说明:doc.save(保存的文件名,保存格式,保存类型,当前请求)
//保存为doc,并打开
}
/// <summary>
/// 替换Word文档文字
/// </summary>
/// <param name="doc">当前上下文doc文档</param>
/// <param name="key">文档中定义的标记(如:#*2010*#)</param>
/// <param name="val">替换值</param>
private static void RepWords(Document doc, string key, string val) {
//bool ret = false;
try {
doc.Range.Replace(key, val, false, false);//说明:aspose提供的方法具体解释如下图
}
catch (System.Exception ex) {
throw ex;
}
//return ret;
}
/// <summary>
/// 替换word文档表格内容
/// </summary>
/// <param name="doc">当前上下文word对象</param>
/// <param name="key">当前定义表的前缀(如:#*TB1_L1_1*#只在xml原始数据中定义TB1)</param>
/// <param name="val">表格数据值(キ隔离每行,ぐ隔离每行中的每列数据)</param>
private static void RepTable(Document doc, string key, string val) {
//bool ret = false;
try {
//doc.Range.Replace(key, val, false, false);
string curKey = string.Empty;
string[] lineData = val.Split('キ');
int lines = lineData.Length;
//string colData = string.Empty;
for (int l = 0; l < lines; l++) {
string[] colData = lineData[l].Split('ぐ');
for (int c = 0; c < colData.Length; c++) {
curKey = key + "_L" + (l + 1) + "_" + (c + 1);
doc.Range.Replace(curKey, colData[c], false, false);
}
}
}
catch (System.Exception ex) {
throw ex;
}
//return ret;
}
/// <summary>
/// 替换Word文档内图片
/// </summary>
/// <param name="doc">当前上下文文档</param>
/// <param name="key">文档中定义的书签(Word书签名)位置</param>
/// <param name="val">图片相对站点根路径|在word中显示的长度|在word中显示的宽度</param>
private static void RepIamges(Document doc, string key, string val) {
//bool ret = false;
DocumentBuilder builder = new DocumentBuilder(doc);
try {
string[] p = val.Split('キ');
string imgPath = HttpContext.Current.Server.MapPath("~/" + p[0]);
if (!System.IO.File.Exists(imgPath))
{
return;
}
System.Drawing.Image image = System.Drawing.Image.FromFile(imgPath);
if (builder.MoveToBookmark(key)) {
if (imgPath.ToLower().IndexOf("rpttempimg") > -1)
{
builder.InsertImage(image, double.Parse(p[1]), double.Parse(p[2]));
}
else
{
int width = 460;
int height = Convert.ToInt32((Convert.ToDouble(image.Height) / image.Width) * width);
builder.InsertImage(image, width, height);
}
builder.Writeln();
}
}
catch (System.Exception ex) {
throw ex;
}
//return ret;
}
通过以上代码,我们了解到,所有操作都是以aspose为核心,那么这个东西是否也能满足我合并多个word文件的需求呢? 于是我再通过互联网进行查询发现,document这个对象有个apppnedDocument方法。于是我准备建一个测试项目。
引入了aspose.words然后增加一个OpreateWord.aspx页面。前台不写任何代码,后台代码如下
相信都看的明白,只是需要说明下
doc2.AppendDocument(DOC,ImportFormatMode.KeepSourceFormatting);
P它的详细定义如下:
可以看到这个方法要求输入两个参数,一个是需要追加的文档,另一个是IMportFormatMode接口的实现,我们可以使用枚举ImportFormatMode来选择
第一个选择是指保持原格式,第二个是指使用目标样式。也就是说我们把文档doc加入到doc2的时候是保留原格式还是使用目标格式。
看看运行结果如何?
哇,结果出来了,还不错,基本是把两个文件完整合并到一起了。
关于aspose的使用,以后再继续讲,尽请关注。
相关文章推荐
- java 操作word和excel 项目和jar文件
- Silverlight编译错误,提示某文件不是项目的一部分或"生成操作"没有设置为"资源"
- 第十三周项目6-体验文件操作 1
- 第十三周项目6-体验文件操作:C++文件操作初体验
- word中出现“由于文件许可权错误,word无法完成保存操作”的解决办法
- C语言对文件操作函数分析
- Python字符串和文件操作常用函数分析
- 鸡啄米vc++2010系列2(项目文件分析)
- 14周年 项目7体验文件操作 3(实战) 求解:不知道用我的这个方法求平均分对不对
- SpringMVC 项目配置文件加载过程分析(spring4.1.4)
- 文件的预读操作分析
- 第三章数程序设计初步--控制结构综合项目4-1文件操作初体验练习1从文件读取数据
- 操作Word模板文件.dot 结合具体数据 生成Word文档 .doc
- Hadoop:第二个程序操作HDFS -> 【获取Datanode名】【写文件】【WordCount计数】
- java项目word文件转html文件
- vs2005集成qt后产生的qt项目文件结构分析
- python---项目2-查找服务器是否开启ftp的21端口,socket,os,sys,端口识别,文件操作
- nginx进程间的通信机制源码分析(二)-------原子操作、自旋锁、文件锁
- C#项目中操作Excel文件——使用NPOI库
- VS05升级到VS08,程序出现无法打开项目文件以执行升级操作