10.3. 查询缓冲节点
Description: Python from novice to pro
Keywords: Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free

# 深入 Python :Dive Into Python 中文版 Python 从新手到专家 [Dip_5.4b_CPyUG_Release] | Find:

## 10.3. 查询缓冲节点

`kgp.py` 使用了多种技巧，在你进行 XML 处理时，它们或许能派上用场。第一个就是，利用输入文档的结构稳定特征来构建节点缓冲。

一个语法文件定义了一系列的 `ref` 元素。每个 `ref` 包含了一个或多个 `p` 元素，`p` 元素则可以包含很多不同的东西，包括 `xref`。对于每个 `xref`，你都能找到相对应的 `ref` 元素 (它们具有相同的 `id` 属性)，然后选择 `ref` 元素的子元素之一进行解析。(在下一部分中你将看到是如何进行这种随机选择的。)

语法的构建方式如下：先为最小的片段定义 `ref` 元素，然后使用 `xref` 定义“包含”第一个 `ref` 元素的 `ref` 元素，等等。然后，解析“最大的”引用并跟着 `xref` 跳来跳去，最后输出真实的文本。输出的文本依赖于你每次填充 `xref` 时所做的 (随机) 决策，所以每次的输出都是不同的。

这种方式非常灵活，但是有一个不好的地方：性能。当你找到一个 `xref` 并需要找到相应的 `ref` 元素时，会遇到一个问题。`xref` 有 `id` 属性，而你要找拥有相同 `id` 属性的 `ref` 元素，但是没有简单的方式做到这件事。较慢的方式是每次获取所有 `ref` 元素的完整列表，然后手动遍历并检视每一个 `id` 属性。较快的方式是只做一次，然后以字典形式构建一个缓冲。

### 例 10.14. `loadGrammar`

        def loadGrammar(self, grammar):
            self.grammar = self._load(grammar)
            self.refs = {}
            for ref in self.grammar.getElementsByTagName("ref"):
                self.refs[ref.attributes["id"].value] = ref

| 从创建一个空字典 `self.refs` 开始。
| 正如你在第 9.5 节 “搜索元素”中看到的，`getElementsByTagName` 返回所有特定名称元素的一个列表。你可以很容易地得到所有 `ref` 元素的一个列表，然后遍历这个列表。
| 正如你在第 9.6 节 “访问元素属性”中看到的，使用标准的字典语法，你可以通过名称来访问个别元素。所以，`self.refs` 字典的键将是每个 `ref` 元素的 `id` 属性值。
| `self.refs` 字典的值将是 `ref` 元素本身。如你在第 9.3 节 “XML 解析”中看到的，已解析 XML 文档中的每个元素、节点、注释和文本片段都是一个对象。

只要构建了这个缓冲，无论何时你遇到一个 `xref` 并且需要找到具有相同 `id` 属性的 `ref` 元素，都只需在 `self.refs` 中查找它。

### 例 10.15. 使用 `ref` 元素缓冲

        def do_xref(self, node):
            id = node.attributes["id"].value
            self.parse(self.randomChildElement(self.refs[id]))

你将在下一部分探究 `randomChildElement` 函数。