java解析xml(sax方式)

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 对象,如图(不专业的关系图)所示:
java解析xml(sax方式)_第1张图片
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);
    } // ()

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);
        }

    } // (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 类的关系(不专业的关系图)如下:
java解析xml(sax方式)_第2张图片

你可能感兴趣的:(知识点整理)