IEP项目对Word文件的操作分析

本文深入分析了NPDS项目中利用Aspose插件处理Word文件的过程,包括导入模板、XML数据解析、接口调用以及文档生成。通过详细解读关键代码片段,展示了如何使用Aspose.Words组件进行Word内容替换、表格填充和图片插入,最终实现Word文件的高效生成。同时,演示了如何使用Aspose插件的AppendDocument方法将多个Word文档合并。

NPDS中,需要对word进行操作,由于在网上查的资料都不怎么有用,所以,我决定今天好好分析下孙伟以前在IEP项目中的操作办法,希望能得到一些启示,以下是我对孙伟的代码的分析:

 

项目结构如下:

 

如到导出功能的就主要是划红线的四个部分,下面我们来分别看下里面的内容,首先从IEP.Exportword的内容

 

展开项目后发现里面只有一个文件,找开该文件,首先看到的是USING处,多了几个不常见的东西

 

 

通过在网上查询发现,aspose是一个收费的第三方插件,我估计现在我们用的可能是破解版,因为在网上有破解版提供下载。aspose是一个专业插件开发公司提供的用于制图,写电子邮件,拼写检查,创建条形码,生成各种文档等的组件。Aspose.Words是一款先进的类库,使您可以直接在各个应用程序中执行各种文档处理任务。Aspose.Words支持DOCOOXMLRTFHTMLOpenDocument, 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节点下都有,ktvm四个子节点,其中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;//说明:替换类型,1word文字,2table3是图片
                
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, 
falsefalse);//说明: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], 
falsefalse);
                    }
                }
 
            }
            
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的使用,以后再继续讲,尽请关注。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值