我们还是把上一篇中的实例放上来接着分析
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.hibernate.util.ConfigHelper;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
public class DomParseService {
public static List<Book> getBooks(InputStream inputStream) throws Exception{
List<Book> list = new ArrayList<Book>();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
//传入参数inputstream,解析指定的xml,解析完成之后会返回一个Document(这里我们可以理解成一棵树)
Document document = builder.parse(inputStream);
//或者这棵树上的元素(种类很多)
Element element = document.getDocumentElement();
NodeList bookNodes = element.getElementsByTagName("book");
for(int i=0;i<bookNodes.getLength();i++){
Element bookElement = (Element) bookNodes.item(i);
Book book = new Book();
book.setId(Integer.parseInt(bookElement.getAttribute("id")));
NodeList childNodes = bookElement.getChildNodes();
// System.out.println("*****"+childNodes.getLength());
for(int j=0;j<childNodes.getLength();j++){
if(childNodes.item(j).getNodeType()==Node.ELEMENT_NODE){
if("name".equals(childNodes.item(j).getNodeName())){
book.setName(childNodes.item(j).getFirstChild().getNodeValue());
System.out.println("nodeValue = " + childNodes.item(j).getFirstChild().getNodeValue());
}else if("price".equals(childNodes.item(j).getNodeName())){
book.setPrice(Float.parseFloat(childNodes.item(j).getFirstChild().getNodeValue()));
System.out.println("nodeValue = " + Float.parseFloat(childNodes.item(j).getFirstChild().getNodeValue()));
}
}
}//end for j
list.add(book);
}//end for i
return list;
}
public static void main(String[] args) {
InputStream inputStream = ConfigHelper.getResourceAsStream("/book.xml");
try {
getBooks(inputStream);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
上一篇中我们知道了,DocumentBuilderFactory.newInstance()最终返回的是DocumentBuilderFactoryImpl,那我们接着往下看newDocumentBuilder()方法:
/**
* Creates a new instance of a {@link javax.xml.parsers.DocumentBuilder}
* using the currently configured parameters.
*/
public DocumentBuilder newDocumentBuilder()
throws ParserConfigurationException
{
/** Check that if a Schema has been specified that neither of the schema properties have been set. */
if (grammar != null && attributes != null) {
if (attributes.containsKey(JAXPConstants.JAXP_SCHEMA_LANGUAGE)) {
throw new ParserConfigurationException(
SAXMessageFormatter.formatMessage(null,
"schema-already-specified", new Object[] {JAXPConstants.JAXP_SCHEMA_LANGUAGE}));
}
else if (attributes.containsKey(JAXPConstants.JAXP_SCHEMA_SOURCE)) {
throw new ParserConfigurationException(
SAXMessageFormatter.formatMessage(null,
"schema-already-specified", new Object[] {JAXPConstants.JAXP_SCHEMA_SOURCE}));
}
}
try {
return new DocumentBuilderImpl(this, attributes, features, fSecureProcess);
} catch (SAXException se) {
// Handles both SAXNotSupportedException, SAXNotRecognizedException
throw new ParserConfigurationException(se.getMessage());
}
}
这里我们看到最终返回的实例是DocumentBuilder的实现类DocumentBuilderImpl,所以要注意这个类中对父类的实现方法
/**
* Parse the content of the given <code>InputStream</code> as an XML
* document and return a new DOM {@link Document} object.
* An <code>IllegalArgumentException</code> is thrown if the
* <code>InputStream</code> is null.
*
* @param is InputStream containing the content to be parsed.
*
* @return <code>Document</code> result of parsing the
* <code>InputStream</code>
*
* @throws IOException If any IO errors occur.
* @throws SAXException If any parse errors occur.
* @throws IllegalArgumentException When <code>is</code> is <code>null</code>
*
* @see org.xml.sax.DocumentHandler
*/
public Document parse(InputStream is)
throws SAXException, IOException {
if (is == null) {
throw new IllegalArgumentException("InputStream cannot be null");
}
InputSource in = new InputSource(is);
return parse(in);
}
/**
* Parse the content of the given input source as an XML document
* and return a new DOM {@link Document} object.
* An <code>IllegalArgumentException</code> is thrown if the
* <code>InputSource</code> is <code>null</code> null.
*
* @param is InputSource containing the content to be parsed.
*
* @return A new DOM Document object.
*
* @throws IOException If any IO errors occur.
* @throws SAXException If any parse errors occur.
* @throws IllegalArgumentException When <code>is</code> is <code>null</code>
*
* @see org.xml.sax.DocumentHandler
*/
public abstract Document parse(InputSource is)
throws SAXException, IOException;
public Document parse(InputSource is) throws SAXException, IOException {
if (is == null) {
throw new IllegalArgumentException(
DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
"jaxp-null-input-source", null));
}
if (fSchemaValidator != null) {
if (fSchemaValidationManager != null) {
fSchemaValidationManager.reset();
}
resetSchemaValidator();
}
domParser.parse(is);
return domParser.getDocument();
}
这里domParser.parse(is)调用的是XMLParser类中的方法:
/**
* parse
*
* @param inputSource
*
* @exception XNIException
* @exception java.io.IOException
*/
public void parse(XMLInputSource inputSource)
throws XNIException, IOException {
reset();
fConfiguration.parse(inputSource);
} // parse(XMLInputSource)
这里fConfiguration.parse(inputSource)方法是调用的com.sun.org.apache.xerces.internal.parsers.XML11Configuration类中的parse(XMLInputSource source)方法,为什么会调用到这里来呢,因为在实例化DOMParser对象的时候:
/**
* Constructs a DOM parser using the specified symbol table and
* grammar pool.
*/
public DOMParser(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 properties
fConfiguration.addRecognizedProperties(RECOGNIZED_PROPERTIES);
if (symbolTable != null) {
fConfiguration.setProperty(SYMBOL_TABLE, symbolTable);
}
if (grammarPool != null) {
fConfiguration.setProperty(XMLGRAMMAR_POOL, grammarPool);
}
fConfiguration.addRecognizedFeatures(RECOGNIZED_FEATURES);
} // <init>(SymbolTable,XMLGrammarPool)
因为XIncludeAwareParserConfiguration类的父类为XML11Configuration类,所以就显得清晰明了:
/**
* Parses the specified input source.
*
* @param source The input source.
*
* @exception XNIException Throws exception on XNI error.
* @exception java.io.IOException Throws exception on i/o error.
*/
public void parse(XMLInputSource source) throws XNIException, IOException {
if (fParseInProgress) {
// REVISIT - need to add new error message
throw new XNIException("FWK005 parse may not be called while parsing.");
}
fParseInProgress = true;
try {
setInputSource(source);
parse(true);
} catch (XNIException ex) {
if (PRINT_EXCEPTION_STACK_TRACE)
ex.printStackTrace();
throw ex;
} catch (IOException ex) {
if (PRINT_EXCEPTION_STACK_TRACE)
ex.printStackTrace();
throw ex;
} catch (RuntimeException ex) {
if (PRINT_EXCEPTION_STACK_TRACE)
ex.printStackTrace();
throw ex;
} catch (Exception ex) {
if (PRINT_EXCEPTION_STACK_TRACE)
ex.printStackTrace();
throw new XNIException(ex);
} finally {
fParseInProgress = false;
// close all streams opened by xerces
this.cleanup();
}
} // parse(InputSource)
这里面具体怎么实现的,我在再下一章好好研究一下。
总结:在查看源码的时候,我总是会出现找不到源码的情况,除了与jdk中版本不一致之外,还有个根本的原因就是java基础知识太差了,像什么子类可以直接使用父类的方法,子类重写父类的方法之后,程序会用到子类的方法等等这些基础的知识点,以前在学习或者面试的时候感觉那个时候都是背的,时间长了之后天天写CRUD,一致与现在都搞不清楚这些最基本也是最重要的知识点了,现在越来越觉得坚持看源码,虽然过程很痛苦,但是日积月累之后我的代码功力肯定会大大提高,加油。