2021SC@SDUSC
xml文件夹分析(1)
JaxpSAXParser
1、总结
使用符合 JAXP 1.1 的解析器的 SAX 解析器
继承自AbstractJaxpParser
2、主要属性
//SAX 解析器工厂
protected SAXParserFactory factory;
//是否需要将命名空间也作为属性的判断标志,默认为假
protected boolean nsPrefixes = false;
//是否需要停止警告的判断标志,默认为真
protected boolean stopOnWarning = true;
//是否需要停止可恢复的错误的判断标志,默认为真
protected boolean stopOnRecoverableError = true;
//是否应该删除 start/endDTD 事件之间出现的comment事件,默认为假
protected boolean dropDtdComments = false;
//sax 解析器工厂的名称
protected String saxParserFactoryName = "javax.xml.parsers.SAXParserFactory";
3、方法
public void setDropDtdComments(boolean dropDtdComments) {
this.dropDtdComments = dropDtdComments;
}
- 是否应该删除来自 DTD 的
comment()
事件?(默认为false) - 因为无论如何这个实现都不支持DeclHandler 接口,所以只有来自DTD 的注释是没有用的。来自内部DTD 子集的注释事件将再次出现在序列化输出中。
public void setNsPrefixes(boolean nsPrefixes) {
this.nsPrefixes = nsPrefixes;
}
- 我们是否希望命名空间声明也作为 ‘xmlns:’ 属性? 默认为假。
- 注意:将此设置为 true 会混淆某些 XSL 处理器(例如 Saxon)
public void setSaxParserFactoryName(String saxParserFactoryName) {
this.saxParserFactoryName = saxParserFactoryName;
}
- 设置要使用的 SAXParserFactory 实现类的名称,而不是使用标准的 JAXP 机制 (
SAXParserFactory.newInstance()
) - 这允许当其中几个在类路径中可用时,明确选择要使用的 JAXP 实现
public void fatalError( final SAXParseException spe )
throws SAXException
- 接收致命错误时进行通知
public void setStopOnRecoverableError(boolean stopOnRecoverableError)
- 如果发生可恢复的错误,判断解析器是否应该停止解析, 默认为真
public void parse( final InputSource in,
final ContentHandler contentHandler,
final LexicalHandler lexicalHandler )
throws SAXException, IOException {
final XMLReader tmpReader = this.setupXMLReader();
try {
LexicalHandler theLexicalHandler = null;
if ( null == lexicalHandler
&& contentHandler instanceof LexicalHandler) {
theLexicalHandler = (LexicalHandler)contentHandler;
}
if( null != lexicalHandler ) {
theLexicalHandler = lexicalHandler;
}
if (theLexicalHandler != null) {
if (this.dropDtdComments) {
theLexicalHandler = new DtdCommentEater(theLexicalHandler);
}
tmpReader.setProperty( "http://xml.org/sax/properties/lexical-handler",
theLexicalHandler );
}
} catch( final SAXException e ) {
final String message =
"SAX2 driver does not support property: " +
"'http://xml.org/sax/properties/lexical-handler'";
this.getLogger().warn( message );
}
tmpReader.setContentHandler( contentHandler );
tmpReader.parse( in );
}
- 补充:ContentHandler
接收文档逻辑内容的通知
这是大多数 SAX 应用程序实现的主要接口:如果应用程序需要获知基本解析事件,则它实现此接口并使用 setContentHandler()
向 SAX 解析器注册一个实例。解析器使用实例报告基本的文档相关事件,如元素和字符数据的开始和结束
此界面中的事件顺序非常重要,它反映了文档本身的信息顺序。例如,元素的所有内容(字符数据、处理指令和/或子元素)将按顺序出现在 startElement 事件和相应的 endElement 事件之间
public void setContentHandler (ContentHandler handler);
- 允许应用程序注册内容事件处理程序,如果应用程序未注册内容处理程序,则 SAX 解析器报告的所有内容事件都将被静默忽略。
- 应用程序可能会在解析过程中注册一个新的或不同的处理程序,并且 SAX 解析器必须立即开始使用新的处理程序。
- 补充:LexicalHandler
这是 SAX2 的可选扩展处理程序,用于提供有关 XML 文档的词法信息,例如注释和 CDATA 节边界。 XML 阅读器不需要识别此处理程序,并且它不是仅核心 SAX2 发行版的一部分。
词法处理程序中的事件适用于整个文档,而不仅仅是文档元素,并且所有词法处理程序事件都必须出现在内容处理程序的 startDocument 和 endDocument 事件之间。
4、嵌套类
JaxpSAXParser.DtdCommentEater:
一个 LexicalHandler 实现,它去除了 startDTD 和 endDTD 之间的所有评论事件。 在所有其他情况下,事件被转发到另一个 LexicalHandler
protected static class DtdCommentEater implements LexicalHandler {
protected LexicalHandler next;
protected boolean inDTD;
public DtdCommentEater(LexicalHandler nextHandler) {
this.next = nextHandler;
}
public void startDTD (String name, String publicId, String systemId)
throws SAXException {
inDTD = true;
next.startDTD(name, publicId, systemId);
}
public void endDTD ()
throws SAXException {
inDTD = false;
next.endDTD();
}
public void startEntity (String name)
throws SAXException {
next.startEntity(name);
}
public void endEntity (String name)
throws SAXException {
next.endEntity(name);
}
public void startCDATA ()
throws SAXException {
next.startCDATA();
}
public void endCDATA ()
throws SAXException {
next.endCDATA();
}
public void comment (char ch[], int start, int length)
throws SAXException {
if (!inDTD) {
next.comment(ch, start, length);
}
}
}
包含的方法:
public void startDTD (String name, String publicId, String systemId)
throws SAXException
-
报告 DTD 声明的开始(如果存在),此方法主要用于报告 DOCTYPE 声明的开始;如果文档没有任何 DOCTYPE 声明,则不调用此方法
-
通过 DTDHandler 或 DeclHandler 事件报告的所有声明必须在 startDTD 和 endDTD 事件之间出现。可以假设声明属于内部 DTD 子集,除非它们在 startEntity 和 endEntity 事件之间出现。也应该在 startDTD 和 endDTD 事件之间,以事件出现的原始顺序(逻辑)报告 DTD 的注释和处理指令;但是,它们不需要出现在相对于 DTDHandler 或 DeclHandler 事件的正确位置
-
注意,start/endDTD 事件将出现在 ContentHandler 的 start/endDocument 事件中,并在第一个 startElement 事件之前
-
参数:
name —— 文档类型名称。
publicId —— 用于外部 DTD 子集的已声明的公共标识符,如果没有声明,则为 null。
systemId —— 用于外部 DTD 子集的已声明的系统公共标识符,如果没有声明,则为 null。(注意,这不能根据文档基 URI 解析)
public void endDTD ()
throws SAXException
- 报告 DTD 声明的结束,此方法主要用于报告 DOCTYPE 声明的结束;如果文档没有任何 DOCTYPE 声明,则不调用此方法
public void startEntity (String name)
throws SAXException
-
报告一些内部和外部 XML 实体的开始,参数实体(包括外部 DTD 子集)的报告是可选的,报告
LexicalHandler
事件的 SAX2 驱动程序不能实现它;可以使用 http://xml.org/sax/features/lexical-handler/parameter-entities 功能查询或控制参数实体的报告 -
使用其正规名称报告常规实体,参数实体具有置于其名称前的 “%”,并且外部 DTD 子集具有伪实体名 “[dtd]”
-
在 SAX2 驱动程序提供这些事件时,所有其他事件必须在开始/结束实体事件中正确嵌套。不存在对来自
DeclHandler()
或DTDHandler()
的事件进行正确排序的 附加要求 -
注意,跳过的实体将通过
skippedEntity()
(是 ContentHandler 接口的一部分)报告 -
参数:
name —— 实体的名称。如果是参数实体,则名称将以 “%” 开头,如果是外部 DTD 子集,则将是 “[dtd]”
public void startCDATA ()
throws SAXException
- 报告 CDATA 节的开始,通过常规 characters 事件报告 CDATA 节的内容;此事件仅用于报告边界
public void comment (char ch[], int start, int length)
throws SAXException
- 报告文档的任何位置的 XML 注释,此回调将用于文档元素内外的注释,包括外部 DTD 子集中的注释(如果读取)。必须在
start/endDTD
和start/endEntity
事件内部正确嵌套 DTD 中的注释(如果已使用)
-参数:
ch —— 保存注释中的字符的数组。
start —— 数组中的开始位置。
length —— 使用的数组中的字符数。