blob: f53a57f8f3f718fd54b5f075f480c465befdce7a [file] [log] [blame]
/*
* 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 apache@apache.org.
*
* 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.stree;
import org.w3c.dom.Node;
import org.w3c.dom.DOMException;
import org.w3c.dom.Element;
import org.apache.xalan.transformer.TransformerImpl;
import org.apache.xalan.templates.StylesheetRoot;
import org.apache.xalan.templates.WhiteSpaceInfo;
import javax.xml.transform.TransformerException;
import org.xml.sax.ContentHandler;
/**
* <meta name="usage" content="internal"/>
* Class representing a parent node. A parent is also a child unless
* it is the root node.
*/
public class Parent extends Child
{
/**
* Constructor Parent
*
*
* @param doc Document object
*/
public Parent(DocumentImpl doc)
{
super(doc);
}
/** The position of this node in its parent's children list */
protected int m_posInChildList;
/** Number of children of this node. This number also includes attribute nodes */
protected int m_childCount = 0; // includes attributes, elements
/** Flag indicating whether all children of this node have been processed */
boolean m_isComplete = false;
/** This node's last child */
Child m_last;
/** This node's first child */
Child m_first;
/**
* Get the number of children this node currently contains.
* Note that this will only return the number of children
* added so far. If the isComplete property is false,
* it is likely that more children will be added.
* DON'T CALL THIS FUNCTION IF YOU CAN HELP IT!!!
*
* @return number of children this node currently contains
*/
public int getChildCount()
{
if (!isComplete())
{
synchronized (m_doc)
{
try
{
// Here we have to wait until the element is complete
while (!isComplete())
{
m_doc.wait(100);
throwIfParseError();
}
}
catch (InterruptedException e)
{
throwIfParseError();
}
//System.out.println("... getcount " );
}
}
//System.out.println("Waiting... Done "+ this.getNodeName() );
return m_childCount;
}
/**
* This is a convenience method to allow easy determination of whether a
* node has any children.
* @return <code>true</code> if the node has any children,
* <code>false</code> if the node has no children.
*/
public boolean hasChildNodes()
{
// synchronized (m_doc)
// {
if (0 != m_childCount)
return true;
else
{
if (!isComplete())
{
synchronized (m_doc)
{
try
{
// Only wait until the first child comes, or we are complete.
while (!isComplete())
{
m_doc.wait(100);
throwIfParseError();
if (0 != m_childCount)
break;
}
}
catch (InterruptedException e)
{
throwIfParseError();
}
}
}
return (0 == m_childCount) ? false : true;
}
// }
}
/**
* <meta name="usage" content="internal"/>
* Get the position of the child of an element in the document.
* Note that this is assuming an index starting at 1
*
* @param pos Position of the child in this parent's children list
*
* @return the position of this child in the document or -1 if the child
* is not found
*/
public int getChildUID(int pos)
{
Child child = getChild(pos);
return (null != child) ? child.getUid() : -1;
}
/**
* Get the nth child.
* @param i the index of the child.
*
* @return The child node at the specified position or null if none found
* @throws ArrayIndexOutOfBoundsException if the index is out of bounds.
* @throws NullPointerException if there are no children.
*/
public Child getChild(int i)
throws ArrayIndexOutOfBoundsException, NullPointerException
{
if (i < 0)
return null;
else if ((i >= m_childCount) &&!isComplete())
{
synchronized (m_doc)
{
try
{
// System.out.println("Waiting... getChild " + i + " " + getNodeName());
while (!isComplete())
{
m_doc.wait(100);
throwIfParseError();
if (i < m_childCount)
break;
}
}
catch (InterruptedException e)
{
throwIfParseError();
}
}
}
if (i < m_childCount)
{
Child child = m_first;
int pos = 0;
while (null != child)
{
if (pos == i)
{
return child;
}
child = child.m_next;
pos++;
}
}
return null;
}
/**
* The first child of this node. If there is no such node, this returns
* <code>null</code>.
*
* @return The first child of this parent or null if none found
*/
public Node getFirstChild()
{
// synchronized (m_doc)
// {
if (null != m_first)
return m_first;
else if (!m_isComplete)
{
synchronized (m_doc)
{
try
{
// System.out.println("Waiting... getChild " + i + " " + getNodeName());
while (!isComplete())
{
m_doc.wait(100);
throwIfParseError();
if (null != m_first)
return m_first;
}
}
catch (InterruptedException e)
{
throwIfParseError();
}
}
}
// }
return m_first;
}
/**
* The last child of this node. If there is no such node, this returns
* <code>null</code>.
*
* @return The last child of this parent
*/
public Node getLastChild()
{
try
{
return getChild(getChildCount() - 1);
}
catch (Exception e)
{
throw new org.apache.xml.utils.WrappedRuntimeException(e);
}
}
/**
* Append a child to the child list.
* @param newChild Must be a org.apache.xalan.stree.Child.
*
* @return The node we just added to this parent's children list
* @throws ClassCastException if the newChild isn't a org.apache.xalan.stree.Child.
*
* @throws DOMException
*/
public Node appendChild(Node newChild) throws DOMException
{
Child child = (Child) newChild;
DocumentImpl doc = m_doc;
child.m_parent = this;
m_childCount++;
if(0 == child.m_uid)
{
child.m_uid = ++m_doc.m_docOrderCount;
}
child.m_level = (short) (m_level + 1);
if (null == m_first)
{
m_first = child;
}
else
{
child.m_prev = m_last;
m_last.m_next = child;
}
m_last = child;
return newChild;
}
/**
* Return if this node has had all it's children added, i.e.
* if a endElement event has occured.
*
* @return whether this node has had all it's children added or not
*/
public boolean isComplete()
{
if (!m_isComplete && (null != m_doc.m_exceptionThrown))
throwParseError(m_doc.m_exceptionThrown);
return m_isComplete;
}
/**
* Set that this node's child list is complete, i.e.
* an endElement event has occured.
*
* @param isComplete flag indicating whether this node has had all it's children added
*/
public void setComplete(boolean isComplete)
{
m_isComplete = isComplete;
}
/**
* Throw a ParseError exception
*
*
* @param e The original exception
*/
protected void throwParseError(Exception e)
{
m_isComplete = true;
super.throwParseError(e);
}
/**
* Handle a Characters event
*
*
* @param ch Content handler to handle SAX events
*
* @throws SAXException if the content handler characters event throws a SAXException.
*/
public void dispatchCharactersEvent(ContentHandler ch)
throws org.xml.sax.SAXException
{
for (Node child = getFirstChild(); child != null;
child = child.getNextSibling())
{
int t = child.getNodeType();
if(Node.COMMENT_NODE != t && Node.PROCESSING_INSTRUCTION_NODE != t)
((SaxEventDispatch)child).dispatchCharactersEvent(ch);
}
}
}