SAX2RTFDTMpublic class SAX2RTFDTM extends SAX2DTM This is a subclass of SAX2DTM which has been modified to meet the needs of
Result Tree Frameworks (RTFs). The differences are:
1) Multiple XML trees may be appended to the single DTM. This means
that the root node of each document is _not_ node 0. Some code has
had to be deoptimized to support this mode of operation, and an
explicit mechanism for obtaining the Node Handle of the root node
has been provided.
2) A stack of these documents is maintained, allowing us to "tail-prune" the
most recently added trees off the end of the DTM as stylesheet elements
(and thus variable contexts) are exited.
PLEASE NOTE that this class may be _heavily_ dependent upon the
internals of the SAX2DTM superclass, and must be maintained in
parallel with that code. Arguably, they should be conditionals
within a single class... but they have deen separated for
performance reasons. (In fact, one could even argue about which is
the superclass and which is the subclass; the current arrangement
is as much about preserving stability of existing code during
development as anything else.)
%REVIEW% In fact, since the differences are so minor, I think it
may be possible/practical to fold them back into the base
SAX2DTM. Consider that as a future code-size optimization. |
Fields Summary |
---|
private static final boolean | DEBUGSet true to monitor SAX events and similar diagnostic info. | private int | m_currentDocumentNodeMost recently started Document, or null if the DTM is empty. | IntStack | mark_sizeTail-pruning mark: Number of nodes in use | IntStack | mark_data_sizeTail-pruning mark: Number of data items in use | IntStack | mark_char_sizeTail-pruning mark: Number of size-of-data fields in use | IntStack | mark_doq_sizeTail-pruning mark: Number of dataOrQName slots in use | IntStack | mark_nsdeclset_sizeTail-pruning mark: Number of namespace declaration sets in use
%REVIEW% I don't think number of NS sets is ever different from number
of NS elements. We can probabably reduce these to a single stack and save
some storage. | IntStack | mark_nsdeclelem_sizeTail-pruning mark: Number of naespace declaration elements in use
%REVIEW% I don't think number of NS sets is ever different from number
of NS elements. We can probabably reduce these to a single stack and save
some storage. | int | m_emptyNodeCountTail-pruning mark: initial number of nodes in use | int | m_emptyNSDeclSetCountTail-pruning mark: initial number of namespace declaration sets | int | m_emptyNSDeclSetElemsCountTail-pruning mark: initial number of namespace declaration elements | int | m_emptyDataCountTail-pruning mark: initial number of data items in use | int | m_emptyCharsCountTail-pruning mark: initial number of characters in use | int | m_emptyDataQNCountTail-pruning mark: default initial number of dataOrQName slots in use |
Constructors Summary |
---|
public SAX2RTFDTM(DTMManager mgr, Source source, int dtmIdentity, DTMWSFilter whiteSpaceFilter, XMLStringFactory xstringfactory, boolean doIndexing)
super(mgr, source, dtmIdentity, whiteSpaceFilter,
xstringfactory, doIndexing);
// NEVER track source locators for RTFs; they aren't meaningful. I think.
// (If we did track them, we'd need to tail-prune these too.)
//com.sun.org.apache.xalan.internal.processor.TransformerFactoryImpl.m_source_location;
m_useSourceLocationProperty=false;
m_sourceSystemId = (m_useSourceLocationProperty) ? new StringVector()
: null;
m_sourceLine = (m_useSourceLocationProperty) ? new IntVector() : null;
m_sourceColumn = (m_useSourceLocationProperty) ? new IntVector() : null;
// Record initial sizes of fields that are pushed and restored
// for RTF tail-pruning. More entries can be popped than pushed, so
// we need this to mark the primordial state of the DTM.
m_emptyNodeCount = m_size;
m_emptyNSDeclSetCount = (m_namespaceDeclSets == null)
? 0 : m_namespaceDeclSets.size();
m_emptyNSDeclSetElemsCount = (m_namespaceDeclSetElements == null)
? 0 : m_namespaceDeclSetElements.size();
m_emptyDataCount = m_data.size();
m_emptyCharsCount = m_chars.size();
m_emptyDataQNCount = m_dataOrQName.size();
|
Methods Summary |
---|
protected int | _documentRoot(int nodeIdentifier)Given a node identifier, find the owning document node. Unlike the DOM,
this considers the owningDocument of a Document to be itself. Note that
in shared DTMs this may not be zero.
if(nodeIdentifier==NULL) return NULL;
for (int parent=_parent(nodeIdentifier);
parent!=NULL;
nodeIdentifier=parent,parent=_parent(nodeIdentifier))
;
return nodeIdentifier;
| public void | endDocument()Receive notification of the end of the document.
%REVIEW% Y'know, this isn't all that much of a deoptimization. We
might want to consider folding the start/endDocument changes back
into the main SAX2DTM so we don't have to expose so many fields
(even as Protected).
charactersFlush();
m_nextsib.setElementAt(NULL,m_currentDocumentNode);
if (m_firstch.elementAt(m_currentDocumentNode) == NOTPROCESSED)
m_firstch.setElementAt(NULL,m_currentDocumentNode);
if (DTM.NULL != m_previous)
m_nextsib.setElementAt(DTM.NULL,m_previous);
m_parents = null;
m_prefixMappings = null;
m_contextIndexes = null;
m_currentDocumentNode= NULL; // no longer open
m_endDocumentOccured = true;
| public int | getDocument()Given a DTM, find the owning document node. In the case of
SAX2RTFDTM, which may contain multiple documents, this returns
the most recently started document, or null if the DTM is
empty or no document is currently under construction.
%REVIEW% Should we continue to report the most recent after
construction has ended? I think not, given that it may have been
tail-pruned.
return makeNodeHandle(m_currentDocumentNode);
| public int | getDocumentRoot(int nodeHandle)Given a node handle, find the owning document node, using DTM semantics
(Document owns itself) rather than DOM semantics (Document has no owner).
(I'm counting on the fact that getOwnerDocument() is implemented on top
of this call, in the superclass, to avoid having to rewrite that one.
Be careful if that code changes!)
for (int id=makeNodeIdentity(nodeHandle); id!=NULL; id=_parent(id)) {
if (_type(id)==DTM.DOCUMENT_NODE) {
return makeNodeHandle(id);
}
}
return DTM.NULL; // Safety net; should never happen
| public boolean | isTreeIncomplete()
return !m_endDocumentOccured;
| public boolean | popRewindMark()"Tail-pruning" support for RTFs.
This function pops the information previously saved by
pushRewindMark (which see) and uses it to discard all nodes added
to the DTM after that time. We expect that this will allow us to
reuse storage more effectively.
This is _not_ intended to be called while a document is still being
constructed -- only between endDocument and the next startDocument
%REVIEW% WARNING: This is the first use of some of the truncation
methods. If Xalan blows up after this is called, that's a likely
place to check.
%REVIEW% Our original design for DTMs permitted them to share
string pools. If there any risk that this might be happening, we
can _not_ rewind and recover the string storage. One solution
might to assert that DTMs used for RTFs Must Not take advantage
of that feature, but this seems excessively fragile. Another, much
less attractive, would be to just let them leak... Nah.
boolean top=mark_size.empty();
m_size=top ? m_emptyNodeCount : mark_size.pop();
m_exptype.setSize(m_size);
m_firstch.setSize(m_size);
m_nextsib.setSize(m_size);
m_prevsib.setSize(m_size);
m_parent.setSize(m_size);
m_elemIndexes=null;
int ds= top ? m_emptyNSDeclSetCount : mark_nsdeclset_size.pop();
if (m_namespaceDeclSets!=null) {
m_namespaceDeclSets.setSize(ds);
}
int ds1= top ? m_emptyNSDeclSetElemsCount : mark_nsdeclelem_size.pop();
if (m_namespaceDeclSetElements!=null) {
m_namespaceDeclSetElements.setSize(ds1);
}
// Values from SAX2DTM - m_data always has a reserved entry
m_data.setSize(top ? m_emptyDataCount : mark_data_size.pop());
m_chars.setLength(top ? m_emptyCharsCount : mark_char_size.pop());
m_dataOrQName.setSize(top ? m_emptyDataQNCount : mark_doq_size.pop());
// Return true iff DTM now empty
return m_size==0;
| public void | pushRewindMark()"Tail-pruning" support for RTFs.
This function pushes information about the current size of the
DTM's data structures onto a stack, for use by popRewindMark()
(which see).
%REVIEW% I have no idea how to rewind m_elemIndexes. However,
RTFs will not be indexed, so I can simply panic if that case
arises. Hey, it works...
if(m_indexing || m_elemIndexes!=null)
throw new java.lang.NullPointerException("Coding error; Don't try to mark/rewind an indexed DTM");
// Values from DTMDefaultBase
// %REVIEW% Can the namespace stack sizes ever differ? If not, save space!
mark_size.push(m_size);
mark_nsdeclset_size.push((m_namespaceDeclSets==null)
? 0
: m_namespaceDeclSets.size());
mark_nsdeclelem_size.push((m_namespaceDeclSetElements==null)
? 0
: m_namespaceDeclSetElements.size());
// Values from SAX2DTM
mark_data_size.push(m_data.size());
mark_char_size.push(m_chars.size());
mark_doq_size.push(m_dataOrQName.size());
| public void | startDocument()Receive notification of the beginning of a new RTF document.
%REVIEW% Y'know, this isn't all that much of a deoptimization. We
might want to consider folding the start/endDocument changes back
into the main SAX2DTM so we don't have to expose so many fields
(even as Protected) and carry the additional code.
// Re-initialize the tree append process
m_endDocumentOccured = false;
m_prefixMappings = new java.util.Vector();
m_contextIndexes = new IntStack();
m_parents = new IntStack();
m_currentDocumentNode=m_size;
super.startDocument();
|
|