1. 简介

Aspose.words 可以在不使用 Microsoft.Word 的情况下生成、修改、转换、打印文档。不依赖office组件,这一点给我们提供了极大的便利性,可以简单的引入 DLL(Dynamic Link Library,动态链接库文件) ,就可以操作 word 文档。不过也有一点小小的麻烦就是需要许可证 Aspose.Words.lic 。

2. word 文档结构

既然要操作 word 文档,就要先简单了解一下 word 对于 aspose 来说是一个怎样的对象。word 在 aspose中是一个 DOM(Document Object Model ,文档对象模型) 。我们先来看一下 word文档在aspose 中的模型图。

这上面节点的具体内容可以先暂时不用理会,到了具体的使用场景,如果你要修改一个页眉,可以查一下,页眉是属于哪一个节点,有哪些属性。我们先建立一个DOM 的大概理解 : 根节点为 Document ,最底层节点为 Run 的一棵树。

3. 查看 DOM

aspose提供了查看DOM 的工具 DocumentExplorer,可以在 github 中下载。地址:https://github.com/aspose-words/Aspose.Words-for-.NET 。左侧的是与文档结构对应的树,右侧是节点中的一些编码内容。看这棵树是为了对 DOM 有一个直观的认识。

4. 为了有更加深刻的理解,我们实现一个小案例

假设有一份word文档, 给定一个 BookMark(书签)的名称,怎么知道这个书签在文档中的位置。我们先简单定位到页数,也就是说已知 Document (文档) 这个对象,BookMark(书签)的名称,要求解 这个BookMark 在文档中的 PageIndex (页数)。

书签在word 中的样子。

这个界面告诉我们书签 有 名称、位置 两个变量。 可以执行 添加、删除、定位、隐藏操作。

接下来看一下书签在 aspose 中的实现。

在 Aspose 中书签的Name 对应名称,可以取值赋值,Text 是书签的值,这个在我们打开word 书签界面的时候没有直接输入的地方,可能可以通过其他方式赋值。BookmarkStart 书签开始的地方,BookmarkEnd 书签结束的地方。 有开始的位置也有结束的位置,这说明书签是一段内容。(更准确的说,是word的文档协议先定义了书签有开始标记和结束标记,aspose根据这个协议,才有了 BookmarkStart 和 BookmarkEnd),我们可以把一整页设为书签,也可以把一张图片设为一个书签。如果书签是一个光标,那么开始和结束标记都是这个光标所在的位置。我们已经有个整个文档的对象 Aspose.words.Document , 书签对象 Aspose.words.BookMark , 书签开始对象 Aspose.words.BookmarkStart, 书签结束对象 Aspose.words.BookmarkEnd。

一份文档中有很多书签,如何找到其中的一个。首先找到所有的 Bookmark

Aspose.Words.BookmarkCollection ,然后根据 bookmarkName找到某一个书签

要实现我们的Case(还记得吗,根据书签定位到页数),是不是应该要有一个 类似 int i = GetPageIndex ( BookMark bookmark ) 的 API 。好像还真有一个实现了类似功能的API 。 Aspose.Words.Layout.LayoutCollector (不要问我怎么知道这个API的) 。LayoutCollector 字面意思:布局收集器。可以理解为文档中所有节点位置信息的集合。

不过还有一个问题:参数是 Node,这又是一个怎样的存在,一个抽象类。

那么 Bookmark 与 Node 是什么关系。

要回答这个问题就要看 BookmarkStart 这个对象,它既是 Node,也是 Bookmark 开始的位置。

到这个时候感觉有好几个对象,有点乱,隐约有点关联。试着建立他们之间的联系。

这样我们可以从 Document(文档)——> Bookmark(书签) ——> BookmarkStart (书签开始节点) ——> Node(节点) ——> PageIndex (页数)

Document doc = new Document(string fileName);

Bookmark bookmark = doc.Range.Bookmarks["bookmarkName"];

int pageIndex = new LayoutCollector(doc).GetStartPageIndex(bookmark.bookmarkStart);

这个地方我们定位到了一个书签开始位置的页数。有了页数,就可以用aspose 中的打印功能直接跳转到这一页显示。

这时,发现刚刚提的那个问题,好像有点不太对。

严格来说应该是: 一个书签在文档中开始的页数 和 结束的页数分别是多少。 当然大部分情况下都是在同一页的。我们实际生活中接触到的是夹在两页之间的书签。word 文档中的电子书签在这个定位的功能上有了扩展。可以定位一个字、一段话、一张图片、还有很多其他意想不到的作用。

5.查找关键API

整个过程中有个地方比较微妙,就是如何查找 public int GetStartPageIndex(Node node) 这个关键API,如果你时间比较仓促,那就在官方提供的Demo中 用VS打开,检索 bookmark 、Page、Index 这几个关键字,一个单词一个单词分别查,可能会查到很多相关的,每一条快速浏览一下,这个API就在其中,有时比较难发现。这种查找方式,需要Demo作者对方法的命名比较规范,命名要有意义,与所做的事对应起来。我们自己在开发过程中命名的时候,如果感觉一个方法命名很纠结,不能用一两个单词表达所做的事情,或者无论如何写注释,都感觉没讲清楚的时候,那很有可能这个方法本身就是有问题的,它做的事情太多了,需要拆分。如果你有比较充足的时间,那就把官方Demo的例子都跑一下,你要找的API,在你调试某一个例子的过程中可能会发现,当然也可能没有现成的方法能实现你的需求,那就用其他方法继续查,StackOverflow 也可以。各种尝试之后不行,可以回到源头,想一下这个需求是不是本身就有问题,是不是可以换个方式实现。“否定问题是解决问题最好的方法”。

Aspose.words 书签定位的更多相关文章

  1. 在大型软件中用Word做报表: 书签的应用

    本文转载:http://www.cnblogs.com/huyong/archive/2011/08/24/2151599.html 报表基本上在每一个项目中占有很大的比例,做报表也是我们开发人员必须 ...

  2. vim笔记2

    用vim 快两年了 看过教程也不少,总的来说还是得自己多练习,当自己觉得有需要的时候,再添加功能.这里分享个看过的最好的教程,出自贴吧的某个朋友,写的很好 零 学会盲打 壹 配置文件先从最简开始,在 ...

  3. 理解SQL Server是如何执行查询的 (2/3)

    查询执行的内存授予(Query Execution Memory Grant) 有些操作符需要较多的内存才能完成操作.例如,SORT.HASH.HAS聚合等.执行计划通过操作符需要处理数据量的预估值( ...

  4. C#操作Word的辅助类(word2003) 修改完善版

    转自:http://blog.csdn.net/jiutao_tang/article/details/6567608 该类在他人编写的几个类基础上扩展完善而来,主要功能有: (1)插入文本 (2)插 ...

  5. netbeans for php常用快捷键

    文本编辑 复制当前行到上一行/下一行ctl+shf+up 移动当前行到上一行/下一行shf+alt+left/right/down/up 删除当前行ctl+E 生成下一行shf+enter(回车) 大 ...

  6. ADO数据库链接

    一.数据库操作准备 // --------------------------------------------------------------------------------------- ...

  7. MFC中使用ADO方式连接数据库

    文章转自:http://blog.sina.com.cn/s/blog_a43aba5601014z8h.html 一.数据库操作准备 1.导入ADO动态链接库 在工程的stdafx.h中加入如下语句 ...

  8. DocX开源WORD操作组件的学习系列三

    DocX学习系列 DocX开源WORD操作组件的学习系列一 : http://www.cnblogs.com/zhaojiedi1992/p/zhaojiedi_sharp_001_docx1.htm ...

  9. 第六周 Word目录和索引

    第六周 Word目录和索引 教学时间 2013-4-2 教学课时 2 教案序号 5 教学目标 能正确使用索引.目录等 教学过程: 复习提问 1.脚注和尾注的区别是什么?2.如何插入脚注和尾注?3.如何 ...

随机推荐

  1. 3.Node.js 自定义微信菜单

    文章目录:         1.Node.js 接入微信公众平台开发         2.Node.js access_token的获取.存储及更新         3.Node.js 自定义微信菜单 ...

  2. 并发容器ConcurrentHashMap#put方法解析

    jdk1.7.0_79 HashMap可以说是每个Java程序员用的最多的数据结构之一了,无处不见它的身影.关于HashMap,通常也能说出它不是线程安全的.这篇文章要提到的是在多线程并发环境下的Ha ...

  3. 平面之后3D成主流?VR全景表示不服!——全景智慧城市常诚

    目前很多人对VR全景这个词汇没有明确的概念,更没有人做过全面的研究,VR全景是什么?VR全景可以做什么?不同于我们经常听到的VR色情,全景智慧城市常诚今天就来为各位做一个系统全面的介绍,深入了解之后, ...

  4. 基于angular实现模拟微信小程序swiper组件

    这段时间的主业是完成一个家政类小程序,终于是过审核发布了.不得不说微信的这个小程序生态还是颇有想法的,抛开他现有的一些问题不说,其提供的组件系统乍一看还是蛮酷的.比如其提供的一个叫swiper的视图组 ...

  5. java基础(四章)

    一.             switch结构(开关语句)的语法 switch(表达式 ){ ------- [dream1]类型为int.char case  常量1 :    ---------[ ...

  6. 封装TableView有可能用到的数据结构和UITableViewCell的一个继承类

    最近4年的时间,我已经做了5个App完全独立开发, 工作经历5个App, 维护了两个App. 在这期间用的最多的是UITableView, 因此也有许多感觉可以封装的. 现在就是我封装的. RXCel ...

  7. Java基础——封装

    最近学习Java面向对象方面的知识点,一直没时间更新博客,因为这块的知识点真的蛮绕的.一个知识点一个知识点的往外冒,而且对于我这个初学者来说区分构造器和方法就花费了一整天的时间.现在准备再重新过一遍知 ...

  8. (cljs/run-at (->JSVM :browser) "语言基础")

    前言  两年多前知道cljs的存在时十分兴奋,但因为工作中根本用不上,国内也没有专门的职位于是搁置了对其的探索.而近一两年来又刮起了函数式编程的风潮,恰逢有幸主理新项目的前端架构,于是引入Ramda. ...

  9. Linux crontab定时执行任务命令格式与详细例子

    基本格式 : * * * * * command 分 时 日 月 周 命令 第1列表示分钟1-59 每分钟用*或者 */1表示 第2列表示小时1-23(0表示0点) 第3列表示日期1-31 第4列表示 ...

  10. SQLServer类型与Java类型转换问题解决

    ResultSet 接口提供用于从当前行获取列值的获取 方法(getBoolean.getLong 等).可以使用列的索引编号或列的名称获取值.一般情况下,使用列索引较为高效.列从 1 开始编号.为了 ...