SAX XML 解析器抛出空指针异常

Posted

技术标签:

【中文标题】SAX XML 解析器抛出空指针异常【英文标题】:SAX XML Parser throwing Null Pointer Exception 【发布时间】:2012-02-04 09:02:05 【问题描述】:

我正在尝试用 Java 编写一个 SAX XML 解析器,但我不断收到一个空指针异常,我似乎无法弄清楚如何修复。这是堆栈跟踪:

Exception in thread "main" java.lang.NullPointerException
    at SAXParserExample.endElement(SAXParserExample.java:91)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
    at javax.xml.parsers.SAXParser.parse(Unknown Source)
    at javax.xml.parsers.SAXParser.parse(Unknown Source)
    at SAXParserExample.parseDocument(SAXParserExample.java:43)
    at SAXParserExample.runExample(SAXParserExample.java:29)
    at SAXParserExample.main(SAXParserExample.java:107)

这是 SAX 解析器的主要类:

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.SAXException;

import org.xml.sax.helpers.DefaultHandler;

public class SAXParserExample extends DefaultHandler

    List<DataRow> myFiles;

    private String tempVal;

    //to maintain context
    private DataRow tempFile;


    public SAXParserExample()
        myFiles = new ArrayList<DataRow>();
    

    public void runExample() 
        parseDocument();
        printData();
    

    private void parseDocument() 

        //get a factory
        SAXParserFactory spf = SAXParserFactory.newInstance();
        try 

            //get a new instance of parser
            SAXParser sp = spf.newSAXParser();

            //parse the file and also register this class for call backs
            sp.parse("./src/filelist.xml", this);

        catch(SAXException se) 
            se.printStackTrace();
        catch(ParserConfigurationException pce) 
            pce.printStackTrace();
        catch(IOException ie) 
            ie.printStackTrace();
        
    

    /**
     * Iterate through the list and print
     * the contents
     */
    private void printData()

        System.out.println("No of Files '" + myFiles.size() + "'.");

        Iterator<DataRow> it = myFiles.iterator();
        while(it.hasNext()) 
            System.out.println(it.next().toString());
        
    


    //Event Handlers
    public void startElement(String uri, String localName, String qName) throws SAXException 
        //reset
        tempVal = "";
        if(qName.equalsIgnoreCase("DATAROW")) 
            //create a new instance of Datarow
            tempFile = new DataRow();
        
    


    public void characters(char[] ch, int start, int length) throws SAXException 
        tempVal = new String(ch,start,length);
    

    public void endElement(String uri, String localName, String qName) throws SAXException 

        if(qName.equalsIgnoreCase("DATAROW")) 
            //add it to the list
            myFiles.add(tempFile);

        else if (qName.equalsIgnoreCase("ID")) 
            tempFile.setID(Integer.parseInt(tempVal));
        else if (qName.equalsIgnoreCase("FILENAME")) 
            tempFile.setFileName(tempVal);
        else if (qName.equalsIgnoreCase("SEARCHKEY")) 
            tempFile.setSearchKey(tempVal);
        else if (qName.equalsIgnoreCase("DATEADDED")) 
            tempFile.setDateAdded(tempVal);
        else if (qName.equalsIgnoreCase("APPLICATIONID")) 
            tempFile.setApplicationID(tempVal);
        else if (qName.equalsIgnoreCase("DISPLAYFILENAME")) 
            tempFile.setDisplayFileName(tempVal);
        
    

    public static void main(String[] args)
        SAXParserExample spe = new SAXParserExample();
        spe.runExample();
    

这里是主类中使用的DataRow类:

public class DataRow 

    private String fileName = "", searchKey = "", dateAdded = "", applicationID = "", displayFileName = "";

    private int id = 0;

    public DataRow()

    

    public DataRow(int id, String fileName, String searchKey, String dateAdded, String applicationID, String displayFileName) 
        this.id  = id;
        this.fileName = fileName;
        this.searchKey = searchKey;
        this.dateAdded = dateAdded;
        this.applicationID = applicationID;
        this.displayFileName = displayFileName;

    
    public String getFileName() 
        return fileName;
    

    public void setFileName(String fileName) 
        this.fileName = fileName;
    

    public int getID() 
        return id;
    

    public void setID(int id) 
        this.id = id;
    

    public String getSearchKey() 
        return searchKey;
    

    public void setSearchKey(String searchKey) 
        this.searchKey = searchKey;
    

    public String getDateAdded() 
        return dateAdded;
    

    public void setDateAdded(String dateAdded) 
        this.dateAdded = dateAdded;
       

    public String getApplicationID() 
        return applicationID;
    

    public void setApplicationID(String applicationID) 
        this.applicationID = applicationID;
    

    public String getDisplayFileName() 
        return displayFileName;
    

    public void setDisplayFileName(String displayFileName) 
        this.displayFileName = displayFileName;
    

    public String toString() 
        StringBuffer sb = new StringBuffer();
        sb.append("File Details - ");
        sb.append("ID:" + getID());
        sb.append(", ");
        sb.append("Filename:" + getFileName());
        sb.append(", ");
        sb.append("Search Key:" + getSearchKey());
        sb.append(", ");
        sb.append("Date Added:" + getDateAdded());
        sb.append(", ");
        sb.append("Application ID:" + getApplicationID());
        sb.append(", ");
        sb.append("Display Filename:" + getDisplayFileName());
        sb.append(".");

        return sb.toString();
    

这是我试图解析的 XML 文件:

<DATAROW><ID>61</ID><FILENAME>TestFile.txt</FILENAME><SEARCHKEY>12345</SEARCHKEY><DATEADDED>2012-1-6 9.12.32.0</DATEADDED><APPLICATIONID>PCIS</APPLICATIONID><DISPLAYFILENAME>TestFile.txt</DISPLAYFILENAME></DATAROW><DATAROW><ID>44</ID><FILENAME>TestFile.txt</FILENAME><SEARCHKEY>12345</SEARCHKEY><DATEADDED>2012-2-5 14.39.50.0</DATEADDED><APPLICATIONID>PCIS</APPLICATIONID><DISPLAYFILENAME>TestFile.txt</DISPLAYFILENAME></DATAROW>

XML 文件采用这种格式,因为最终它将解析从数据库以单个字符串形式返回的元数据。

【问题讨论】:

【参考方案1】:

好的,我已经费心数了几行,91 是这一行:

tempFile.setID(Integer.parseInt(tempVal));

所以tempFilenull

【讨论】:

myFiles 在构造函数中被初始化。【参考方案2】:

从异常中您可以看出您正在尝试取消引用值为 null 的变量。为什么不查看第 91 行并打印出所有用于查看哪些为空的变量。我的猜测是 tempFile 从未被分配,这意味着它在第 91 行为空。

【讨论】:

【参考方案3】:

我已经有一段时间没有使用 SAX,所以可能是错误的,但我的猜测是你应该在这里使用 localName,而不是 qname,因为没有限定名称(即有一些XML 中的命名空间,例如 'namespace:name')。因此,很可能提供的 qname 为 null,并且由于您访问它进行比较,因此您获得了 NPE。

根据 javadoc (http://docs.oracle.com/javase/1.4.2/docs/api/org/xml/sax/helpers/DefaultHandler.html#endElement(java.lang.String, java. lang.String, java.lang.String) ),如果提供的 qname 在 XML 文档中不可用,则可能为空。

【讨论】:

【参考方案4】:

你的覆盖函数

public void startElement(String uri, String localName, String qName) throws SAXException...

应该是

public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException...

改成如下,效果很好

public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException 
        //reset
        tempVal = "";
        if(qName.equalsIgnoreCase("DATAROW")) 
            //create a new instance of Datarow
            tempFile = new DataRow();
        
    

【讨论】:

以上是关于SAX XML 解析器抛出空指针异常的主要内容,如果未能解决你的问题,请参考以下文章

为啥非空列表会抛出空指针异常?

Android Canvas drawcolor 抛出空指针异常

HashCode 抛出空指针异常

Play 2.4 Finder 抛出空指针异常

JOOQ“IN”查询抛出空指针异常

JSONObject 创建抛出空指针异常