欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java解析xml(sax方式)

程序员文章站 2022-06-16 12:15:33
...

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