SAX的方式,大致步骤:
在一个public static void main(String []args)方法中所执行的步骤
使用SAXParserFactory 生成 SAXParser解析类。
创建一个 extends DefaultHandler 的类,例如ParserDefaultHandler
调用SAXParser.parse("文件路径","ParserDefaultHandler");
直接可以遍历ParserDefaultHandler得到的结果。
代码为:
public static void main(String []args) throws Exception{
SAXParserFactory saxPF = SAXParserFactory.newInstance();
SAXParser saxParser = saxPF.newSAXParser();
SaxParserHandler saxHandler = new SaxParserHandler();
saxParser.parse("fish.xml", saxHandler);
System.out.println("~~~~~共有"+saxHandler.getFishList().size()+"种鱼");
for (Fish fish : saxHandler.getFishList()) {
}
}
ParserDefaultHandler(继承DefaultHandler 的 类) 需要实现的方法:
startDocument()----开始的标识、
endDocument()-----结束的标识、
startElement(String uri, String localName, String qName, Attributes attributes)----获取相关属性的操作、
endElement(String uri,String localName,String qName)--存储相关对象的操作、
characters(char[] ch, int start, int length)-----进行取第几个值的方法、
以下为查看相关所关联的class:
在SAXParserImpl中的
1、 先调用父类SAXParser的parse(String uri, DefaultHandler dh)
它的逻辑代码:
public void parse(String uri, DefaultHandler dh)
throws SAXException, IOException {
if (uri == null) {
throw new IllegalArgumentException("uri cannot be null");
}
InputSource input = new InputSource(uri);
this.parse(input, dh);
}
2、 再执行父类的 parse(InputSource is, DefaultHandler dh)
逻辑代码为:
public void parse(InputSource is, DefaultHandler dh)
throws SAXException, IOException {
if (is == null) {
throw new IllegalArgumentException("InputSource cannot be null");
}
XMLReader reader = this.getXMLReader();---继承类实现的方法
if (dh != null) {
reader.setContentHandler(dh);
reader.setEntityResolver(dh);
reader.setErrorHandler(dh);
reader.setDTDHandler(dh);
}
reader.parse(is);
}
XMLReader reader = JAXPSAXParser类的对象
为什么 JAXPSAXParser对象 可以给 XMLReader 对象,如图(不专业的关系图)所示:
3、reader.parse(is)的源码(JAXPSAXParser类中):
public void parse(InputSource inputSource)
throws SAXException, IOException {
if (fSAXParser != null && fSAXParser.fSchemaValidator != null) {
if (fSAXParser.fSchemaValidationManager != null) {
fSAXParser.fSchemaValidationManager.reset();
}
resetSchemaValidator();
}
super.parse(inputSource);
}
4、 super.parse(inputSource)源码(于AbstractSAXParser类中):
public void parse(InputSource inputSource)
throws SAXException, IOException {
// parse document
try {
XMLInputSource xmlInputSource =
new XMLInputSource(inputSource.getPublicId(),
inputSource.getSystemId(),
null);
xmlInputSource.setByteStream(inputSource.getByteStream());
xmlInputSource.setCharacterStream(inputSource.getCharacterStream());
xmlInputSource.setEncoding(inputSource.getEncoding());
parse(xmlInputSource);
}
// wrap XNI exceptions as SAX exceptions
catch (XMLParseException e) {
Exception ex = e.getException();
if (ex == null) {
// must be a parser exception; mine it for locator info and throw
// a SAXParseException
LocatorImpl locatorImpl = new LocatorImpl() {
public String getXMLVersion() {
return fVersion;
}
// since XMLParseExceptions know nothing about encoding,
// we cannot return anything meaningful in this context.
// We *could* consult the LocatorProxy, but the
// application can do this itself if it wishes to possibly
// be mislead.
public String getEncoding() {
return null;
}
};
locatorImpl.setPublicId(e.getPublicId());
locatorImpl.setSystemId(e.getExpandedSystemId());
locatorImpl.setLineNumber(e.getLineNumber());
locatorImpl.setColumnNumber(e.getColumnNumber());
throw new SAXParseException(e.getMessage(), locatorImpl);
}
if (ex instanceof SAXException) {
// why did we create an XMLParseException?
throw (SAXException)ex;
}
if (ex instanceof IOException) {
throw (IOException)ex;
}
throw new SAXException(ex);
}
catch (XNIException e) {
Exception ex = e.getException();
if (ex == null) {
throw new SAXException(e.getMessage());
}
if (ex instanceof SAXException) {
throw (SAXException)ex;
}
if (ex instanceof IOException) {
throw (IOException)ex;
}
throw new SAXException(ex);
}
} // parse(InputSource)
5、parse(xmlInputSource); 源码:
public void parse(XMLInputSource inputSource)
throws XNIException, IOException {
reset();
fConfiguration.parse(inputSource);
} // parse(XMLInputSource)
确认fConfiguration 是调用哪一个类的方法:
初始化 SAXParserImpl 的实例的时候,调用了 SAXParserImpl(SAXParserFactoryImpl spf, Hashtable features, boolean secureProcessing);
在该构造函数中调用 xmlReader = new JAXPSAXParser(this);
则所调用的 JAXPSAXParser 构造函数为:
JAXPSAXParser(SAXParserImpl saxParser) {
super();
fSAXParser = saxParser;
}
super() 父类的构造函数(无参的构造函数调用了有参的构造函数):
public SAXParser() {
this(null, null);
} // <init>()
public SAXParser(SymbolTable symbolTable, XMLGrammarPool grammarPool) {
super((XMLParserConfiguration)ObjectFactory.createObject(
"com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration",
"com.sun.org.apache.xerces.internal.parsers.XIncludeAwareParserConfiguration"
));
// set features
fConfiguration.addRecognizedFeatures(RECOGNIZED_FEATURES);
fConfiguration.setFeature(NOTIFY_BUILTIN_REFS, true);
// set properties
fConfiguration.addRecognizedProperties(RECOGNIZED_PROPERTIES);
if (symbolTable != null) {
fConfiguration.setProperty(SYMBOL_TABLE, symbolTable);
}
if (grammarPool != null) {
fConfiguration.setProperty(XMLGRAMMAR_POOL, grammarPool);
}
} // <init>(SymbolTable,XMLGrammarPool)
调用的入参两个的构造方法中的:
super((XMLParserConfiguration)ObjectFactory.createObject(
“com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration”,
“com.sun.org.apache.xerces.internal.parsers.XIncludeAwareParserConfiguration”
));
进行初始化了 XMLParserConfiguration 的对象。
static Object createObject(String factoryId, String fallbackClassName)
throws ConfigurationError {
return createObject(factoryId, null, fallbackClassName);//传入的是所对应的父类,以及所需要传回的实际的类
} // createObject(String,String):Object
static Object createObject(String factoryId,
String propertiesFilename,
String fallbackClassName)
throws ConfigurationError
{
if (DEBUG) debugPrintln("debug is on");
SecuritySupport ss = SecuritySupport.getInstance();
ClassLoader cl = findClassLoader();
// Use the system property first
try {
String systemProp = ss.getSystemProperty(factoryId);// 此处运用的一个方法是查找系统属性,一般是jvm系统属性,该传参为"com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration",则获取到的是 null
if (systemProp != null) {
if (DEBUG) debugPrintln("found system property, value=" + systemProp);
return newInstance(systemProp, cl, true);
}
} catch (SecurityException se) {
// Ignore and continue w/ next location
}
// JAXP specific change
// always use fallback class to avoid the expense of constantly
// "stat"ing a non-existent "xerces.properties" and jar SPI entry
// see CR 6400863: Expensive creating of SAX parser in Mustang
if (true) { //这里根据所传入的 所需返回的类的参数 进行返回所需的类的实例
if (fallbackClassName == null) {
throw new ConfigurationError(
"Provider for " + factoryId + " cannot be found", null);
}
if (DEBUG) debugPrintln("using fallback, value=" + fallbackClassName);
return newInstance(fallbackClassName, cl, true);
}
//接下来根据propertiesFilename 参数进行获取
// Try to read from propertiesFilename, or $java.home/lib/xerces.properties
String factoryClassName = null;
// no properties file name specified; use $JAVA_HOME/lib/xerces.properties:
if (propertiesFilename == null) {
File propertiesFile = null;
boolean propertiesFileExists = false;
try {
String javah = ss.getSystemProperty("java.home");
propertiesFilename = javah + File.separator +
"lib" + File.separator + DEFAULT_PROPERTIES_FILENAME;
propertiesFile = new File(propertiesFilename);
propertiesFileExists = ss.getFileExists(propertiesFile);
} catch (SecurityException e) {
// try again...
fLastModified = -1;
fXercesProperties = null;
}
synchronized (ObjectFactory.class) {
boolean loadProperties = false;
FileInputStream fis = null;
try {
// file existed last time
if(fLastModified >= 0) {
if(propertiesFileExists &&
(fLastModified < (fLastModified = ss.getLastModified(propertiesFile)))) {
loadProperties = true;
} else {
// file has stopped existing...
if(!propertiesFileExists) {
fLastModified = -1;
fXercesProperties = null;
} // else, file wasn't modified!
}
} else {
// file has started to exist:
if(propertiesFileExists) {
loadProperties = true;
fLastModified = ss.getLastModified(propertiesFile);
} // else, nothing's changed
}
if(loadProperties) {
// must never have attempted to read xerces.properties before (or it's outdeated)
fXercesProperties = new Properties();
fis = ss.getFileInputStream(propertiesFile);
fXercesProperties.load(fis);
}
} catch (Exception x) {
fXercesProperties = null;
fLastModified = -1;
// assert(x instanceof FileNotFoundException
// || x instanceof SecurityException)
// In both cases, ignore and continue w/ next location
}
finally {
// try to close the input stream if one was opened.
if (fis != null) {
try {
fis.close();
}
// Ignore the exception.
catch (IOException exc) {}
}
}
}
if(fXercesProperties != null) {
factoryClassName = fXercesProperties.getProperty(factoryId);
}
} else {
FileInputStream fis = null;
try {
fis = ss.getFileInputStream(new File(propertiesFilename));
Properties props = new Properties();
props.load(fis);
factoryClassName = props.getProperty(factoryId);
} catch (Exception x) {
// assert(x instanceof FileNotFoundException
// || x instanceof SecurityException)
// In both cases, ignore and continue w/ next location
}
finally {
// try to close the input stream if one was opened.
if (fis != null) {
try {
fis.close();
}
// Ignore the exception.
catch (IOException exc) {}
}
}
}
if (factoryClassName != null) {
if (DEBUG) debugPrintln("found in " + propertiesFilename + ", value=" + factoryClassName);
return newInstance(factoryClassName, cl, true);
}
// Try Jar Service Provider Mechanism
Object provider = findJarServiceProvider(factoryId);
if (provider != null) {
return provider;
}
if (fallbackClassName == null) {
throw new ConfigurationError(
"Provider for " + factoryId + " cannot be found", null);
}
if (DEBUG) debugPrintln("using fallback, value=" + fallbackClassName);
return newInstance(fallbackClassName, cl, true);
} // createObject(String,String,String):Object
在上面 createObject(String factoryId,
String propertiesFilename,
String fallbackClassName)中所调用的SecuritySupport的 getSystemProperty方法
String getSystemProperty(final String propName) {
return (String)
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
return System.getProperty(propName);//该方法是获取系统属性
}
});
}
调用的 AccessController中的 public static native T doPrivileged(PrivilegedAction action);// native的修饰,则表示外部定义.
则 获取到的实例为 XIncludeAwareParserConfiguration 类的。它与XMLParserConfiguration 类的关系(不专业的关系图)如下: