📄 saxchunkproducer.java
字号:
// You can redistribute this software and/or modify it under the terms of// the Ozone Library License version 1 published by ozone-db.org.//// The original code and portions created by SMB are// Copyright (C) 1997-2000 by SMB GmbH. All rights reserved.//// $Id: SAXChunkProducer.java,v 1.14 2000/11/09 14:38:18 daniela Exp $package org.ozoneDB.xml.util;import java.io.IOException;import java.io.Serializable;import org.ozoneDB.DxLib.DxDeque;import org.ozoneDB.DxLib.DxArrayDeque;import org.w3c.dom.Node;import org.w3c.dom.Document;import org.w3c.dom.Element;import org.w3c.dom.NamedNodeMap;import org.xml.sax.ContentHandler;import org.xml.sax.Attributes;import org.xml.sax.Locator;import org.xml.sax.SAXException;import org.xml.sax.helpers.AttributesImpl;/** * This class produces a sequence of {@link SAXEventChunk}s out of SAX events or * out of a DOM tree. These chunks are used to communicate between client and * server. * * * @version $Revision: 1.14 $ $Date: 2000/11/09 14:38:18 $ * @author <a href="http://www.smb-tec.com">SMB</a> */public final class SAXChunkProducer implements ContentHandler, Serializable { // Constants private final static boolean debug = false; private final static int DEFAULT_CHUNK_SIZE = 100000; private final static int DEFAULT_CHUNK_INCREASE = 4096; /** the default state */ private final static int CHUNK_STATE_INVALID = -1; /** the initial state */ private final static int CHUNK_STATE_INIT = 0; /** a new node has to be processed */ private final static int CHUNK_STATE_NODE = 1; /** next step is to close an element (or document) */ private final static int CHUNK_STATE_CLOSE = 3; /** conversion was finished. i.e. there are no more events to throw */ private final static int CHUNK_STATE_FINISH = 4; // Data /** * Used for SAX storage. Because chunk processing is done using * {@link SAXChunkProducerDelegate} (which means consumer creation and * consumer usage happens in different methods) the consumer has to be * stored somewhere. I choose the corresponding producer. */ public SAXChunkConsumer dbConsumer; private final SAXChunkProducerDelegate delegate; private final ChunkOutputStream chunkOutput; private final CXMLContentHandler contentHandler; /** * True if all descendant children shall be traversed, false otherwise. * @see #depth */ private final boolean deep; /** * The depth of the traversal. If {@link #deep} is false this determines * how deep descendant shall be traversed, otherwise this member is ignored. */ private int depth; private int processLevel = 0; /** * Keeps information about which nodes have already been opened. * (used by {@link nextChunk(ContentHandler, int) nextChunk}) */ private final DxDeque endEvents; /** * The node that has to be converted next; used by * {@link nextChunk(ContentHandler, int) nextChunk}. This has to be initialized to * the start node before calling nextChunk() the first time. */ private Node nextNode; /** * implies that the node to be converted was created by a DOM Level 2 * implementation. * used by {@link nextChunk(ContentHandler, int) nextChunk}. */ private final boolean domLevel2; /** * the state of the {@link nextChunk(ContentHandler, int) nextChunk} method * @see #CHUNK_STATE_INVALID * @see #CHUNK_STATE_INIT * @see #CHUNK_STATE_NODE * @see #CHUNK_STATE_CLOSE */ private int chunkState = CHUNK_STATE_INVALID; /** */ public SAXChunkProducer( Node node ) throws IOException{ this( node, SAXChunkProducer.DEFAULT_CHUNK_SIZE, -1 ); } /** */ public SAXChunkProducer( Node node, int _depth ) throws IOException{ this( node, SAXChunkProducer.DEFAULT_CHUNK_SIZE, _depth ); } /** */ public SAXChunkProducer( Node _node, int _maxParts, int _depth ) throws IOException{ this.deep = _depth < 0; this.depth = _depth < 0 ? 0 : _depth; this.delegate = null; this.nextNode = _node; this.chunkState = CHUNK_STATE_NODE; this.endEvents = new DxArrayDeque(); Document factory = (Document)(_node.getNodeType() == Node.DOCUMENT_NODE ? _node : _node.getOwnerDocument()); this.domLevel2 = factory.getImplementation().hasFeature( "XML", "2.0" ); this.chunkOutput = new ChunkOutputStream( SAXChunkProducer.DEFAULT_CHUNK_SIZE, SAXChunkProducer.DEFAULT_CHUNK_INCREASE ); this.contentHandler = new CXMLContentHandler( this.chunkOutput ); } /** */ public SAXChunkProducer( SAXChunkProducerDelegate _delegate ) throws IOException{ this( _delegate, SAXChunkProducer.DEFAULT_CHUNK_SIZE, -1 ); } /** */ public SAXChunkProducer( SAXChunkProducerDelegate _delegate, int _depth ) throws IOException{ this( _delegate, SAXChunkProducer.DEFAULT_CHUNK_SIZE, _depth ); } /** */ public SAXChunkProducer( SAXChunkProducerDelegate _delegate, int _maxParts, int _depth ) throws IOException{ this.deep = _depth == -1; this.depth = this.deep ? 0 : _depth; this.delegate = _delegate; this.chunkOutput = new ChunkOutputStream( SAXChunkProducer.DEFAULT_CHUNK_SIZE, SAXChunkProducer.DEFAULT_CHUNK_INCREASE ); this.contentHandler = new CXMLContentHandler( this.chunkOutput ); this.domLevel2 = false; this.endEvents = null; } /** * @return the data of the chunk created during the last call of * {@link #createNextChunk()}. */ public ChunkOutputStream chunkStream() throws SAXException { return this.chunkOutput; } /** * Converts a given DOM tree in multiple steps to SAX events. * Every call throws the specified number of events (or less, if the * conversion is finished). * Before calling this method the first time {@link #nextNode nextNode} has to * be set to the root node of the DOM tree to convert, and * {@link #chunkState} has to be set to * {@link #CHUNK_STATE_INIT}. (The same way you can reset the nextChunk * context.) * * @param _contentHandler SAX content handler that receives the events * @param _eventsToThrow the number of events to throw * @return true if there are still events to throw, false if processing has * finished * @throws SAXException * @throws IllegalStateException if {@link #chunkState} has * not been set or has been set to an unknown value. * @throws IllegalArgumentException if the value of _eventsToThrow was * equal or less than 0. */ public final void createNextChunk() throws SAXException { String uri; String qName; String lName; chunkOutput.reset(); while (chunkOutput.getState() != ChunkOutputStream.STATE_OVERFLOW && chunkState != CHUNK_STATE_FINISH) { //throw events until the chunk is filled switch (chunkState) { case CHUNK_STATE_NODE: switch (nextNode.getNodeType()) { case Node.DOCUMENT_NODE: contentHandler.startDocument(); depth -= deep ? 0 : 1; endEvents.push( nextNode ); //any children to process ? nextNode = nextNode.getFirstChild(); chunkState = ((nextNode == null) || (depth < 0)) ? CHUNK_STATE_CLOSE : CHUNK_STATE_NODE; nextNode = (chunkState == CHUNK_STATE_CLOSE) ? (Node)endEvents.pop() : nextNode; break; case Node.ELEMENT_NODE: Element elem = (Element)nextNode; Attributes saxAttr = createSAXAttributes(elem); uri = domLevel2 ? elem.getNamespaceURI() : ""; qName = elem.getNodeName(); lName = domLevel2 ? elem.getLocalName() : qName; contentHandler.startElement( uri == null ? "" : uri, lName == null ? qName : lName, qName, saxAttr ); endEvents.push(nextNode); depth -= deep ? 0 : 1; nextNode = nextNode.getFirstChild(); chunkState = ((nextNode == null) || (depth < 0)) ? CHUNK_STATE_CLOSE : CHUNK_STATE_NODE; nextNode = (chunkState == CHUNK_STATE_CLOSE) ? (Node)endEvents.pop() : nextNode; break; default: convertSingleEventNode( nextNode ); nextNode = nextNode.getNextSibling(); chunkState = ((nextNode != null) && (endEvents.peek() != null)) ? CHUNK_STATE_NODE : ((nextNode = (Node)endEvents.pop()) != null) ? CHUNK_STATE_CLOSE : CHUNK_STATE_FINISH; break; } break; case CHUNK_STATE_CLOSE: { switch (nextNode.getNodeType()) { case Node.ELEMENT_NODE: depth += deep ? 0 : 1; Element elem = (Element)nextNode; uri = domLevel2 ? elem.getNamespaceURI() : ""; qName = elem.getNodeName(); lName = domLevel2 ? elem.getLocalName() : qName; contentHandler.endElement(
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -