/* * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ 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.xalan.internal.xsltc.TransletException; import com.sun.org.apache.xml.internal.dtm.Axis; 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.DTMAxisTraverser; 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.DTMManagerDefault; import com.sun.org.apache.xml.internal.serializer.EmptySerializer; import com.sun.org.apache.xml.internal.serializer.SerializationHandler; import com.sun.org.apache.xml.internal.utils.XMLString; import com.sun.org.apache.xml.internal.utils.XMLStringDefault; import java.util.Map; import javax.xml.transform.SourceLocator; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; /** * This class represents a light-weight DOM model for simple result tree fragment(RTF). * A simple RTF is an RTF that has only one Text node. The Text node can be produced by a * combination of Text, xsl:value-of and xsl:number instructions. It can also be produced * by a control structure (xsl:if or xsl:choose) whose body is pure Text. *
* A SimpleResultTreeImpl has only two nodes, i.e. the ROOT node and its Text child. All DOM * interfaces are overridden with this in mind. For example, the getStringValue() interface * returns the value of the Text node. This class receives the character data from the * characters() interface. *
* This class implements DOM and SerializationHandler. It also implements the DTM interface
* for support in MultiDOM. The nested iterators (SimpleIterator and SingletonIterator) are
* used to support the nodeset() extension function.
*/
public class SimpleResultTreeImpl extends EmptySerializer implements DOM, DTM
{
/**
* The SimpleIterator is designed to support the nodeset() extension function. It has
* a traversal direction parameter. The DOWN direction is used for child and descendant
* axes, while the UP direction is used for parent and ancestor axes.
*
* This iterator only handles two nodes (RTF_ROOT and RTF_TEXT). If the type is set,
* it will also match the node type with the given type.
*/
public final class SimpleIterator extends DTMAxisIteratorBase
{
static final int DIRECTION_UP = 0;
static final int DIRECTION_DOWN = 1;
static final int NO_TYPE = -1;
// The direction of traversal (default to DOWN).
// DOWN is for child and descendant. UP is for parent and ancestor.
int _direction = DIRECTION_DOWN;
int _type = NO_TYPE;
int _currentNode;
public SimpleIterator()
{
}
public SimpleIterator(int direction)
{
_direction = direction;
}
public SimpleIterator(int direction, int type)
{
_direction = direction;
_type = type;
}
public int next()
{
// Increase the node ID for down traversal. Also match the node type
// if the type is given.
if (_direction == DIRECTION_DOWN) {
while (_currentNode < NUMBER_OF_NODES) {
if (_type != NO_TYPE) {
if ((_currentNode == RTF_ROOT && _type == DTM.ROOT_NODE)
|| (_currentNode == RTF_TEXT && _type == DTM.TEXT_NODE))
return returnNode(getNodeHandle(_currentNode++));
else
_currentNode++;
}
else
return returnNode(getNodeHandle(_currentNode++));
}
return END;
}
// Decrease the node ID for up traversal.
else {
while (_currentNode >= 0) {
if (_type != NO_TYPE) {
if ((_currentNode == RTF_ROOT && _type == DTM.ROOT_NODE)
|| (_currentNode == RTF_TEXT && _type == DTM.TEXT_NODE))
return returnNode(getNodeHandle(_currentNode--));
else
_currentNode--;
}
else
return returnNode(getNodeHandle(_currentNode--));
}
return END;
}
}
public DTMAxisIterator setStartNode(int nodeHandle)
{
int nodeID = getNodeIdent(nodeHandle);
_startNode = nodeID;
// Increase the node ID by 1 if self is not included.
if (!_includeSelf && nodeID != DTM.NULL) {
if (_direction == DIRECTION_DOWN)
nodeID++;
else if (_direction == DIRECTION_UP)
nodeID--;
}
_currentNode = nodeID;
return this;
}
public void setMark()
{
_markedNode = _currentNode;
}
public void gotoMark()
{
_currentNode = _markedNode;
}
} // END of SimpleIterator
/**
* The SingletonIterator is used for the self axis.
*/
public final class SingletonIterator extends DTMAxisIteratorBase
{
static final int NO_TYPE = -1;
int _type = NO_TYPE;
int _currentNode;
public SingletonIterator()
{
}
public SingletonIterator(int type)
{
_type = type;
}
public void setMark()
{
_markedNode = _currentNode;
}
public void gotoMark()
{
_currentNode = _markedNode;
}
public DTMAxisIterator setStartNode(int nodeHandle)
{
_currentNode = _startNode = getNodeIdent(nodeHandle);
return this;
}
public int next()
{
if (_currentNode == END)
return END;
_currentNode = END;
if (_type != NO_TYPE) {
if ((_currentNode == RTF_ROOT && _type == DTM.ROOT_NODE)
|| (_currentNode == RTF_TEXT && _type == DTM.TEXT_NODE))
return getNodeHandle(_currentNode);
}
else
return getNodeHandle(_currentNode);
return END;
}
} // END of SingletonIterator
// empty iterator to be returned when there are no children
private final static DTMAxisIterator EMPTY_ITERATOR =
new DTMAxisIteratorBase() {
public DTMAxisIterator reset() { return this; }
public DTMAxisIterator setStartNode(int node) { return this; }
public int next() { return DTM.NULL; }
public void setMark() {}
public void gotoMark() {}
public int getLast() { return 0; }
public int getPosition() { return 0; }
public DTMAxisIterator cloneIterator() { return this; }
public void setRestartable(boolean isRestartable) { }
};
// The root node id of the simple RTF
public static final int RTF_ROOT = 0;
// The Text node id of the simple RTF (simple RTF has only one Text node).
public static final int RTF_TEXT = 1;
// The number of nodes.
public static final int NUMBER_OF_NODES = 2;
// Document URI index, which increases by 1 at each getDocumentURI() call.
private static int _documentURIIndex = 0;
// Constant for empty String
private static final String EMPTY_STR = "";
// The String value of the Text node.
// This is set at the endDocument() call.
private String _text;
// The array of Text items, which is built by the characters() call.
// The characters() interface can be called multiple times. Each character item
// can have different escape settings.
protected String[] _textArray;
// The DTMManager
protected XSLTCDTMManager _dtmManager;
// Number of character items
protected int _size = 0;
// The document ID
private int _documentID;
// A BitArray, each bit holding the escape setting for a character item.
private BitArray _dontEscape = null;
// The current escape setting
private boolean _escaping = true;
// Create a SimpleResultTreeImpl from a DTMManager and a document ID.
public SimpleResultTreeImpl(XSLTCDTMManager dtmManager, int documentID)
{
_dtmManager = dtmManager;
_documentID = documentID;
_textArray = new String[4];
}
public DTMManagerDefault getDTMManager()
{
return _dtmManager;
}
// Return the document ID
public int getDocument()
{
return _documentID;
}
// Return the String value of the RTF
public String getStringValue()
{
return _text;
}
public DTMAxisIterator getIterator()
{
return new SingletonIterator(getDocument());
}
public DTMAxisIterator getChildren(final int node)
{
return new SimpleIterator().setStartNode(node);
}
public DTMAxisIterator getTypedChildren(final int type)
{
return new SimpleIterator(SimpleIterator.DIRECTION_DOWN, type);
}
// Return the axis iterator for a given axis.
// The SimpleIterator is used for the child, descendant, parent and ancestor axes.
public DTMAxisIterator getAxisIterator(final int axis)
{
switch (axis)
{
case Axis.CHILD:
case Axis.DESCENDANT:
return new SimpleIterator(SimpleIterator.DIRECTION_DOWN);
case Axis.PARENT:
case Axis.ANCESTOR:
return new SimpleIterator(SimpleIterator.DIRECTION_UP);
case Axis.ANCESTORORSELF:
return (new SimpleIterator(SimpleIterator.DIRECTION_UP)).includeSelf();
case Axis.DESCENDANTORSELF:
return (new SimpleIterator(SimpleIterator.DIRECTION_DOWN)).includeSelf();
case Axis.SELF:
return new SingletonIterator();
default:
return EMPTY_ITERATOR;
}
}
public DTMAxisIterator getTypedAxisIterator(final int axis, final int type)
{
switch (axis)
{
case Axis.CHILD:
case Axis.DESCENDANT:
return new SimpleIterator(SimpleIterator.DIRECTION_DOWN, type);
case Axis.PARENT:
case Axis.ANCESTOR:
return new SimpleIterator(SimpleIterator.DIRECTION_UP, type);
case Axis.ANCESTORORSELF:
return (new SimpleIterator(SimpleIterator.DIRECTION_UP, type)).includeSelf();
case Axis.DESCENDANTORSELF:
return (new SimpleIterator(SimpleIterator.DIRECTION_DOWN, type)).includeSelf();
case Axis.SELF:
return new SingletonIterator(type);
default:
return EMPTY_ITERATOR;
}
}
// %REVISIT% Can this one ever get used?
public DTMAxisIterator getNthDescendant(int node, int n, boolean includeself)
{
return null;
}
public DTMAxisIterator getNamespaceAxisIterator(final int axis, final int ns)
{
return null;
}
// %REVISIT% Can this one ever get used?
public DTMAxisIterator getNodeValueIterator(DTMAxisIterator iter, int returnType,
String value, boolean op)
{
return null;
}
public DTMAxisIterator orderNodes(DTMAxisIterator source, int node)
{
return source;
}
public String getNodeName(final int node)
{
if (getNodeIdent(node) == RTF_TEXT)
return "#text";
else
return EMPTY_STR;
}
public String getNodeNameX(final int node)
{
return EMPTY_STR;
}
public String getNamespaceName(final int node)
{
return EMPTY_STR;
}
// Return the expanded type id of a given node
public int getExpandedTypeID(final int nodeHandle)
{
int nodeID = getNodeIdent(nodeHandle);
if (nodeID == RTF_TEXT)
return DTM.TEXT_NODE;
else if (nodeID == RTF_ROOT)
return DTM.ROOT_NODE;
else
return DTM.NULL;
}
public int getNamespaceType(final int node)
{
return 0;
}
public int getParent(final int nodeHandle)
{
int nodeID = getNodeIdent(nodeHandle);
return (nodeID == RTF_TEXT) ? getNodeHandle(RTF_ROOT) : DTM.NULL;
}
public int getAttributeNode(final int gType, final int element)
{
return DTM.NULL;
}
public String getStringValueX(final int nodeHandle)
{
int nodeID = getNodeIdent(nodeHandle);
if (nodeID == RTF_ROOT || nodeID == RTF_TEXT)
return _text;
else
return EMPTY_STR;
}
public void copy(final int node, SerializationHandler handler)
throws TransletException
{
characters(node, handler);
}
public void copy(DTMAxisIterator nodes, SerializationHandler handler)
throws TransletException
{
int node;
while ((node = nodes.next()) != DTM.NULL)
{
copy(node, handler);
}
}
public String shallowCopy(final int node, SerializationHandler handler)
throws TransletException
{
characters(node, handler);
return null;
}
public boolean lessThan(final int node1, final int node2)
{
if (node1 == DTM.NULL) {
return false;
}
else if (node2 == DTM.NULL) {
return true;
}
else
return (node1 < node2);
}
/**
* Dispatch the character content of a node to an output handler.
*
* The escape setting should be taken care of when outputting to
* a handler.
*/
public void characters(final int node, SerializationHandler handler)
throws TransletException
{
int nodeID = getNodeIdent(node);
if (nodeID == RTF_ROOT || nodeID == RTF_TEXT) {
boolean escapeBit = false;
boolean oldEscapeSetting = false;
try {
for (int i = 0; i < _size; i++) {
if (_dontEscape != null) {
escapeBit = _dontEscape.getBit(i);
if (escapeBit) {
oldEscapeSetting = handler.setEscaping(false);
}
}
handler.characters(_textArray[i]);
if (escapeBit) {
handler.setEscaping(oldEscapeSetting);
}
}
} catch (SAXException e) {
throw new TransletException(e);
}
}
}
// %REVISIT% Can the makeNode() and makeNodeList() interfaces ever get used?
public Node makeNode(int index)
{
return null;
}
public Node makeNode(DTMAxisIterator iter)
{
return null;
}
public NodeList makeNodeList(int index)
{
return null;
}
public NodeList makeNodeList(DTMAxisIterator iter)
{
return null;
}
public String getLanguage(int node)
{
return null;
}
public int getSize()
{
return 2;
}
public String getDocumentURI(int node)
{
return "simple_rtf" + _documentURIIndex++;
}
public void setFilter(StripFilter filter)
{
}
public void setupMapping(String[] names, String[] uris, int[] types, String[] namespaces)
{
}
public boolean isElement(final int node)
{
return false;
}
public boolean isAttribute(final int node)
{
return false;
}
public String lookupNamespace(int node, String prefix)
throws TransletException
{
return null;
}
/**
* Return the node identity from a node handle.
*/
public int getNodeIdent(final int nodehandle)
{
return (nodehandle != DTM.NULL) ? (nodehandle - _documentID) : DTM.NULL;
}
/**
* Return the node handle from a node identity.
*/
public int getNodeHandle(final int nodeId)
{
return (nodeId != DTM.NULL) ? (nodeId + _documentID) : DTM.NULL;
}
public DOM getResultTreeFrag(int initialSize, int rtfType)
{
return null;
}
public DOM getResultTreeFrag(int initialSize, int rtfType, boolean addToManager)
{
return null;
}
public SerializationHandler getOutputDomBuilder()
{
return this;
}
public int getNSType(int node)
{
return 0;
}
public String getUnparsedEntityURI(String name)
{
return null;
}
public Map