1.实现接口
前面一篇已经确定了接口,并且已经生成了类,但是这些类显然还不完整,因为这些类没有实现任何接口。
不过,在实现接口之前,必须要注意的是ms的这一段警告:
这里清楚地说明了直接修改这段代码的一个风险:如果xsd发生变化了,那么再次用xsd.exe生成代码时,所做的修改讲丢失。这时要么手工迁移,要么就再写一遍,无论哪种,都是无法接受的。
因此,实现接口的代码不能放在生成的pptx.cnblogs.cs中。这里借助c# 2.0就提供的partial关键字,把对类型的修改放到另一个文件中(这里要注意namespace,如果不相同,就会被认为是两个不同的类型)。所以,新添加的文件至少应该是这样的:
然后实现接口:
2.具体实现…
限于篇幅,以及和主题的相关度,此处省略具体实现。
3.修改pptx
pptx的open xml format说白了就是xml+zip的格式,所以修改xml就可以修改呈现给终端用户的pptx。
现在又要感谢ms的Linq to Xml,可以把原来操作非常麻烦的Xml DOM方式完全扔到一边,用简洁的Linq语法完成当初几十行DOM代码才能完成的辛苦工作。
这里以修改pptx中的文本内容为例(因为这个最简单,其它的都会比较复杂,例如chart需要同时修改缓存数据和真实数据,真实数据又在一个embed xlsx里面,对于不熟悉open xml format的人来说,有点少儿不宜的感觉)。
先来看看文本内容在pptx中的xml到底是什么样子的,为了看xml,先做一个pptx的模板,如下:
保存为sample.pptx,然后到目录下面,把文件名修改成sample.pptx.zip,并解压,找到这个目录:
用vs2008打开slide1.xml,可以看到:
几乎所有内容都在第二行,估计没有人愿意看这样的xml。。。别急,利用vs2008的格式化文档的功能(快捷键为Ctrl+K,Ctrl+D):
瞬间,就可以获得一个完全格式化好的xml,然后再找到里面的placeholder:
可以看到placeholder在a:t节中出现,至于其它的节,暂时忽略它们。
注意先看namespace:a,a的定义为:
所以,需要在代码里面预先定义namespace:
乍一看这个语句是不是有点怪,左边的类型是XNamespace,而右边怎么是个字符串?别急,来看看XNamespace的定义:
可以发现XNamespace里面定义了从string的隐式转换,所以上面那个语句是合法的,另外,还有一个很重要的运算符重载+,输入是XNamespace和string,输出为XName,这个运算符重载将在后面非常广泛的用到。
下面来看看TextModification的大体结构吧:
这里用到了ExecutionContext的两个扩展方法,GetCurrentSlideDocument和SaveCurrentSlideDocument这两个方法,分别用于取得XDocument的实例和保存这个实例,而中间的todo就是实现的重点。
还记得前面的a:t吗?需要到整个xml文档中去查找a:t的节点,怎么找哪?最简单的当然是用Linq to Xml:
Descendants方法代表着XPath的子孙轴(关于Xml的13个轴可以参考w3schools,为了方便起见,就来个截图:
),也就是查找Xml文档下面的所有节点。
但是前面的Linq找到的是所有的a:t,而不是包含特定内容的a:t,所以需亚修改一下Linq:
节点找到了,但是还需要修改它们:
剩下一个问题,就是realValue怎么取得哪?
TextModification有一个value属性是Expression类型的,而Expression有实现了IExpression接口,也就是有一个GetValue的方法,那么realValue就可以这么写:
所以整个类就是:
到现在为止,这个组件基本上已经可以工作了,但是,不得不说一个问题,如果Xml配置错了,如何差错哪?下一篇将讨论一下这个问题。
下一篇:从写组件说Xml——改良(六)