为 SAX ContentHandler 构建编译器(2)DFA 构造与测试汇编器
 
- UID
- 1066743
|

为 SAX ContentHandler 构建编译器(2)DFA 构造与测试汇编器
DFA 构造DFAFactory 类从该解析树编译 DFA。它在 createDFA() 方法中实现了上月所讨论的算法。目前,该方法接受解析树(作为一个 XPathNode 对象)作为参数,并返回 DFATable 的实例。
DFATableDFATable 是一个临时类,主要是为了测试而引入它。最终,正如在第一篇 HC 的专栏文章中所解释的,它会被 table类所替代。这个类提供三个有用的方法:
- 一旦命中给定的 XML 元素, move() 返回 DFA 转换的状态。对于 XML 元素,它的参数是 QName 和当前状态。
- 如果当前状态是接受状态,则 isAcceptingState() 返回真。接受状态是指,已识别了 XPath 时的状态。在解析树中,它对应于命中 END_MARK 。
- getAssociatedData() 返回与 XPath 相关的数据(或者为空,如果当前状态不为接受状态)。通常,当已经识别了某个 XPath 时,该数据会告诉我们调用哪些方法。
是 DFATable 。如您所见,这个类很简单。它有三个分别用于 DFA 识别的 QName 列表的数据字段:( symbols )、转换表( dtran )和接受状态( astate )。
DFAFactory 中的 DFAFactory 是 HC 编译器中的核心类,因为它负责编译转换表。 createDFA() 是以前专栏文章中所讨论过的 DFA 构造算法的直接实现。事实上,这个算法出现在该代码的注释中。
我认为,阅读该代码时,最困难的方面是认识到状态是由一组 XPathNode 表示的。请记住在第一篇 HC 专栏文章中对状态和堆栈的讨论:状态表示特定的堆栈配置(即,出现在堆栈中的一组 XML 元素和属性)。
在该算法中,一组 XPathNode 表示一个堆栈配置。事实上,如果跟踪该算法的过程,就会认识到它构建一个所有可能的堆栈配置以及在这些配置间的转换的列表。
该算法中的顶层循环对可能出现在 XML 文档中的 XML 元素和属性的列表进行迭代。为了计算这个列表, DFAFactory 遍历该解析树,并通过 uniqueSymbols() 方法来编译一个唯一的 QName 列表。
通过检查状态是否与 END_MARK 节点相一致, createDFA() 还构建了一个接受状态的列表。
e_closure() 是一个助手方法,它计算 followpos() 中的节点列表。
测试编译器虽然 HC 还不十分完整,但它的后端已经基本编写完成。现在只差代理和前端。
为了测试 DFA 构造,我必须模拟代理和前端。 是 DFAHandler (一个模拟代理的类)。但它不调用应用处理程序;它只将其自身限于打印已识别的 XPath。
该处理程序获取 DFATable 的实例,并使用 move() 函数来转换到新状态(在给定 XML 元素的情况下)。
进一步设想,您对 db:sect1/db:simpara/db:ulink 和 db:sect1/db:simpara XPath 感兴趣。下面摘录的这段代码显示了如何创建识别 db:sect1/db:simpara/db:ulink 和 db:sect1/db:simpara XPath 的 DFA:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| NamespaceSupport namespace =
new NamespaceSupport();
namespace.declarePrefix("db",
"http://www.ananas.org/2001/docbook");
MessageStore message =
MessageStore.getMessageStore(
"org.ananas.hc.compiler.Message");
XPathParser parser =
new XPathParser(namespace,message);
String xpath1 = "db:sect1/db:simpara/db:ulink",
xpath2 = "db:sect1/db:simpara";
XPathNode first = parser.axpath(xpath1,1,xpath1),
second = parser.axpath(xpath2,2,xpath2),
root = new XPathNode(XPathNode.OR_XPATH,
first,second);
DFAFactory factory = new DFAFactory();
DFATable table = factory.createDFA(root);
XMLReader xparser =
XMLReaderFactory.createXMLReader(
"org.apache.xerces.parsers.SAXParser");
xparser.setContentHandler(new DFAHandler(table));
xparser.parse("file:doc.xml");
对于 HC,下一步是什么DFAHandler 展示了,HC 不久将如何工作。无可否认,前面的示例针对两个 XPath 进行了硬编码,但那只是因为 HC 仍然需要一个前端(在下一篇专栏文章中会涉及到)。
然而,您可能已经意识到了使用编译器的强大功能:DFA 构造算法来负责所有状态管理。
有关 XM 有趣的反馈意见对于 XM 的状态,这里有一个快速更新。您可以回想起:XM(XSLT Make 的缩写)是“ 使用 XML”专栏中介绍的第一个项目。对于用 XML 和 XSLT 来发布网站,XM 是一个能承担此任务的解决方案。我暂停了 XM 开发是为了收集用户的反馈意见。
迄今为止,我已经在 ananas 讨论邮件列表上收到了一些反馈意见,但我还是很想收到更多来自您那里的意见,因此希望大家能自由踊跃地发表意见。在上月,我还用 XM 构建了两个新网站。第一个网站是用 XML 部分重写了 Pineapplesoft(我的咨询公司)公司的网站。第二个网站是我的一个简短的咨询任务,旨在帮助一家组织实现 XML 和 XSLT。
邮件列表和其它一些经验使我发现了几个错误,而且我已经纠正了其中的大部分。邮件列表和经验还让我更深入了解了第三方是如何部署 XM 的。这些经验还促使我要增加两个新特性:
- 现在,XM 可以选择忽略文档的外部 DTD。对于 SoftQuad XMetaL(以及可能其它的 XML 编辑器),这证明是很便利的。我发现,XMetaL 插入相对于其目录之一的路径,有一个令人遗憾的副作用:会破坏其它 XML 应用程序(包括作出这些纠正之前的 XM)。
- 现在,XM 完全支持 xsl
utput 元素。所以,可以使用 XM 来对 XML 文档进行预处理,例如,进行大量 XML 转换。
|
|
|
|
|
|
|