您的位置:首页 > 其它

开源Word读写组件DocX 的深入研究和问题总结

2013-07-15 19:46 381 查看

一. 前言

前两天看到了asxinyu大神的【原创】开源Word读写组件DocX介绍与入门,正好我也有类似的自动生成word文档得需求,于是便仔细的研究了这个DocX。 我也把它融入到我的项目当中并进行了实践。工具果然牛叉,但也有一些问题,后边一并列出来。

二. DocX的基本原理

Word有一个开放的文件格式,叫做Office Open XML。Office 从2007版本开始用它。它的基本方法是将文本和格式存储成xml,把其他资源(图片等)存储成独立文件,并将其进行Zip压缩。这样的好处是它的体积远比03版本的office文件小得多,但也造成了一部分不兼容性。因此,别指望DocX支持Office2003.

当理解Word实质上是XML以后,就不难了解如何操作Word了。理论上说,你不需要任何工具就能对它进行操作,当然复杂性极高。微软推出了Open XML SDK, 专门帮助.NET语言与Office实现互操作,这也成了COM组件外的新选择,但它的安装包有100M, 对很多部署来说,难度不小。

这个组件DocX本身实际上是对XML操作的封装库,如果你有兴趣看它的源代码,基本核心就是XML的字符串组装和拼接,添加一个图表的本质就是在对应XML标签下面再增加一个图表的子文档。

看到字符串拼接,有经验的同学肯定站出来会问性能如何。它没有使用StringBuilder,但本身性能不差,我生成100页的图文并茂的Word文档也是瞬间的事情,所以,没有关系。

三. 自动文档生成的方法

对程序开发来说,最常见的需求便是自动生成文档,完全从0生成图文并茂,排版合理的文档对程序员来说不现实,代码多得海了去了。所以很多人的做法是字符串替换,通过替换特定文字来操作,但这样显然是相当不专业的。

比较合理的做法,是Office里面的“域”。域的本质,对程序员来说就是表达式,这个变量可以是文档字数,文档页数(这是Office里面自带的属性)。域相当牛逼,甚至可以连接到一个数据库,一个按钮,乃至一篇网页上去,真心无所不能。

同样你也可以自己添加属性,也就是所谓“自定义属性”。

如何查看文档中的所有自定义域呢?

在Word最上面的“插入”卷展栏下选择文档部件->域,如下图所示,并在域控制框中左侧选择DocProperty,即可看到所有的属性:

///
/// Insert a chart in document
///
public void InsertChart(Chart chart,Paragraph paragraph=null)
{
// Create a new chart part uri.
String chartPartUriPath = String.Empty;
Int32 chartIndex = 1;
do
{
chartPartUriPath = String.Format
(
"/word/charts/chart{0}.xml",
chartIndex
);
chartIndex++;
} while (package.PartExists(new Uri(chartPartUriPath, UriKind.Relative)));

// Create chart part.
PackagePart chartPackagePart = package.CreatePart(new Uri(chartPartUriPath, UriKind.Relative), "application/vnd.openxmlformats-officedocument.drawingml.chart+xml");

// Create a new chart relationship
String relID = GetNextFreeRelationshipID();
PackageRelationship rel = mainPart.CreateRelationship(chartPackagePart.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart", relID);

// Save a chart info the chartPackagePart
using (TextWriter tw = new StreamWriter(chartPackagePart.GetStream(FileMode.Create, FileAccess.Write)))
chart.Xml.Save(tw);

// Insert a new chart into a paragraph.

Paragraph p = paragraph ?? this.InsertParagraph()
//如果指定了paragraph,则从这个段落插入
XElement chartElement = new XElement(
XName.Get("r", DocX.w.NamespaceName),
new XElement(
XName.Get("drawing", DocX.w.NamespaceName),
new XElement(
XName.Get("inline", DocX.wp.NamespaceName),
new XElement(XName.Get("extent", DocX.wp.NamespaceName), new XAttribute("cx", "5486400"), new XAttribute("cy", "3200400")),
new XElement(XName.Get("effectExtent", DocX.wp.NamespaceName), new XAttribute("l", "0"), new XAttribute("t", "0"), new XAttribute("r", "19050"), new XAttribute("b", "19050")),
new XElement(XName.Get("docPr", DocX.wp.NamespaceName), new XAttribute("id", "1"), new XAttribute("name", "chart")),
new XElement(
XName.Get("graphic", DocX.a.NamespaceName),
new XElement(
XName.Get("graphicData", DocX.a.NamespaceName),
new XAttribute("uri", DocX.c.NamespaceName),
new XElement(
XName.Get("chart", DocX.c.NamespaceName),
new XAttribute(XName.Get("id", DocX.r.NamespaceName), relID)
)
)
)
)
));
p.Xml.Add(chartElement);
}


在指定位置插入图表

和源代码对比,很容易就能看出两者的区别。

我能添加更多的图表吗?当然可以。源代码只内置了三种图表:Pie, Line和Bar,不能满足要求,既然充分理解了它的原理,不妨我们扩展它吧:

public class PieChart : Chart
{
#region Properties

public override Boolean IsAxisExist
{
get
{
return false;
}
}

public override Int16 MaxSeriesCount
{
get
{
return 1;
}
}

#endregion

#region Methods

protected override XElement CreateChartXml()
{
return XElement.Parse(@"<c:pieChart xmlns:c=""http://schemas.openxmlformats.org/drawingml/2006/chart"">
</c:pieChart>");
}

#endregion
}


注意看上面PieChart的定义,只要修改CreateChartXml函数,修改pieChart变成你想要的图表就可以了,通过一个工厂方法指定枚举类型生成想要的图表。至于Word支持什么类型的图表,在微软的技术文章这里可以看到更详细的类型。我又创建了四五个新类型。满足了我的需要。

五. 总结

用了这个组件,感受良多,这哥们和我一样的在校学生,,但已经做了这样的开源项目,下载量超过18000+。 虽然理论不一定多牛逼,但确实满足广大人民群众需要了,400KB的dll文件,直接解决了.NET平台word生成这一刚性需求。 但作者确实下了功夫,大量的XML转换和分析,纯粹的体力活啊!

1. 对Office2013的支持不够

2. API远没达到完善,例如无法良好的操作图表类型,只能使用默认值。

3. 代码欠重构,可获得更好的程序风格和性能的提升。

4. 域更新不正常

如果这几个问题能解决,那确实是最好不过的了。除此之外,其实还有很多小问题,一方面期待作者解决,另外一方面如果项目需求紧急的话,索性我们自己先改了得了。代码还是很容易理解的。

我尝试把它用在项目中,经过测试,发现基本稳定,大家可以尝试采纳。

有任何问题,欢迎随时交流,如果您觉得对您有帮助,请点推荐,谢谢!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: