/* * Copyright 2001-2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * $Id: MultiDOM.java,v 1.31 2004/02/16 22:54:59 minchau Exp $ */ package com.sun.org.apache.xalan.internal.xsltc.dom; import com.sun.org.apache.xalan.internal.xsltc.DOM; import com.sun.org.apache.xalan.internal.xsltc.StripFilter; import com.sun.org.apache.xml.internal.serializer.SerializationHandler; import com.sun.org.apache.xalan.internal.xsltc.TransletException; import com.sun.org.apache.xalan.internal.xsltc.runtime.BasisLibrary; import com.sun.org.apache.xalan.internal.xsltc.runtime.Hashtable; import com.sun.org.apache.xml.internal.dtm.DTM; import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; import com.sun.org.apache.xml.internal.dtm.DTMManager; import com.sun.org.apache.xml.internal.dtm.ref.DTMAxisIteratorBase; import com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBase; import com.sun.org.apache.xml.internal.utils.SuballocatedIntVector; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * @author Jacek Ambroziak * @author Morten Jorgensen * @author Erwin Bolwidt */ public final class MultiDOM implements DOM { private static final int NO_TYPE = DOM.FIRST_TYPE - 2; private static final int INITIAL_SIZE = 4; private DOM[] _adapters; private DOMAdapter _main; private DTMManager _dtmManager; private int _free; private int _size; private Hashtable _documents = new Hashtable(); private final class AxisIterator extends DTMAxisIteratorBase { // constitutive data private final int _axis; private final int _type; // implementation mechanism private DTMAxisIterator _source; private int _dtmId = -1; public AxisIterator(final int axis, final int type) { _axis = axis; _type = type; } public int next() { if (_source == null) { return(END); } return _source.next(); } public void setRestartable(boolean flag) { if (_source != null) { _source.setRestartable(flag); } } public DTMAxisIterator setStartNode(final int node) { if (node == DTM.NULL) { return this; } int dom = node >>> DTMManager.IDENT_DTM_NODE_BITS; // Get a new source first time and when mask changes if (_source == null || _dtmId != dom) { if (_type == NO_TYPE) { _source = _adapters[dom].getAxisIterator(_axis); } else if (_axis == Axis.CHILD) { _source = _adapters[dom].getTypedChildren(_type); } else { _source = _adapters[dom].getTypedAxisIterator(_axis, _type); } } _dtmId = dom; _source.setStartNode(node); return this; } public DTMAxisIterator reset() { if (_source != null) { _source.reset(); } return this; } public int getLast() { if (_source != null) { return _source.getLast(); } else { return END; } } public int getPosition() { if (_source != null) { return _source.getPosition(); } else { return END; } } public boolean isReverse() { return Axis.isReverse[_axis]; } public void setMark() { if (_source != null) { _source.setMark(); } } public void gotoMark() { if (_source != null) { _source.gotoMark(); } } public DTMAxisIterator cloneIterator() { final AxisIterator clone = new AxisIterator(_axis, _type); if (_source != null) { clone._source = _source.cloneIterator(); } clone._dtmId = _dtmId; return clone; } } // end of AxisIterator /************************************************************** * This is a specialised iterator for predicates comparing node or * attribute values to variable or parameter values. */ private final class NodeValueIterator extends DTMAxisIteratorBase { private DTMAxisIterator _source; private String _value; private boolean _op; private final boolean _isReverse; private int _returnType = RETURN_PARENT; public NodeValueIterator(DTMAxisIterator source, int returnType, String value, boolean op) { _source = source; _returnType = returnType; _value = value; _op = op; _isReverse = source.isReverse(); } public boolean isReverse() { return _isReverse; } public DTMAxisIterator cloneIterator() { try { NodeValueIterator clone = (NodeValueIterator)super.clone(); clone._source = _source.cloneIterator(); clone.setRestartable(false); return clone.reset(); } catch (CloneNotSupportedException e) { BasisLibrary.runTimeError(BasisLibrary.ITERATOR_CLONE_ERR, e.toString()); return null; } } public void setRestartable(boolean isRestartable) { _isRestartable = isRestartable; _source.setRestartable(isRestartable); } public DTMAxisIterator reset() { _source.reset(); return resetPosition(); } public int next() { int node; while ((node = _source.next()) != END) { String val = getStringValueX(node); if (_value.equals(val) == _op) { if (_returnType == RETURN_CURRENT) return returnNode(node); else return returnNode(getParent(node)); } } return END; } public DTMAxisIterator setStartNode(int node) { if (_isRestartable) { _source.setStartNode(_startNode = node); return resetPosition(); } return this; } public void setMark() { _source.setMark(); } public void gotoMark() { _source.gotoMark(); } } public MultiDOM(DOM main) { _size = INITIAL_SIZE; _free = 1; _adapters = new DOM[INITIAL_SIZE]; DOMAdapter adapter = (DOMAdapter)main; _adapters[0] = adapter; _main = adapter; DOM dom = adapter.getDOMImpl(); if (dom instanceof DTMDefaultBase) { _dtmManager = ((DTMDefaultBase)dom).getManager(); } // %HZ% %REVISIT% Is this the right thing to do here? In the old // %HZ% %REVISIT% version, the main document did not get added through // %HZ% %REVISIT% a call to addDOMAdapter, which meant it couldn't be // %HZ% %REVISIT% found by a call to getDocumentMask. The problem is // %HZ% %REVISIT% TransformerHandler is typically constructed with a // %HZ% %REVISIT% system ID equal to the stylesheet's URI; with SAX // %HZ% %REVISIT% input, it ends up giving that URI to the document. // %HZ% %REVISIT% Then, any references to document('') are resolved // %HZ% %REVISIT% using the stylesheet's URI. // %HZ% %REVISIT% MultiDOM.getDocumentMask is called to verify that // %HZ% %REVISIT% a document associated with that URI has not been // %HZ% %REVISIT% encountered, and that method ends up returning the // %HZ% %REVISIT% mask of the main document, when what we really what // %HZ% %REVISIT% is to read the stylesheet itself! addDOMAdapter(adapter, false); } public int nextMask() { return _free; } public void setupMapping(String[] names, String[] uris, int[] types, String[] namespaces) { // This method only has a function in DOM adapters } public int addDOMAdapter(DOMAdapter adapter) { return addDOMAdapter(adapter, true); } private int addDOMAdapter(DOMAdapter adapter, boolean indexByURI) { // Add the DOM adapter to the array of DOMs DOM dom = adapter.getDOMImpl(); int domNo = 1; int dtmSize = 1; SuballocatedIntVector dtmIds = null; if (dom instanceof DTMDefaultBase) { DTMDefaultBase dtmdb = (DTMDefaultBase)dom; dtmIds = dtmdb.getDTMIDs(); dtmSize = dtmIds.size(); domNo = dtmIds.elementAt(dtmSize-1) >>> DTMManager.IDENT_DTM_NODE_BITS; } else if (dom instanceof SimpleResultTreeImpl) { SimpleResultTreeImpl simpleRTF = (SimpleResultTreeImpl)dom; domNo = simpleRTF.getDocument() >>> DTMManager.IDENT_DTM_NODE_BITS; } if (domNo >= _size) { int oldSize = _size; do { _size *= 2; } while (_size <= domNo); final DOMAdapter[] newArray = new DOMAdapter[_size]; System.arraycopy(_adapters, 0, newArray, 0, oldSize); _adapters = newArray; } _free = domNo + 1; if (dtmSize == 1) { _adapters[domNo] = adapter; } else if (dtmIds != null) { int domPos = 0; for (int i = dtmSize - 1; i >= 0; i--) { domPos = dtmIds.elementAt(i) >>> DTMManager.IDENT_DTM_NODE_BITS; _adapters[domPos] = adapter; } domNo = domPos; } // Store reference to document (URI) in hashtable if (indexByURI) { String uri = adapter.getDocumentURI(0); _documents.put(uri, new Integer(domNo)); } // If the dom is an AdaptiveResultTreeImpl, we need to create a // DOMAdapter around its nested dom object (if it is non-null) and // add the DOMAdapter to the list. if (dom instanceof AdaptiveResultTreeImpl) { AdaptiveResultTreeImpl adaptiveRTF = (AdaptiveResultTreeImpl)dom; DOM nestedDom = adaptiveRTF.getNestedDOM(); if (nestedDom != null) { DOMAdapter newAdapter = new DOMAdapter(nestedDom, adapter.getNamesArray(), adapter.getUrisArray(), adapter.getTypesArray(), adapter.getNamespaceArray()); addDOMAdapter(newAdapter); } } return domNo; } public int getDocumentMask(String uri) { Integer domIdx = (Integer)_documents.get(uri); if (domIdx == null) { return(-1); } else { return domIdx.intValue(); } } public DOM getDOMAdapter(String uri) { Integer domIdx = (Integer)_documents.get(uri); if (domIdx == null) { return(null); } else { return(_adapters[domIdx.intValue()]); } } public int getDocument() { return _main.getDocument(); } public DTMManager getDTMManager() { return _dtmManager; } /** * Returns singleton iterator containing the document root */ public DTMAxisIterator getIterator() { // main source document @ 0 return _main.getIterator(); } public String getStringValue() { return _main.getStringValue(); } public DTMAxisIterator getChildren(final int node) { return _adapters[getDTMId(node)].getChildren(node); } public DTMAxisIterator getTypedChildren(final int type) { return new AxisIterator(Axis.CHILD, type); } public DTMAxisIterator getAxisIterator(final int axis) { return new AxisIterator(axis, NO_TYPE); } public DTMAxisIterator getTypedAxisIterator(final int axis, final int type) { return new AxisIterator(axis, type); } public DTMAxisIterator getNthDescendant(int node, int n, boolean includeself) { return _adapters[getDTMId(node)].getNthDescendant(node, n, includeself); } public DTMAxisIterator getNodeValueIterator(DTMAxisIterator iterator, int type, String value, boolean op) { return(new NodeValueIterator(iterator, type, value, op)); } public DTMAxisIterator getNamespaceAxisIterator(final int axis, final int ns) { DTMAxisIterator iterator = _main.getNamespaceAxisIterator(axis, ns); return(iterator); } public DTMAxisIterator orderNodes(DTMAxisIterator source, int node) { return _adapters[getDTMId(node)].orderNodes(source, node); } public int getExpandedTypeID(final int node) { if (node != DTM.NULL) { return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getExpandedTypeID(node); } else { return DTM.NULL; } } public int getNamespaceType(final int node) { return _adapters[getDTMId(node)].getNamespaceType(node); } public int getNSType(int node) { return _adapters[getDTMId(node)].getNSType(node); } public int getParent(final int node) { if (node == DTM.NULL) { return DTM.NULL; } return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getParent(node); } public int getAttributeNode(final int type, final int el) { if (el == DTM.NULL) { return DTM.NULL; } return _adapters[el >>> DTMManager.IDENT_DTM_NODE_BITS].getAttributeNode(type, el); } public String getNodeName(final int node) { if (node == DTM.NULL) { return ""; } return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getNodeName(node); } public String getNodeNameX(final int node) { if (node == DTM.NULL) { return ""; } return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getNodeNameX(node); } public String getNamespaceName(final int node) { if (node == DTM.NULL) { return ""; } return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getNamespaceName(node); } public String getStringValueX(final int node) { if (node == DTM.NULL) { return ""; } return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getStringValueX(node); } public void copy(final int node, SerializationHandler handler) throws TransletException { if (node != DTM.NULL) { _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].copy(node, handler); } } public void copy(DTMAxisIterator nodes, SerializationHandler handler) throws TransletException { int node; while ((node = nodes.next()) != DTM.NULL) { _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].copy(node, handler); } } public String shallowCopy(final int node, SerializationHandler handler) throws TransletException { if (node == DTM.NULL) { return ""; } return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].shallowCopy(node, handler); } public boolean lessThan(final int node1, final int node2) { if (node1 == DTM.NULL) { return true; } if (node2 == DTM.NULL) { return false; } final int dom1 = getDTMId(node1); final int dom2 = getDTMId(node2); return dom1 == dom2 ? _adapters[dom1].lessThan(node1, node2) : dom1 < dom2; } public void characters(final int textNode, SerializationHandler handler) throws TransletException { if (textNode != DTM.NULL) { _adapters[textNode >>> DTMManager.IDENT_DTM_NODE_BITS].characters(textNode, handler); } } public void setFilter(StripFilter filter) { for (int dom=0; dom<_free; dom++) { if (_adapters[dom] != null) { _adapters[dom].setFilter(filter); } } } public Node makeNode(int index) { if (index == DTM.NULL) { return null; } return _adapters[getDTMId(index)].makeNode(index); } public Node makeNode(DTMAxisIterator iter) { // TODO: gather nodes from all DOMs ? return _main.makeNode(iter); } public NodeList makeNodeList(int index) { if (index == DTM.NULL) { return null; } return _adapters[getDTMId(index)].makeNodeList(index); } public NodeList makeNodeList(DTMAxisIterator iter) { // TODO: gather nodes from all DOMs ? return _main.makeNodeList(iter); } public String getLanguage(int node) { return _adapters[getDTMId(node)].getLanguage(node); } public int getSize() { int size = 0; for (int i=0; i<_size; i++) { size += _adapters[i].getSize(); } return(size); } public String getDocumentURI(int node) { if (node == DTM.NULL) { node = DOM.NULL; } return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getDocumentURI(0); } public boolean isElement(final int node) { if (node == DTM.NULL) { return false; } return(_adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].isElement(node)); } public boolean isAttribute(final int node) { if (node == DTM.NULL) { return false; } return(_adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].isAttribute(node)); } public int getDTMId(int nodeHandle) { if (nodeHandle == DTM.NULL) return 0; int id = nodeHandle >>> DTMManager.IDENT_DTM_NODE_BITS; while (id >= 2 && _adapters[id] == _adapters[id-1]) { id--; } return id; } public int getNodeIdent(int nodeHandle) { return _adapters[nodeHandle >>> DTMManager.IDENT_DTM_NODE_BITS].getNodeIdent(nodeHandle); } public int getNodeHandle(int nodeId) { return _main.getNodeHandle(nodeId); } public DOM getResultTreeFrag(int initSize, int rtfType) { return _main.getResultTreeFrag(initSize, rtfType); } public DOM getResultTreeFrag(int initSize, int rtfType, boolean addToManager) { return _main.getResultTreeFrag(initSize, rtfType, addToManager); } public DOM getMain() { return _main; } /** * Returns a DOMBuilder class wrapped in a SAX adapter. */ public SerializationHandler getOutputDomBuilder() { return _main.getOutputDomBuilder(); } public String lookupNamespace(int node, String prefix) throws TransletException { return _main.lookupNamespace(node, prefix); } // %HZ% Does this method make any sense here??? public String getUnparsedEntityURI(String entity) { return _main.getUnparsedEntityURI(entity); } // %HZ% Does this method make any sense here??? public Hashtable getElementsWithIDs() { return _main.getElementsWithIDs(); } }