我的情况类似于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/