mmidy 00/11/30 08:26:50
Modified: java/src/org/apache/xalan/stree StreeDOMBuilder.java
java/src/org/apache/xalan/transformer KeyIterator.java
KeyTable.java KeyWalker.java
java/src/org/apache/xpath/axes LocPathIterator.java
Added: java/src/org/apache/xalan/transformer KeyRefIterator.java
Log:
Change Key() to incrementally build a table with key values and iterators.
With this change, we will only walk through the source tree once per key name
definition.
Revision Changes Path
1.8 +3 -0
xml-xalan/java/src/org/apache/xalan/stree/StreeDOMBuilder.java
Index: StreeDOMBuilder.java
===================================================================
RCS file:
/home/cvs/xml-xalan/java/src/org/apache/xalan/stree/StreeDOMBuilder.java,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- StreeDOMBuilder.java 2000/11/23 04:57:39 1.7
+++ StreeDOMBuilder.java 2000/11/30 16:26:48 1.8
@@ -323,6 +323,9 @@
*/
void appendAccumulatedText(Node currentNode, char ch[], int start, int
length)
{
+ // Get the text node. It should be the last node that was
+ // added to the current node. (Text nodes are never made to be
+ // the currentNode).
TextImpl textNode = (TextImpl)((Parent)currentNode).m_last;
textNode.appendText(ch, start, length);
}
1.7 +52 -0
xml-xalan/java/src/org/apache/xalan/transformer/KeyIterator.java
Index: KeyIterator.java
===================================================================
RCS file:
/home/cvs/xml-xalan/java/src/org/apache/xalan/transformer/KeyIterator.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- KeyIterator.java 2000/11/23 04:58:16 1.6
+++ KeyIterator.java 2000/11/30 16:26:48 1.7
@@ -81,9 +81,18 @@
*/
public class KeyIterator extends LocPathIterator
{
+
+ /** The key table this iterator is associated to */
+ private KeyTable m_keyTable;
/** NEEDSDOC Field m_name */
private QName m_name;
+
+ /**
+ * Flag indicating whether the whole source tree has been walked.
+ * True if we still need to finish walking the tree.
+ * */
+ private boolean m_lookForMoreNodes = true;
/**
* NEEDSDOC Method getName
@@ -172,4 +181,47 @@
this.setLastUsedWalker(m_firstWalker);
this.setNextPosition(0);
}
+
+ /**
+ * Set the KeyTable associated with this iterator
+ *
+ *
+ * @param keyTable, the KeyTable associated with this iterator
+ */
+ void setKeyTable(KeyTable keyTable)
+ {
+ m_keyTable = keyTable;
+ }
+
+ /**
+ * Add this ref to the refsTable in KeyTable
+ *
+ *
+ * @param ref Key ref(from key use field)
+ * @param node Node matching that ref
+ */
+ void addRefNode(String ref, Node node)
+ {
+ m_keyTable.addRefNode(ref, node);
+ }
+
+ /**
+ * Indicate whether we have walked the whole tree
+ *
+ * @param b False if we have walked the whole tree
+ */
+ void setLookForMoreNodes(boolean b)
+ {
+ m_lookForMoreNodes = b;
+ }
+
+ /**
+ * Get flag indicating whether we have walked the whole tree
+ *
+ */
+ boolean getLookForMoreNodes()
+ {
+ return m_lookForMoreNodes;
+ }
+
}
1.7 +83 -11
xml-xalan/java/src/org/apache/xalan/transformer/KeyTable.java
Index: KeyTable.java
===================================================================
RCS file:
/home/cvs/xml-xalan/java/src/org/apache/xalan/transformer/KeyTable.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- KeyTable.java 2000/11/23 04:58:16 1.6
+++ KeyTable.java 2000/11/30 16:26:48 1.7
@@ -63,6 +63,7 @@
import java.util.Hashtable;
import java.util.Vector;
+import java.util.Enumeration;
import org.apache.xpath.NodeSet;
import org.apache.xpath.objects.XObject;
@@ -111,6 +112,8 @@
* b) with a value that is a KeyIterator.
*/
private KeyIterator m_keyIter;
+
+ private Hashtable defsTable;
/**
* Build a keys table.
@@ -131,35 +134,64 @@
m_docKey = doc;
m_keyIter = new KeyIterator(doc, nscontext, name, keyDeclarations,
xmlLiaison);
+ m_keyIter.setKeyTable(this);
} // end buildKeysTable method
/**
* Given a valid element key, return the corresponding node list.
* @param The name of the key, which must match the 'name' attribute on
xsl:key.
*
- * NEEDSDOC @param name
+ * @param name The name of the key
* @param ref The value that must match the value found by the 'match'
attribute on xsl:key.
* @return If the name was not declared with xsl:key, this will return
null,
* if the identifier is not found, it will return null,
* otherwise it will return a LocPathIterator instance.
*/
- public KeyIterator getNodeSetByKey(QName name, String ref)
+ public LocPathIterator getNodeSetByKey(QName name, String ref)
{
KeyIterator ki;
-
- try
- {
- ki = (KeyIterator) m_keyIter.clone();
+ KeyRefIterator kiRef;
+ Hashtable refsTable = null;
- ki.setLookupKey(ref);
- }
- catch (CloneNotSupportedException cnse)
+ if (defsTable != null)
{
- ki = null;
+ refsTable = (Hashtable)defsTable.get(name);
+ if (refsTable != null)
+ {
+ Object kiObj = refsTable.get(ref);
+ if (kiObj != null)
+ {
+ try
+ {
+ // clone with reset??
+ kiRef = (KeyRefIterator)((KeyRefIterator)kiObj).clone();
+ return kiRef;
+ }
+ catch (CloneNotSupportedException cnse)
+ {
+ ki = null;
+ }
+ }
+ }
}
- return ki;
+ {
+ if (defsTable == null)
+ defsTable = new Hashtable();
+ if (refsTable == null)
+ refsTable = new Hashtable();
+
+ // initialize walker only once!
+ if (m_keyIter.getFirstWalker().getRoot() == null)
+ m_keyIter.setLookupKey(ref);
+ else
+ ((KeyWalker)m_keyIter.getFirstWalker()).m_lookupKey = ref;
+ kiRef = new KeyRefIterator(ref, m_keyIter);
+ refsTable.put(ref, kiRef);
+ defsTable.put(name,refsTable);
+ return kiRef;
+ }
}
/**
@@ -172,4 +204,44 @@
{
return m_keyIter.getName();
}
+
+ /**
+ * Add this ref to the refsTable
+ *
+ *
+ * @param ref Key ref(from key use field)
+ * @param node Node matching that ref
+ */
+ void addRefNode(String ref, Node node)
+ {
+ KeyRefIterator kiRef = null;
+ Hashtable refsTable = null;
+ if (defsTable != null)
+ {
+ refsTable = (Hashtable)defsTable.get(getKeyTableName());
+ if (refsTable != null)
+ {
+ Object kiObj = refsTable.get(ref);
+ if (kiObj != null)
+ {
+ kiRef = (KeyRefIterator)kiObj;
+ }
+ }
+ }
+ if (kiRef == null)
+ {
+ if (defsTable == null)
+ defsTable = new Hashtable();
+ if (refsTable == null)
+ {
+ refsTable = new Hashtable();
+ defsTable.put(getKeyTableName(),refsTable);
+ }
+ kiRef = new KeyRefIterator(ref, m_keyIter);
+ refsTable.put(ref, kiRef);
+ }
+ kiRef.addNode(node);
+ }
+
+
}
1.9 +43 -7
xml-xalan/java/src/org/apache/xalan/transformer/KeyWalker.java
Index: KeyWalker.java
===================================================================
RCS file:
/home/cvs/xml-xalan/java/src/org/apache/xalan/transformer/KeyWalker.java,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- KeyWalker.java 2000/11/23 04:58:16 1.8
+++ KeyWalker.java 2000/11/30 16:26:49 1.9
@@ -194,8 +194,8 @@
testNode);
if (score == kd.getMatch().MATCH_SCORE_NONE)
- continue;
-
+ continue;
+
// Query from the node, according the the select pattern in the
// use attribute in xsl:key.
XObject xuse = kd.getUse().execute(ki.getXPathContext(), testNode,
@@ -204,7 +204,8 @@
if (xuse.getType() != xuse.CLASS_NODESET)
{
String exprResult = xuse.str();
-
+ ((KeyIterator)m_lpi).addRefNode(exprResult, testNode);
+
if (lookupKey.equals(exprResult))
return this.FILTER_ACCEPT;
}
@@ -212,15 +213,32 @@
{
NodeIterator nl = xuse.nodeset();
Node useNode;
-
+ short result = -1;
+ /*
+ We are walking through all the nodes in this nodeset
+ rather than stopping when we find the one we're looking
+ for because we don't currently save the state of KeyWalker
+ such that the next time it gets called it would continue
+ to look in this nodeset for any further matches.
+ TODO: Try to save the state of KeyWalker, i.e. keep this node
+ iterator saved somewhere and finish walking through its nodes
+ the next time KeyWalker is called before we look for any new
+ matches. What if the next call is for the same match+use
+ combination??
+ */
while (null != (useNode = nl.nextNode()))
{
String exprResult = m_lpi.getDOMHelper().getNodeData(useNode);
-
+ ((KeyIterator)m_lpi).addRefNode(exprResult, testNode);
+
if ((null != exprResult) && lookupKey.equals(exprResult))
- return this.FILTER_ACCEPT;
+ result = this.FILTER_ACCEPT;
+ //return this.FILTER_ACCEPT;
}
- }
+ if (-1 != result)
+ return result;
+ }
+
} // end for(int i = 0; i < nDeclarations; i++)
}
catch (TransformerException se)
@@ -231,4 +249,22 @@
return this.FILTER_REJECT;
}
+
+ /**
+ * Moves the <code>TreeWalker</code> to the next visible node in document
+ * order relative to the current node, and returns the new node. If the
+ * current node has no next node, or if the search for nextNode attempts
+ * to step upward from the TreeWalker's root node, returns
+ * <code>null</code> , and retains the current node.
+ * @return The new node, or <code>null</code> if the current node has no
+ * next node in the TreeWalker's logical view.
+ */
+ public Node nextNode()
+ {
+ Node node = super.nextNode();
+ if (node == null)
+ ((KeyIterator)m_lpi).setLookForMoreNodes(false);
+ return node;
+ }
+
}
1.1
xml-xalan/java/src/org/apache/xalan/transformer/KeyRefIterator.java
Index: KeyRefIterator.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Xalan" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 1999, Lotus
* Development Corporation., http://www.lotus.com. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.xalan.transformer;
import java.util.Vector;
import org.apache.xpath.axes.LocPathIterator;
import org.apache.xml.utils.QName;
import org.apache.xalan.templates.KeyDeclaration;
import org.apache.xpath.NodeSet;
import org.w3c.dom.Node;
import org.w3c.dom.DOMException;
/**
* <meta name="usage" content="internal"/>
* NEEDSDOC Class KeyIterator <needs-comment/>
*/
public class KeyRefIterator extends LocPathIterator
{
/** Key name */
private QName m_name;
/** Use field of key function */
private String m_lookupKey;
/** Main Key iterator for this iterator */
private KeyIterator m_ki;
/**
* Get key name
*
*
* @return Key name
*/
public QName getName()
{
return m_name;
}
/**
* Constructor KeyRefIterator
*
*
* NEEDSDOC @param doc
* NEEDSDOC @param nscontext
* NEEDSDOC @param name
* NEEDSDOC @param keyDeclarations
* NEEDSDOC @param xctxt
*/
public KeyRefIterator(String ref, KeyIterator ki)
{
super(ki.getPrefixResolver());
setShouldCacheNodes(true);
m_ki = ki;
m_name = ki.getName();
m_lookupKey = ref;
this.m_execContext = ki.getXPathContext();
this.m_dhelper = ki.getDOMHelper();
}
/**
* Returns the next node in the set and advances the position of the
* iterator in the set. After a NodeIterator is created, the first call
* to nextNode() returns the first node in the set.
*
* @return The next <code>Node</code> in the set being iterated over, or
* <code>null</code> if there are no more members in that set.
*
* @exception DOMException
* INVALID_STATE_ERR: Raised if this method is called after the
* <code>detach</code> method was invoked.
*/
public Node nextNode() throws DOMException
{
if (m_foundLast)
return null;
// If the cache is on, and the node has already been found, then
// just return from the list.
NodeSet m_cachedNodes = getCachedNodes();
// We are not using the NodeSet methods getCurrentPos() and nextNode()
// in this case because the nodeset is not cloned and therefore
// the positions it indicates may not be associated with the
// current iterator.
if ((null != m_cachedNodes)
&& (m_next < m_cachedNodes.size()))
{
Node next = m_cachedNodes.elementAt(m_next);
this.setCurrentPos(++m_next);
m_lastFetched = next;
return next;
}
Node next = null;
if ( m_ki.getLookForMoreNodes())
{
((KeyWalker)m_ki.getFirstWalker()).m_lookupKey = m_lookupKey;
next = m_ki.nextNode();
}
if (null != next)
{
m_lastFetched = next;
this.setCurrentPos(++m_next);
return next;
}
else
m_foundLast = true;
m_lastFetched = null;
return null;
}
/**
* Get a cloned LocPathIterator that holds the same
* position as this iterator.
*
* @return A clone of this iterator that holds the same node position.
*
* @throws CloneNotSupportedException
*/
public Object clone() throws CloneNotSupportedException
{
KeyRefIterator clone = (KeyRefIterator)super.clone();
clone.m_foundLast = false;
clone.m_lastFetched = null;
clone.m_next = 0;
clone.setCurrentPos(0);
return clone;
}
/**
* Add a node matching this ref to the cached nodes for this iterator
*
*
* @param node Node to add to cached nodes
*/
public void addNode(Node node)
{
NodeSet m_cachedNodes = getCachedNodes();
if (null != m_cachedNodes)
m_cachedNodes.addElement(node);
}
}
1.16 +11 -1
xml-xalan/java/src/org/apache/xpath/axes/LocPathIterator.java
Index: LocPathIterator.java
===================================================================
RCS file:
/home/cvs/xml-xalan/java/src/org/apache/xpath/axes/LocPathIterator.java,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -r1.15 -r1.16
--- LocPathIterator.java 2000/11/23 04:59:01 1.15
+++ LocPathIterator.java 2000/11/30 16:26:50 1.16
@@ -111,7 +111,7 @@
ObjectPool m_pool = new ObjectPool(this.getClass());
/** The last node that was fetched, usually by nextNode. */
- Node m_lastFetched;
+ public Node m_lastFetched;
/** If this iterator needs to cache nodes that are fetched, they
* are stored here. */
@@ -350,6 +350,16 @@
m_cachedNodes = new NodeSet();
else
m_cachedNodes = null;
+ }
+
+ /**
+ * Get cached nodes.
+ *
+ * @return Cached nodes.
+ */
+ public NodeSet getCachedNodes()
+ {
+ return m_cachedNodes;
}
/**