使用SAX在Java中解析XML:将值减少两半

Mic*_*sLE 5 java xml sax saxparser

我正在尝试读取基于xml的文件格式,并在JAVA中使用SAX称为mzXML.它携带部分编码的质谱数据(具有强度的信号).

这就是感兴趣的条目看起来像(有更多的信息):

    <peaks ... >eJwBgAN//EByACzkZJkHP/NlAceAXLJAckeQ4CIUJz/203q2...</peaks>
Run Code Online (Sandbox Code Playgroud)

可以在此处下载一个强制错误的完整文件.

其中一个条目中的String包含大约500个压缩和base64编码的双精度对(信号和强度).我所做的是解压缩和解码,以获取值(解码未在下面的示例中显示).这对小型数据集来说都很好.现在我使用了更大的一个,我遇到了一个我不理解的问题:

过程字符(ch,start,length)不会读取之前显示的行中的完整条目.该长度值似乎是小.

当我刚刚将峰值条目打印到控制台时,我没有看到这个问题,因为有很多字母而且我没有意识到字母丢失了.但是当缺少信息时,减压失败了.当我重复运行这个程序时,它总是在同一点打破同一行而不给出任何异常.如果我通过删除扫描来更改mzXML文件,它会在不同的位置中断.我在character()过程中使用断点查看currentValue的内容时发现了这一点

以下是概括问题所需的一段代码:

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;

import javax.xml.bind.DatatypeConverter;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class ReadXMLFile {

    public static byte[] decompress(byte[] data) throws IOException, DataFormatException { 
        Inflater inflater = new Inflater();  
        inflater.setInput(data); 

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length); 
        byte[] buffer = new byte[data.length*2]; 
        while (!inflater.finished()) { 
            int count = inflater.inflate(buffer); 
            outputStream.write(buffer, 0, count); 
        } 
        outputStream.close(); 
        byte[] output = outputStream.toByteArray(); 

        return output; 
    } 

    public static void main(String args[]) {

        try {

            SAXParserFactory factory = SAXParserFactory.newInstance();
            SAXParser saxParser = factory.newSAXParser();

            DefaultHandler handler = new DefaultHandler() {

                boolean peaks = false;

                public void startElement(String uri, String localName,String qName, 
                        Attributes attributes) throws SAXException {

                    if (qName.equalsIgnoreCase("PEAKS")) {
                        peaks = true;
                    }
                }

                public void endElement(String uri, String localName,
                        String qName) throws SAXException {
                    if (peaks) {peaks = false;}
                }

                public void characters(char ch[], int start, int length) throws SAXException {

                    if (peaks) {
                        String currentValue = new String(ch, start, length);
                        System.out.println(currentValue);
                        try {
                            byte[] array = decompress(DatatypeConverter.parseBase64Binary(currentValue));
                            System.out.println(array[1]);

                        } catch (IOException | DataFormatException e) {e.printStackTrace();}
                        peaks = false;
                    }
                }
            };

            saxParser.parse("file1_zlib.mzxml", handler);

        } catch (Exception e) {e.printStackTrace();}
    }

}
Run Code Online (Sandbox Code Playgroud)

是否有更安全的方式来读取大型xml文件?你能告诉我错误来自何处或如何避免错误?

谢谢,迈克尔

das*_*ght 7

该过程characters(ch,start,length)不会读取之前显示的行中的完整条目.长度值似乎很小.

这正是它被设计的方式.来自以下文件ContentHandler:

SAX解析器可以在单个块中返回所有连续的字符数据,或者它们可以将其拆分为多个块.

因此,您不应该尝试decompresscharacters实现中调用.相反,您应该将您获得的字符附加到可扩展缓冲区,并decompress仅在获得相应的时调用endElement:

StringBuilder sb = null;

public void startElement(String uri, String localName,String qName, 
    Attributes attributes) throws SAXException {
    if (qName.equalsIgnoreCase("PEAKS")) {
        sb = new StringBuilder();
    }
}

public void endElement(String uri, String localName, String qName) throws SAXException {
    if (sb == null) return;
    try {
        byte[] array = decompress(DatatypeConverter.parseBase64Binary(sb.toString()));
        System.out.println(array[1]);
    } catch (IOException | DataFormatException e) {e.printStackTrace();}
    sb = null;
}

public void characters(char ch[], int start, int length) throws SAXException {
    if (sb == null) return;
    String currentValue = new String(ch, start, length);
    sb.appens(currentValue);
}
Run Code Online (Sandbox Code Playgroud)