初步创建一个Xsd
既然要写组件,当然就要确定这个组件的需求,以及确定如何去写。
一般情况下,组件的需求应该不是问题,因为对于这种封装技术难度的组件而言,需求很简单,就是尽量降低技术难度,让更多人能用这个组件,完成本来比较麻烦的事情。
那么从哪里开始写哪?
我选择了从xsd(XML Schema Definition)开始,为什么选择xsd哪?
- 在拥有xsd的情况下,可以很容易的写一个配置的xml,给后面的开发者,一个直观的感受,有利于前期的交流
- 在xsd已经确定的情况下,即使组件的代码还没完成,也不会阻塞其他开发者的进度
- xsd可以用于代码生成,直接生成相关的c#代码
- 借助现在的xml工具,可以非常简单的得到xml的智能提示和格式检查的目的
好,假定这里还是要写一个关于pptx的组件,首先在vs2008中创建一个xsd:
修改一下namespace以及相关的内容
把这个xsd的目标namespace定位"http://www.cnblogs.com/vwxyzh/pptx”,并且在这个xsd中把这个namespace定为前缀pptx。
现在,可以开始写xsd了,回想一下pptx的组成元素,一个pptx可以有很多个slide,每个slide里面有可以有很多的字符串、图、表,当然还有动画元素。
如果要组件无中生有的写出这么一大个pptx,无论对组件而言还是对后续的开发者而言都是个不小的挑战,而且也是一个浪费,浪费了美工资源。
而且通常而言,需要组件化的也仅仅是修改pptx中的数据,而不是从头开始画pptx。所以,配置中只需指名pptx的模板文件即可,以及一些必须的修改动作。
看到这里,相信有不少熟悉xsd的已经想到了下面的:
但是,这样嵌套着定义有些缺陷
- 类型都是匿名的,可能为将来生成c#类型带来麻烦
- 很难共用一些共同的特征
- 影响阅读,对以后的修改带来麻烦
可能是c#写太多了,我不太喜欢xsd中的匿名类型,感觉严重影响阅读效率,把上面那一段用类型化的方式重新改写一下(这里的命名习惯为类型用Pascal,实例用camel):
这里,可以清晰地看到现在有3个类型,分别是Modification、Slide、PptxConfiguation,根节点定义为PptxConfiguation类型。别忘了vs2008的强大功能,在我们写完这些的时候,可以看到旁边已经把xsd的信息都显示出来了:
这个管理器不但可以很形象的显示出各个类型和它们的结构,还可以为我们根据这个xsd生成一个示例的xml:
那么就来生成一个xml看看:
虽然,定义namespace的方法给人的感觉很拙劣,但是,可以很清楚的看到这个xml的大概结构,以及slideIndex的取值范围,简单的整理一下:
发现哪些问题了?
- slideIndex的取值范围(正确的应该是0到int.MaxValue)
- 没有模板文件的信息
先解决第一个问题,slideIndex的类型是xs:int,所以允许是负数,但是这里的场景不允许负数,所以slideIndex的类型应该是xs:int的子集,也就是要重新定义一个简单类型nonNegativeInt,并且修改slideIndex的类型:
(熟悉xsd的一定会问一句,为什么不用xs:nonNegativeInteger,原因很简单,这个类型是对xs:Integer加上范围限制的类型,所以,基本类型不一样,以后生成代码的时候就不是一个c#里面的int了。)
回头看看,示例文件:
vs2008立即发现了slideIndex不允许是一个负数,并且提供了警告提示,并且在错误列表中出现:
修改成一个非负的int值后,警告立即消失。
接下来看第二个问题,pptx的模板没有定义,因为模板是相对于整个pptx而言的,所以应该直接隶属于configuation节,简单点,就直接定义一个属性吧:
再修改一下示例xml,结果如下:
到现在,整个xml配置的大结构是有了,但是怎么修改pptx到现在仍然还是一个简单的modification的占位而已。
思考一下,pptx有哪些内容,那些要做修改,很快就可以得到一个粗略的结果:
- 修改文本内容
- 修改表格
- 修改图表(Chart)
当然其他修改也可能发生,只是概率不及上面3个出现的频率高。假设暂时需求就是这么3个修改,这里我们有2个选择:
- 利用xsd的xs:choice节点
- 利用xsd类型的继承
两者都有自己的优势,如果没有明确的重用部分,以及选项是固定的,不太可能在未来的某个时刻发生变化,那么就用xs:choice节点,反之,则用xsd类型的继承。
现在虽然我们就假定了3种修改,但是这个假定显然是不可靠的,因为还没有把这个xsd拿出来和大家讨论过,讨论过程中随时可能出现新类型的修改,再则,在组件交付的后期仍然有增加修改类型的可能,所以,这里就选择运用继承的方式。
(不熟悉xsd的读者,可能会吃惊,xml里面的类型居然还有继承!是的,确实是有继承的,甚至还有抽象类和封闭类的概念。)
先把Modification类型声明为抽象类:
然后声明3种修改,都继承自Modification:
这里开始就以TextModification为例,其他修改就省略了。思考一下,如何修改pptx中的文本,需要知道那些信息:
- 在哪里修改(where)
- 修改成什么(what)
- 怎么修改(how to)
- 何时修改(when)
关于how to的问题,这与xml无关,是c#实现时需要解决的问题,关于when的问题,将在下一节中详细说明。剩下来的就是where和what这两个问题了。
对于熟悉office 2007二次开发的人,一定对where问题非常拿手,但是,考虑到大部分人并不熟悉这一方法,这里就使用最简单的字符串占位的方法。
也就是说,一个TextModification需要知道where(占位字符串)和修改成的内容,也就是:
看起来像那么回事,来看看真正的xml会是什么样子的,首先预备好这么一个xml:
在slide节里面添加一个modification:
有没有发现这个节点是白色的,和之前的节点不同,这是因为modification节点的是Modification类型的,而Modification类型是个抽象类,不可能创建出这么一个抽象类,必须创建它的子类,按下空格创建这个节点:
智能提示直接蹦出来了3个Modification的子类,选TextModification类型,输入必要的信息:
(另外几个modification的继承类也用相同的方式思考和处理,就可以获得一个草稿的xsd了)
看起来像那么回事情,可以去和组件的合作者以及组件的使用者讨论一下了看看他们有什么想法,以及有那些思考的不周全的地方。
(注意,到这里为止,这个组件尚未写1行c#代码,纯粹在需求分析和构思阶段。但是,这里产生了一个对今后相当重要的文档——xsd,这是一个组件代码的实现目标,同时也是组件使用者的"使用手册",换句话说,这是这个组件的一个契约,实现者和使用者都要遵循这个契约。)
上一篇:从写组件说Xml——背景篇(零)