基于.net平台的office开发(3

序言:

   

昨天晚上洗澡的时候突然回忆起当时我们开发的时候遇到的几个技术问题,觉得还是有写头的。所以就决定今天照着以前的代码给大家描述一下遇到的问题。

 

Smart Document开发

问题一:程序自动化填写xml标签。

    我想了解智能文档开发的人都知道,整个智能文档就是围绕着XMl标签或者说是XSD架构来实施的,任何一个操作都会和特定的标签联系起来。而大家看到的简单的例子中一般标签都是固定的。而当时我们做的方案中却要求能够动态生成xml的标签。其实这样的应用是比较多的,大家设想一下,比如你是在做一个员工工资的文档的智能文档,那么你非常很有可能就需要选择一个员工,就在表格中新建一行,同时在这一行中生成相应的xml标签。这个在微软的smart documentadditional example里面就有这样的例子。有人可能会认为直接通过RangeInsertXMl的方法插入一段XML标签不就可以了么。事实上就是这样的,但是有一个问题就是如果你插入的xml标签是没有按照特定的规范,最后智能文档是不能够识别这些标签生成相应操作的。例子:我们的XSD如下:

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="Exercise" targetNamespace="Exercise"

    elementFormDefault="qualified">

    <xsd:complexType name="exampleType">

       <xsd:all>

           <xsd:element name="CourseName" type="xsd:string" />

           <xsd:element name="Chapter" type="xsd:string" />

           <xsd:element name="KeyPoint" type="xsd:string" />

           <xsd:element name="Questions">

              <xsd:complexType>

                  <xsd:sequence>

                     <xsd:element name="Question">

                         <xsd:complexType>

                            <xsd:sequence>

                                <xsd:element name="Content" type="xsd:string" />

                                <xsd:element name="AnswerA" type="xsd:string" />

                                <xsd:element name="AnswerB" type="xsd:string" />

                                <xsd:element name="AnswerC" type="xsd:string" />

                                <xsd:element name="AnswerD" type="xsd:string" />

                                <xsd:element name="Result" type="xsd:string" />

                            </xsd:sequence>

                         </xsd:complexType>

                     </xsd:element>

                  </xsd:sequence>

              </xsd:complexType>

           </xsd:element>

       </xsd:all>

    </xsd:complexType>

    <xsd:element name="Exercise" type="exampleType" />

</xsd:schema>

而现在我们需要对应用了这个Xml架构的页面实现自动化的添加多个Question节点,而且事先并不知道我们到底需要多少个。我们查找Word对象模型,http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbawd11/html/womthInsertXML_HV01031008.asp得知:

Inserts the specified XML text into the specified range or selection. If the specified range or selection contains text, the InsertXML method replaces the existing text.

expression.InsertXML(XML, Transform)

有了这个方法,我们可能会采取下面的方法,我们所要插的东西父节点是Questions(也就是说我们的所有Question节点都添加在它的下面),所以我们就在这个文档中搜索Questions节点。使用下面方法:

    oRange.Application.ActiveDocument.SelectSingleNode("//c:Questions",cXMLNSc,true)//这里的oRange可以从任何位置出发,就是说他只要是一个Range对象即可,不一定要是特别的位置。

上面这句话就可以让我们定位到Questions位置。下面我们就可以采取

    object test = null;

    oRange.Application.ActiveDocument.SelectSingleNode("//c:Questions",cXMLNSc,true).Range.InsertXML(“<Question><Content>test</Content><AnswerA>just a test</AnswerA><AnswerB>just a test</AnswerB><AnswerC>just a test</AnswerC><AnswerD>just a test</AnswerD></Question>”,test);

确实像这样的方法,我们是可以在word里面插入相应的xml节点,但是我们也会发现,如果我们以前在这些节点上定义了相关的操作的话,现在它是不可以使用,如果我们去看word中的XML结构的话,你会发现这些新加的xml节点的命名空间等都是和以前的那些不一样的,也就是说两者之间是不兼容的。

    那么解决这个问题的办法是显然的,我们设想是否可以直接将这里的xml变成兼容的呢?暂时我还没有找到可以直接通过这样的方式,或者修改命名空间的方式来实现这样的兼容性,我是通过另外一种方式。

    首先我们新建一个word文档,将上面的那个框架加到里面去,然后我们再在word中使用这些框架,但是我们只用我们需要的也就是说我们如下:

<Question><Content></Content>

<AnswerA></AnswerA>

<AnswerB></AnswerB>

<AnswerC></AnswerC>

<AnswerD></AnswerD></Question>

    然后我们保存文档,选择保存的格式为Xml格式,这个时候我们就可以生成一个架构完全一样的xml得文档片断。然后我们采取:

    XMlDocument xmlDoc = XMLDocument();

    xmlDoc.Load(前面的那个文档片断);

    object test = null;

    oRange.Application.ActiveDocument.SelectSingleNode("//c:Questions",cXMLNSc,true).Range.InsertXML(xmlDoc.InnerXMl,test);

    就可以了实现我们想要的效果。

注意:这里就牵涉到一个智能文档的解决方案如何读取本地文件的问题。我想读取文件一般只有两个问题。一:权限,二:路径。由于我们现在没有涉及权限,所以默认我们设置的都是full trust(这是不合理的),然后一个问题就是路径,大家应该知道智能文档的dll的目录是C:\Documents and Settings\Administrator\Local Settings\Application Data\Microsoft\Schemas,在这个目录下,大家设想,我们的方案是要到客户那儿部署,所以我们如果放在一个特定的位置,然后使用绝对路经编码,显然是不合理的,那么剩下来就有几条路:第一:放在注册表,这个很简单,我不想去说。第二:如果你不想放在注册表的话,你可以选择部署的时候,将此片断文件部署到智能文档dll相同目录下,然后使用相对路径来访问。当然这也是可以的。第三:如果你说你不也不想使用上面的方法,那么你可以采取利用manifest文件,打开manifest.xml文件,可以看到:

<SD:file>

              <SD:type>other</SD:type>

              <SD:version>1.2</SD:version>

              <SD:filePath>useXml.xml</SD:filePath>

       </SD:file>

这样的片断,你就可以采取把你的文件放在这个里面,然后通过安装扩展包的时候一同安装上去,但是这个就要求你把这个片断文件,放在安装过后的程序目录下了。

问题二:传输文件。

    可能大家会疑问,这是智能文档开发要解决的问题么?这还需要你说么?但是现实上,我们当时确实遇到了这样的问题,比如说你想你的客户使用一个Word文档填写好了信息,然后直接使用智能文档,点击提交,文档就能够自动发给你。这该如何实现呢,我们当时就想到两种方法,第一:使用邮件,这就会牵涉到在智能文档编程中去使用邮件服务来传递文档本身。第二:采用Web Service.由于当时我们开发的应用采取邮件方式不合适,所以我们采用了Web Service方式。我们采用了WSE中的attachment方式。当时我们使用的WSE 2.0。至于如何使用WSE –AttachMent,这个问题非常的简单,大家只要安装了WSE 2.0然后看它的例子就可以了。我在这里只是想提供给大家,这是一条可选的道路。至于如何去实现,则是相当简单的问题,大家可以自己去试。

注意:但是我们在开发中遇到一个奇怪的问题,差点就让我们放弃了WSE,当时老板让我是用WSE 的附件,然后他说在他机器上可以,当然他只是测试了一般的例子,没有测试智能文档的例子,然后我就兴冲冲的安装了WSE,也不记得当时安装的是什么版本了,然后我就在我的InvokeControl方法里面调用WSE attachment的方法,结果运行,我发现,不会报错,但是只要你的那个函数里面调用了WSE的方法,那些函数就永远无法运行,就是不会进去,也不会出错,如果你在SmartDocInitialize中调用了这些方法,那么你的智能文档就无法使用。当时真是让我郁闷得快死了。后来才知道是因为安装WSE的选项错了,后来我换了机器装了WSE,然后选择自定义安装,把所有的东西都装上了,才可以。到目前为止,这是我遇到的一个非常有趣的事情,在office 开发的过程中。希望大家以后如果一起使用的话,不要犯我这样的错误,当时我差点就将婴儿和脏水一起倒掉了。呵呵。

    小结:在这篇中,回忆了当时在开发的过程中的一些郁闷的事情,这两个问题都折腾了我将近一天的时间,可能当时新接触office 开发没有经验,瞎摸瞎撞。可谓满头是包。不过总算都解决,也算让人感到欣慰。