DOM解析XML(一)

来源:互联网 发布:lte优化工程师前景 编辑:程序博客网 时间:2024/05/16 05:46

1、什么是DOM

DOM-Document Object Model. 简称:文档对象模型。我听到这个词还是不知道什么意思。它其实主要用来解析XML与HTML文档。它的解析方式是一开始会加载整个XML文档,然后对这些文档进行树形结构的搭建。在实际工作中,它适合针对小而且频繁使用的XML文档。

2、新建Book.xml

<?xml version="1.0" encoding="UTF-8"?> <books>     <book id="12">         <name>thinking in java</name>         <price>85.5</price>     </book>     <book id="15">         <name>Spring in Action</name>         <price>39.0</price>     </book> </books>

3、编写简单测试例子

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 blocke.printStackTrace();}}} 

4、首先看看如何获得DocumentBuilderFactory对象,这里面用到了类加载的知识,有人说这是工作模式,实话说我没太明白啥是工厂模式,不多说,解读源码:

/**     * Obtain a new instance of a     * <code>DocumentBuilderFactory</code>. This static method creates     * a new factory instance.     * This method uses the following ordered lookup procedure to determine     * the <code>DocumentBuilderFactory</code> implementation class to     * load:     * <ul>     * <li>     * Use the <code>javax.xml.parsers.DocumentBuilderFactory</code> system     * property.     * </li>     * <li>     * Use the properties file "lib/jaxp.properties" in the JRE directory.     * This configuration file is in standard <code>java.util.Properties     * </code> format and contains the fully qualified name of the     * implementation class with the key being the system property defined     * above.     *     * The jaxp.properties file is read only once by the JAXP implementation     * and it's values are then cached for future use.  If the file does not exist     * when the first attempt is made to read from it, no further attempts are     * made to check for its existence.  It is not possible to change the value     * of any property in jaxp.properties after it has been read for the first time.     * </li>     * <li>     * Use the Services API (as detailed in the JAR specification), if     * available, to determine the classname. The Services API will look     * for a classname in the file     * <code>META-INF/services/javax.xml.parsers.DocumentBuilderFactory</code>     * in jars available to the runtime.     * </li>     * <li>     * Platform default <code>DocumentBuilderFactory</code> instance.     * </li>     * </ul>     *     * Once an application has obtained a reference to a     * <code>DocumentBuilderFactory</code> it can use the factory to     * configure and obtain parser instances.     *     *     * <h2>Tip for Trouble-shooting</h2>     * <p>Setting the <code>jaxp.debug</code> system property will cause     * this method to print a lot of debug messages     * to <code>System.err</code> about what it is doing and where it is looking at.</p>     *     * <p> If you have problems loading {@link DocumentBuilder}s, try:</p>     * <pre>     * java -Djaxp.debug=1 YourProgram ....     * </pre>     *     * @return New instance of a <code>DocumentBuilderFactory</code>     *     * @throws FactoryConfigurationError if the implementation is not     *   available or cannot be instantiated.     */    public static DocumentBuilderFactory newInstance() {        try {            return (DocumentBuilderFactory) FactoryFinder.find(                /* The default property name according to the JAXP spec */                "javax.xml.parsers.DocumentBuilderFactory",                /* The fallback implementation class name */                "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl");        } catch (FactoryFinder.ConfigurationError e) {            throw new FactoryConfigurationError(e.getException(),                                                e.getMessage());        }    }

   /**     * Finds the implementation Class object in the specified order.  Main     * entry point.     * @return Class object of factory, never null     *     * @param factoryId             Name of the factory to find, same as     *                              a property name     * @param fallbackClassName     Implementation class name, if nothing else     *                              is found.  Use null to mean no fallback.     *     * Package private so this code can be shared.     */    static Object find(String factoryId, String fallbackClassName)        throws ConfigurationError    {        dPrint("find factoryId =" + factoryId);        // Use the system property first        try {            String systemProp = ss.getSystemProperty(factoryId);            if (systemProp != null) {                dPrint("found system property, value=" + systemProp);                return newInstance(systemProp, null, true);            }        }        catch (SecurityException se) {            if (debug) se.printStackTrace();        }        // try to read from $java.home/lib/jaxp.properties        try {            String factoryClassName = null;            if (firstTime) {                synchronized (cacheProps) {                    if (firstTime) {                        String configFile = ss.getSystemProperty("java.home") + File.separator +                            "lib" + File.separator + "jaxp.properties";                        File f = new File(configFile);                        firstTime = false;                        if (ss.doesFileExist(f)) {                            dPrint("Read properties file "+f);                            cacheProps.load(ss.getFileInputStream(f));                        }                    }                }            }            factoryClassName = cacheProps.getProperty(factoryId);            if (factoryClassName != null) {                dPrint("found in $java.home/jaxp.properties, value=" + factoryClassName);                return newInstance(factoryClassName, null, true);            }        }        catch (Exception ex) {            if (debug) ex.printStackTrace();        }        // 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);        }        dPrint("loaded from fallback value: " + fallbackClassName);        return newInstance(fallbackClassName, null, true);    }

我之所以把注释都放上来,是因为我每次看完源码之后再去看这些注释,总有一种原来是这样的感觉,羡慕英文好的同学,我想他们在看源码的时候速度一般会快很多,上面真正有效执行的是最后一句:

    /**     * Create an instance of a class. Delegates to method     * <code>getProviderClass()</code> in order to load the class.     *     * @param className Name of the concrete class corresponding to the     * service provider     *     * @param cl <code>ClassLoader</code> used to load the factory class. If <code>null</code>     * current <code>Thread</code>'s context classLoader is used to load the factory class.     *     * @param doFallback True if the current ClassLoader should be tried as     * a fallback if the class is not found using cl     */    static Object newInstance(String className, ClassLoader cl, boolean doFallback)        throws ConfigurationError    {        return newInstance(className, cl, doFallback, false);    }

    /**     * Create an instance of a class. Delegates to method     * <code>getProviderClass()</code> in order to load the class.     *     * @param className Name of the concrete class corresponding to the     * service provider     *     * @param cl <code>ClassLoader</code> used to load the factory class. If <code>null</code>     * current <code>Thread</code>'s context classLoader is used to load the factory class.     *     * @param doFallback True if the current ClassLoader should be tried as     * a fallback if the class is not found using cl     *     * @param useBSClsLoader True if cl=null actually meant bootstrap classLoader. This parameter     * is needed since DocumentBuilderFactory/SAXParserFactory defined null as context classLoader.     */    static Object newInstance(String className, ClassLoader cl, boolean doFallback, boolean useBSClsLoader)        throws ConfigurationError    {        try {            Class providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader);            Object instance = providerClass.newInstance();            if (debug) {    // Extra check to avoid computing cl strings                dPrint("created new instance of " + providerClass +                       " using ClassLoader: " + cl);            }            return instance;        }        catch (ClassNotFoundException x) {            throw new ConfigurationError(                "Provider " + className + " not found", x);        }        catch (Exception x) {            throw new ConfigurationError(                "Provider " + className + " could not be instantiated: " + x,                x);        }    }

    /**     * Attempt to load a class using the class loader supplied. If that fails     * and fall back is enabled, the current (i.e. bootstrap) class loader is     * tried.     *     * If the class loader supplied is <code>null</code>, first try using the     * context class loader followed by the current (i.e. bootstrap) class     * loader.     *     * Use bootstrap classLoader if cl = null and useBSClsLoader is true     */    static private Class getProviderClass(String className, ClassLoader cl,            boolean doFallback, boolean useBSClsLoader) throws ClassNotFoundException    {        try {            if (cl == null) {                if (useBSClsLoader) {                    return Class.forName(className, true, FactoryFinder.class.getClassLoader());                } else {                    cl = ss.getContextClassLoader();                    if (cl == null) {                        throw new ClassNotFoundException();                    }                    else {                        return cl.loadClass(className);                    }                }            }            else {                return cl.loadClass(className);            }        }        catch (ClassNotFoundException e1) {            if (doFallback) {                // Use current class loader - should always be bootstrap CL                return Class.forName(className, true, FactoryFinder.class.getClassLoader());            }            else {                throw e1;            }        }    }

我们好好看看这个方法,ClassLoader是通过获取上下文Loader而来,执行完cl = ss.getContextClassLoader();之后返回的对象为:sun.misc.Launcher$AppClassLoaderw 

我在学习深入探讨java类加载器的时候,知道AppClassLoaderw 属于类加载器加载而来,在他的上面有扩展类加载器,扩展类加载器上面有引导类加载器

由于我们传入的className为:com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl,所以最终返回的对象为:DocumentBuilderFactoryImpl

我们接着把类具体加载看完:

/**     * Loads the class with the specified <a href="#name">binary name</a>.     * This method searches for classes in the same manner as the {@link     * #loadClass(String, boolean)} method.  It is invoked by the Java virtual     * machine to resolve class references.  Invoking this method is equivalent     * to invoking {@link #loadClass(String, boolean) <tt>loadClass(name,     * false)</tt>}.  </p>     *     * @param  name     *         The <a href="#name">binary name</a> of the class     *     * @return  The resulting <tt>Class</tt> object     *     * @throws  ClassNotFoundException     *          If the class was not found     */    public Class<?> loadClass(String name) throws ClassNotFoundException {        return loadClass(name, false);    }

    /**     * Loads the class with the specified <a href="#name">binary name</a>.  The     * default implementation of this method searches for classes in the     * following order:     *     * <p><ol>     *     *   <li><p> Invoke {@link #findLoadedClass(String)} to check if the class     *   has already been loaded.  </p></li>     *     *   <li><p> Invoke the {@link #loadClass(String) <tt>loadClass</tt>} method     *   on the parent class loader.  If the parent is <tt>null</tt> the class     *   loader built-in to the virtual machine is used, instead.  </p></li>     *     *   <li><p> Invoke the {@link #findClass(String)} method to find the     *   class.  </p></li>     *     * </ol>     *     * <p> If the class was found using the above steps, and the     * <tt>resolve</tt> flag is true, this method will then invoke the {@link     * #resolveClass(Class)} method on the resulting <tt>Class</tt> object.     *     * <p> Subclasses of <tt>ClassLoader</tt> are encouraged to override {@link     * #findClass(String)}, rather than this method.  </p>     *     * <p> Unless overridden, this method synchronizes on the result of     * {@link #getClassLoadingLock <tt>getClassLoadingLock</tt>} method     * during the entire class loading process.     *     * @param  name     *         The <a href="#name">binary name</a> of the class     *     * @param  resolve     *         If <tt>true</tt> then resolve the class     *     * @return  The resulting <tt>Class</tt> object     *     * @throws  ClassNotFoundException     *          If the class could not be found     */    protected Class<?> loadClass(String name, boolean resolve)        throws ClassNotFoundException    {        synchronized (getClassLoadingLock(name)) {            // First, check if the class has already been loaded            Class c = findLoadedClass(name);            if (c == null) {                long t0 = System.nanoTime();                try {                    if (parent != null) {                        c = parent.loadClass(name, false);                    } else {                        c = findBootstrapClassOrNull(name);                    }                } catch (ClassNotFoundException e) {                    // ClassNotFoundException thrown if class not found                    // from the non-null parent class loader                }                if (c == null) {                    // If still not found, then invoke findClass in order                    // to find the class.                    long t1 = System.nanoTime();                    c = findClass(name);                    // this is the defining class loader; record the stats                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);                    sun.misc.PerfCounter.getFindClasses().increment();                }            }            if (resolve) {                resolveClass(c);            }            return c;        }    }

 /**     * Returns the class with the given <a href="#name">binary name</a> if this     * loader has been recorded by the Java virtual machine as an initiating     * loader of a class with that <a href="#name">binary name</a>.  Otherwise     * <tt>null</tt> is returned.  </p>     *     * @param  name     *         The <a href="#name">binary name</a> of the class     *     * @return  The <tt>Class</tt> object, or <tt>null</tt> if the class has     *          not been loaded     *     * @since  1.1     */    protected final Class<?> findLoadedClass(String name) {        if (!checkName(name))            return null;        return findLoadedClass0(name);    }

    private native final Class findLoadedClass0(String name);

类具体如何加载这里由虚拟机和底层操作系统具体去做


0 0
原创粉丝点击