XML解析之ContentHandler接口
程序实现ContentHandler接口并且使用 setContentHandler
方法,向 SAX 解析器注册一个实例。解析器将使用该实例报告与基本文档相关的事件,如启动和终止元素与字符数据。
此接口中的事件顺序非常重要,它本身可镜像文档中信息的顺序。例如,在 startElement 事件与相应的 endElement 事件之间,元素的所有内容(字符数据、处理指令和/ 或子元素)都将以一定顺序出现。
此接口与现在不推荐使用的 SAX 1.0 DocumentHandler 接口相似,但它增加了对名称空间和报告跳过的实体(在非验证的 XML 处理器中)的支持。
在 java.net
包中还有一个 ContentHandler
类;这意味着以下实现方法可能并非明智之举
import java.net.*;
import org.xml.sax.*;
实际上,不管怎样 "import ...*" 通常标志不简洁的编程,因此,用户应该将此作为一种功能而不是错误。
接口主要的方法
void setDocumentLocator(Locator locator)
接收用来查找 SAX 文档事件起源的对象。
强烈建议(但不是绝对需要)使用 SAX 解析器来提供定位器:如果是这样,则必须在调用 ContentHandler 接口中的任何其他方法之前调用此方法为应用程序提供定位器。
定位器允许应用程序确定任何与文档相关的事件的终止位置,即便是解析器不报告错误也是如此。通常情况下,应用程序将使用此信息报告它自己的错误(例如与应用程序的业务规则不匹配的字符内容)。由定位器返回的信息可能不足以供搜索引擎使用。
注意,该定位器仅在调用 SAX 事件回调期间,在 startDocument 返回之后,调用 endDocument 之前,返回正确的信息。应用程序不应该尝试在任何时间都使用它。
参数:
locator - 可以返回任何 SAX 文档事件位置的对象
另请参见:
Locator
void startDocument() throws SAXException
接收文档的开始的通知。在其他任何事件回调(不包括 setDocumentLocator)之前,SAX 解析器仅调用此方法一次。
抛出:
SAXException - 任何 SAX 异常,可能包装另外的异常
另请参见:endDocument()
void endDocument() throws SAXException
接收文档的结尾的通知。
在此方法的说明和 ErrorHandler.fatalError(org.xml.sax.SAXParseException) 的说明之间存在着明显的冲突。在未来的主版本中解决这一不明确问题之后,关于解析器报告 fatalError() 或抛出异常后是否调用 endDocument() 这一点,客户将会十分明确。
SAX 解析器仅调用此方法一次,并且它将是解析期间最后调用的方法。直到解析器放弃解析(由于不可恢复的错误)或到达输入的结尾时,它才可以调用此方法。
抛出:
SAXException - 任何 SAX 异常,可能包装另外的异常
另请参见:startDocument()
void startPrefixMapping(String prefix,String uri) throws SAXException
开始前缀 URI 名称空间范围映射。
此事件的信息对于常规的名称空间处理并非必需:当 http://xml.org/sax/features/namespaces 功能为 true(默认)时,SAX XML 读取器将自动替换元素和属性名称的前缀。
但是,有这样几种情况,应用程序需要在字符数据或属性值中使用前缀,但在这里,前缀不能自动地安全扩展;必要时,start/endPrefixMapping 事件将为应用程序提供所需信息,以便应用程序本身可在这些上下文中扩展前缀。
注意,不能保证 start/endPrefixMapping 事件相互之间能够正确地嵌套:所有的 startPrefixMapping 事件将在相应的 startElement 事件之前立即发生,所有的 endPrefixMapping 事件将在相应的 endElement 事件之后立即发生,但在其他情况下不能保证其顺序。
对于 "xml" 前缀,永远不应有 start/endPrefixMapping 事件,因为它是预声明的和不可改变。
参数:
prefix - 声明的名称空间前缀。对于没有前缀的默认元素名称空间,使用空字符串。
uri - 将前缀映射到的名称空间 URI
抛出:
SAXException - 客户端可能会在处理期间抛出一个异常
另请参见:
void endPrefixMapping(java.lang.String), startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
void endPrefixMapping void endPrefixMapping(String prefix) throws SAXException
结束前缀 URI 范围的映射。
详细信息请参阅 startPrefixMapping。这些事件将始终在相应的 endElement 事件之后立即发生,但在其他情况下 endPrefixMapping 事件的顺序不能保证。
参数:
prefix - 被映射的前缀。当默认的映射范围结束时,这是一个空字符串。
抛出:
SAXException - 客户端可能会在处理期间抛出一个异常
另请参见:startPrefixMapping(java.lang.String, java.lang.String), endElement(java.lang.String, java.lang.String, java.lang.String)
void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException
接收元素开始的通知。
解析器在 XML 文档中的每个元素的开始调用此方法;对于每个 startElement 事件都将有相应的 endElement 事件(即使该元素为空时)。所有元素的内容都将在相应的 endElement 事件之前顺序地报告。
此事件允许每个元素最多有以下三个名称组件:
名称空间 URI;
本地名称;和
限定(前缀)名。
可以提供它们中的部分或全部,具体如何取决于 http://xml.org/sax/features/namespaces 和 http://xml.org/sax/features/namespace-prefixes 属性的值:
当名称空间属性为 true(默认)时,名称空间 URI 和本地名称是必需项,当名称空间属性为 false 时,则为可选项(如果指定一个值,两个都必须指定);
当名称空间前缀属性为 true 时,限定名是必需项,当名称空间前缀属性为 false(默认值)时,则为可选项。
注意,所提供的属性列表仅包括具有显式值(指定的或默认的)的属性:将忽略 #IMPLIED 属性。仅在 http://xml.org/sax/features/namespace-prefixes 属性为 true (默认情况下为 false,并且对 true 值的支持是可选项)时属性列表才包括用于名称空间声明(xmlns* 属性)的属性。
与 characters() 一样,属性值可以具有需要不止一个 char 值的字符。
参数:
uri - 名称空间 URI,如果元素没有名称空间 URI,或者未执行名称空间处理,则为空字符串
localName - 本地名称(不带前缀),如果未执行名称空间处理,则为空字符串
qName - XML 标签名称
atts - 连接到元素上的属性。如果没有属性,则它将是空 Attributes 对象。在 startElement 返回后,此对象的值是未定义的
抛出:
SAXException - 任何 SAX 异常,可能包装另外的异常
另请参见:
endElement(java.lang.String, java.lang.String, java.lang.String), Attributes, AttributesImpl
void endElement(String uri,String localName,String qName) throws SAXException
接收元素结束的通知。
SAX 解析器会在 XML 文档中每个元素的末尾调用此方法;对于每个 endElement 事件都将有相应的 startElement 事件(即使该元素为空时)。
有关名称的信息,请参见 startElement。
参数:
uri - 名称空间 URI,如果元素没有名称空间 URI,或者未执行名称空间处理,则为空字符串
localName - 本地名称(不带前缀),如果未执行名称空间处理,则为空字符串
qName - 限定的 XML 名称(带前缀),如果限定名不可用,则为空字符串
抛出:
SAXException - 任何 SAX 异常,可能包装另外的异常
void characters(char[] ch, int start, int length) throws SAXException
- 接收字符数据的通知。
解析器将调用此方法来报告字符数据的每个存储块。SAX 解析器能够用单个存储块返回所有的连续字符数据,或者可以将该数据拆分成几个存储块;但是,任何单个事件中的全部字符都必须来自同一个外部实体,以便定位器能够提供有用的信息。
应用程序不能尝试在指定的范围外从数组中读取数据。
单独的字符可以由不止一个 Java
char
值组成。由于不能仅用十六位来表示字符,所以发生此情况的重要情形有两种。一种情形是,字符用代理项对 表示,使用两个特殊的 Unicode 值。此类字符在所谓的 "Astral Planes" 中,代码点在 U+FFFF 之上。另一种情形涉及到复合字符,如由一个或多个重音字符构成的基本字符。编写代码时不能假定一次读入一个
char
的算法将适用于字符单元;在某些情况下这些算法将拆分一些字符。这与在什么情况下 XML 允许有任意字符(如属性值、处理指令数据、注解以及从此方法中报告的数据)相关。通常还与 Java 代码控制国际化的文本时相关;该问题不是 XML 独有的。注意,有些解析器将使用
ignorableWhitespace
方法而不是此方法报告元素内容中的空白(验证解析器必须 这么做)。 - 参数:
ch
- 来自 XML 文档的字符start
- 数组中的开始位置length
- 从数组中读取的字符的个数 抛出:SAXException
- 任何 SAX 异常,可能包装另外的异常 另请参见:ignorableWhitespace(char[], int, int)
,Locator
void ignorableWhitespace(char ch,int start,int length) throws SAXException
接收元素内容中可忽略的空白的通知。
验证解析器必须使用此方法来报告元素内容中的每块空白(请参阅“W3C XML 1.0 Recommendation”中的 2.10 节):如果非验证解析器能够解析和使用内容模块,则这些非验证解析器也可以使用此方法。
SAX 解析器能够用单个存储块返回所有的连续空白,或者可以将该数据拆分成几个存储块;但是,任何单个事件中的全部字符都必须来自同一个外部实体,以便定位器能够提供有用的信息。
应用程序不能尝试在指定的范围外从数组中读取数据。
参数:
ch - 来自 XML 文档的字符
start - 数组中的开始位置
length - 从数组中读取的字符的个数
抛出:
SAXException - 任何 SAX 异常,可能包装另外的异常
另请参见:characters(char[], int, int)
void processingInstruction(String target,String data) throws SAXException
接收处理指令的通知。
解析器将为找到的每个处理指令调用一次此方法:注意,处理指令可以出现在主要文档元素的前面或后面。
SAX 解析器必须从不使用此方法报告 XML 声明(XML 1.0 的 2.8 节)或文本声明(XML 1.0 的 4.3.1 节)。
与 characters() 一样,处理指令数据可以具有需要不止一个 char 值的字符。
参数:
target - 处理指令目标
data - 处理指令数据,如果未提供,则为 null。该数据不包括将其与目标分开的任何空白
抛出:
SAXException - 任何 SAX 异常,可能包装另外的异常。
void skippedEntity(String name) throws SAXException
接收跳过的实体的通知。将不为标记结构(如元素开始标记或标记声明)内的实体引用调用此方法。(XML 建议书要求报告所跳过的外部实体。SAX 还报告内部实体扩展 / 非扩展,但不包括在标记结构内部。)
解析器将在每次跳过实体时调用此方法。如果非验证处理器尚未看到声明,则可以跳过实体(例如,因为该实体在外部 DTD 子集中声明)。所有的处理器都可以跳过外部实体,但具体情况取决于 http://xml.org/sax/features/external-general-entities 和 http://xml.org/sax/features/external-parameter-entities 属性的值。
参数:
name - 所跳过的实体的名称。如果它是参数实体,则名称将以 '%' 开头,如果它是外部 DTD 子集,则将是字符串 "[dtd]"
抛出:
SAXException - 任何 SAX 异常,可能包装另外的异常