💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# 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 ``` | | | | --- | --- | | \[1\] | 从创建一个空字典 `self.refs` 开始。 | | \[2\] | 正如你在[第 9.5 节 “搜索元素”](../xml_processing/searching.html "9.5. 搜索元素")中看到的,`getElementsByTagName` 返回所有特定名称元素的一个列表。你可以很容易地得到所有 `ref` 元素的一个列表,然后遍历这个列表。 | | \[3\] | 正如你在[第 9.6 节 “访问元素属性”](../xml_processing/attributes.html "9.6. 访问元素属性")中看到的,使用标准的字典语法,你可以通过名称来访问个别元素。所以,`self.refs` 字典的键将是每个 `ref` 元素的 `id` 属性值。 | | \[4\] | `self.refs` 字典的值将是 `ref` 元素本身。如你在[第 9.3 节 “XML 解析”](../xml_processing/parsing_xml.html "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` 函数。