# 处理词汇事件

> 原文： [https://docs.oracle.com/javase/tutorial/jaxp/sax/events.html](https://docs.oracle.com/javase/tutorial/jaxp/sax/events.html)

此时，您已经消化了许多 XML 概念，包括 DTD 和外部实体。您还学习了 SAX 解析器的方法。本课程的其余部分将介绍只有在编写基于 SAX 的应用程序时才需要了解的高级主题。如果您的主要目标是编写基于 DOM 的应用程序，则可以跳到[文档对象模型](../dom/index.html)。

您之前看到，如果您以 XML 格式编写文本，则需要知道自己是否在 CDATA 部分。如果是，则尖括号（&lt;）和&符号（&amp;）应该不变地输出。但是如果你不在 CDATA 部分，它们应该被预定义的实体`&amp; lt;` 和`&amp; amp;` 。但是，您如何知道您是否正在处理 CDATA 部分？

然后，如果您以某种方式过滤 XML，则需要传递注释。通常，解析器会忽略注释。你怎么能得到评论，以便你能回应他们？

本节回答了这些问题。它向您展示了如何使用 `org.xml.sax.ext.LexicalHandler` 来识别注释，CDATA 部分和对已解析实体的引用。

注释，CDATA 标记和对已解析实体的引用构成词汇信息 - 即涉及 XML 本身文本的信息，而不是 XML 的信息内容。当然，大多数应用程序仅关注 XML 文档的内容。此类应用程序不会使用 `LexicalEventListener` API。但是输出 XML 文本的应用程序会发现它非常宝贵。

* * *

**注 -** 词法事件处理是一个可选的解析器功能。解析器实现不需要支持它。 （参考实现会这样做。）本讨论假定您的解析器这样做。

* * *

## `LexicalHandler` 如何工作

要在 SAX 解析器看到词法信息时得到通知，您可以使用 `LexicalHandler` 配置作为解析器基础的 `XmlReader` 。 `LexicalHandler` 接口定义了以下事件处理方法。

`comment(String comment)`

将评论传递给应用程序。

`startCDATA()`, `endCDATA()`

告诉 CDATA 部分何时开始和结束，告诉您的应用程序下次调用`字符（）`时期望的字符类型。

`startEntity(String name)`, `endEntity(String name)`

给出已解析实体的名称。

`startDTD(String name, String publicId, String systemId)`, `endDTD()`

告知何时处理 DTD 并识别它。

要激活 Lexical Handler，您的应用程序必须扩展 `DefaultHandler` 并实现 `LexicalHandler` 接口。然后，您必须配置解析器委派给的 `XMLReader` 实例，并将其配置为将词法事件发送到词法处理程序，如下所示。

```
// ...

SAXParser saxParser = factory.newSAXParser();
XMLReader xmlReader = saxParser.getXMLReader();
xmlReader.setProperty("http://xml.org/sax/properties/lexical-handler",
                      handler); 
// ...

```

在这里，使用 `XMLReader` 类中定义的 `setProperty（）`方法配置 `XMLReader` 。作为 SAX 标准的一部分定义的属性名称是 URN， `http://xml.org/sax/properties/lexical-handler` 。

最后，添加类似下面的代码来定义将实现接口的适当方法。

```
// ...

public void warning(SAXParseException err) {
    // ...
}

public void comment(char[] ch, int start, int length) throws SAXException {
    // ...   
}

public void startCDATA() throws SAXException {
    // ...
}

public void endCDATA() throws SAXException {
    // ...
}

public void startEntity(String name) throws SAXException {
    // ...
}

public void endEntity(String name) throws SAXException {
    // ...
}

public void startDTD(String name, String publicId, String systemId)
    throws SAXException {
    // ...
}

public void endDTD() throws SAXException {
    // ...
}

private void echoText() {
    // ...
}

// ...

```

此代码将您的解析应用程序转换为词法处理程序。剩下要做的就是给这些新方法中的每一个执行一个动作。