java - 从 JAXP SAX ContentHandler 发出 XML 的最节省内存的方法是什么?

标签 java xml-serialization sax jaxp

我的情况类似于an earlier question about emitting XML .我正在分析 SAX ContentHandler 中的数据,同时将其序列化为流。我怀疑链接问题中的解决方案——尽管它正是我在 API 方面寻找的——内存效率不高,因为它涉及 XSLT 处理器的身份转换。我希望程序的内存消耗受到限制,而不是随着输入大小而增长。

我怎样才能轻松地将参数转发到我的 ContentHandler 方法到序列化程序,而不用做杂技来适应,例如StAX 到 SAX,或者更糟,将 SAX 事件内容复制到输出流?

编辑:这是我所追求的一个最小示例。 thingIWant 应该只写入给它的 OutputStream。就像我说的,前面的问题有一个 TransformerHandler,它为我提供了正确的 API,但它使用 XSLT 处理器而不是简单的序列化。

public class MyHandler implements ContentHandler {

    ContentHandler thingIWant;

    MyHandler(OutputStream outputStream) {
        thingIWant = setup(outputStream);
    }

    public void startDocument() throws SAXException {
        // parsing logic
        thingIWant.startDocument();
    }

    public void startElement(String uri, String localName, String qName,
                             Attributes atts) throws SAXException {
        // parsing logic
        thingIWant.startElement(uri, localName, qName, atts);
    }

    public void characters(char[] ch, int start, int length) throws SAXException {
        // parsing logic
        thingIWant.characters(ch, start, length);
    }

    // etc...
 }

最佳答案

我最近遇到了类似的问题。这是我为获得 thingIWant 而编写的类:

import java.io.OutputStream;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerException;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamResult;
import org.xml.sax.*;

public class XMLSerializer implements ContentHandler {
    static final private TransformerFactory tf = TransformerFactory.newInstance();
    private ContentHandler ch;

    public XMLSerializer(OutputStream os) throws SAXException {
        try {
            final Transformer t = tf.newTransformer();

            t.transform(new SAXSource(                
                new XMLReader() {     
                    public ContentHandler getContentHandler() { return ch; }
                    public DTDHandler getDTDHandler() { return null; }      
                    public EntityResolver getEntityResolver() { return null; }
                    public ErrorHandler getErrorHandler() { return null; }    
                    public boolean getFeature(String name) { return false; }
                    public Object getProperty(String name) { return null; } 
                    public void parse(InputSource input) { }               
                    public void parse(String systemId) { }  
                    public void setContentHandler(ContentHandler handler) { ch = handler; }                
                    public void setDTDHandler(DTDHandler handler) { }
                    public void setEntityResolver(EntityResolver resolver) { }
                    public void setErrorHandler(ErrorHandler handler) { }
                    public void setFeature(String name, boolean value) { }
                    public void setProperty(String name, Object value) { }
                }, new InputSource()),                                    
                new StreamResult(os));
        }
        catch (TransformerException e) {
            throw new SAXException(e);  
        }

        if (ch == null)
            throw new SAXException("Transformer didn't set ContentHandler");
    }

    public void setDocumentLocator(Locator locator) {
        ch.setDocumentLocator(locator);
    }

    public void startDocument() throws SAXException {
        ch.startDocument();
    }

    public void endDocument() throws SAXException {
        ch.endDocument();
    }

    public void startPrefixMapping(String prefix, String uri) throws SAXException {
        ch.startPrefixMapping(prefix, uri);
    }

    public void endPrefixMapping(String prefix) throws SAXException {
        ch.endPrefixMapping(prefix);
    }

    public void startElement(String uri, String localName, String qName, Attributes atts)
        throws SAXException {
        ch.startElement(uri, localName, qName, atts);
    }

    public void endElement(String uri, String localName, String qName)
        throws SAXException {
        ch.endElement(uri, localName, qName);
    }

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

    public void ignorableWhitespace(char[] ch, int start, int length)
        throws SAXException {
        this.ch.ignorableWhitespace(ch, start, length);
    }

    public void processingInstruction(String target, String data)
        throws SAXException {
        ch.processingInstruction(target, data);
    }

    public void skippedEntity(String name) throws SAXException {
        ch.skippedEntity(name);
    }
}

基本上,它会拦截 Transformer 对 parse() 的调用,并获取对其内部 ContentHandler 的引用。之后,该类充当被阻塞的 ContentHandler 的代理。

不是很干净,但是可以用。

关于java - 从 JAXP SAX ContentHandler 发出 XML 的最节省内存的方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1977504/

相关文章:

c# - 将类序列化为 XML 并包含 CDATA 部分时出现问题

java - 应用引擎 : monitor dashboard from another app

java - 在 JPA/EclipseLink EntityManager 中更改隔离级别后进行清理

java - 保存时构建和部署

.net - 包含无效字符的对象的 XML 序列化

Java XML Parser——如何收集或统计某个标签

java - 如何在 Java 中读取和验证文本文件中一行文本的不同部分?

java - 在 Accept header 中指定 application/xml 时出现 HttpMediaTypeNotAcceptableException

java - 如何解析 cvc-pattern-valid : Value '' is not facet-valid with respect to pattern problem

Android SAX 解析 : How to Preserve Newlines from within a CDATA Tag