com.ximpleware.AutoPilot Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vtd-xml Show documentation
Show all versions of vtd-xml Show documentation
XimpleWare's VTD-XML is, far and away, the industry's most advanced and powerful XML processing model for SOA and Cloud Computing
The newest version!
/*
* Copyright (C) 2002-2017 XimpleWare, [email protected]
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*VTD-XML is protected by US patent 7133857, 7260652, an 7761459*/
/*All licenses to any parties in litigation with XimpleWare have been expressly terminated. No new license, and no renewal of any revoked license,
* is granted to those parties as a result of re-downloading software from this or any other website*/
package com.ximpleware;
import com.ximpleware.xpath.*;
import java.util.*;
import java.io.*;
/**
* XimpleWare's AutoPilot implementation encapsulating node iterator and XPath.
*
*/
public class AutoPilot {
protected int depth;
// the depth of the element at the starting point will determine when to
// stop iteration
protected int iter_type; // see selectElement
protected VTDNav vn; // the navigator object
protected int index; // for iterAttr
protected int endIndex;
protected boolean ft; // a helper variable for
protected boolean special; // This helps distinguish between
// the case of node() and * for preceding axis
// of xpath evaluation
protected String name; // Store element name after selectElement
protected String name2; // store xmlns:+name
protected String localName; // Store local name after selectElemntNS
protected String URL; // Store URL name after selectElementNS
protected int size; // for iterateAttr
protected Expr xpe; // for evalXPath
protected int[] contextCopy; // for preceding axis
protected int stackSize; // the stack size for xpath evaluation
private FastIntBuffer fib; // for namespace axis
static protected Hashtable nsHash;
protected boolean enableCaching;
// private parser p;
// defines the type of "iteration"
public final static int UNDEFINED = 0;
// set the mode corresponding to DOM's getElemetnbyName(string)
public final static int SIMPLE = 1;
// set the mode corresponding to DOM's getElementbyNameNS(string)
public final static int SIMPLE_NS = 2;
public final static int DESCENDANT = 3;
public final static int DESCENDANT_NS = 4;
public final static int FOLLOWING = 5;
public final static int FOLLOWING_NS = 6;
public final static int PRECEDING = 7;
public final static int PRECEDING_NS = 8;
public final static int ATTR = 9;
public final static int ATTR_NS = 10;
public final static int NAME_SPACE = 11;
public final static int SIMPLE_NODE = 12;
public final static int DESCENDANT_NODE = 13;
public final static int FOLLOWING_NODE = 14;
public final static int PRECEDING_NODE = 15;
private Hashtable symbolHash;
// static int count=0;
protected String getName() {
return name;
}
/**
* AutoPilot constructor comment.
*
* @exception IllegalArgumentException
* If the VTDNav object is null
*/
public AutoPilot(VTDNav v) {
if (v == null)
throw new IllegalArgumentException(" instance of VTDNav can't be null ");
name = null;
vn = v;
// depth = v.getCurrentDepth();
iter_type = UNDEFINED; // not defined
ft = true;
size = 0;
special = false;
xpe = null;
symbolHash = new Hashtable();
fib = null;
enableCaching = true;
// fib = new FastIntBuffer(4);
// p = null;
// count=0;
}
/**
* Use this constructor for delayed binding to VTDNav which allows the reuse
* of XPath expression
*
*/
public AutoPilot() {
name = null;
// vn = v;
// depth = v.getCurrentDepth();
iter_type = UNDEFINED; // not defined
ft = true;
size = 0;
special = false;
xpe = null;
symbolHash = new Hashtable();
fib = null;
enableCaching = true;
// count=0;
}
/**
* This function creates URL ns prefix and is intended to be called prior to
* selectXPath
*
* @param prefix
* @param URL
*/
final public void declareXPathNameSpace(String prefix, String URL) {
if (nsHash == null)
nsHash = new Hashtable();
nsHash.put(prefix, URL);
// System.out.println(ht);
}
/**
* Bind is to replace rebind() and setVTDNav() It resets the internal state
* of AutoPilot so one can attach a VTDNav object to the autopilot
*
* @param vnv
*
*/
public void bind(VTDNav vnv) {
name = null;
if (vnv == null)
throw new IllegalArgumentException(" instance of VTDNav can't be null ");
vn = vnv;
// depth = v.getCurrentDepth();
iter_type = UNDEFINED; // not defined
ft = true;
size = 0;
special = false;
// count = 0;
// resetXPath();
}
/**
* Register the binding between a variableExpr name and variableExpr
* expression
*
* @param varName
* @param varExpr
* @throws XPathParseException
*/
public void declareVariableExpr(String varName, String varExpr) throws XPathParseException {
try {
parser p = new parser(new StringReader(varExpr));
p.nsHash = nsHash;
p.symbolHash = symbolHash;
xpe = (Expr) p.parse().value;
symbolHash.put(varName, xpe);
ft = true;
} catch (XPathParseException e) {
System.out.println("Syntax error after or around the end of ==>" + varExpr.substring(0, e.getOffset()));
throw e;
} catch (Exception e) {
throw new XPathParseException("Error occurred");
}
}
/**
* Remove all declared variable expressions
*/
final public void clearVariableExprs() {
symbolHash.clear();
}
/**
* Remove all namespaces bindings
*/
final public void clearXPathNameSpaces() {
nsHash.clear();
}
public boolean iterate2() throws PilotException, NavException {
// count++;
// System.out.println("count-=>"+count);
switch (iter_type) {
case SIMPLE_NODE:
if (ft && vn.atTerminal)
return false;
if (ft) {
ft = false;
return true;
}
return vn.iterateNode(depth);
case DESCENDANT_NODE:
if (ft && vn.atTerminal)
return false;
else {
ft = false;
return vn.iterateNode(depth);
}
case FOLLOWING_NODE:
if (ft) {
boolean b = false;
do {
b = vn.toNode(VTDNav.NEXT_SIBLING);
if (b) {
ft = false;
return true;
} else {
b = vn.toNode(VTDNav.PARENT);
}
} while (b);
return false;
}
return vn.iterate_following_node();
case PRECEDING_NODE:
if (ft) {
ft = false;
vn.toNode(VTDNav.ROOT);
vn.toNode(VTDNav.P);
}
return vn.iterate_preceding_node(contextCopy, endIndex);
// case
default:
throw new PilotException(" iteration action type undefined");
}
}
/**
* Iterate over all the selected element nodes in document order. Null
* element name allowed, corresponding to node() in xpath Creation date:
* (12/4/03 5:25:42 PM)
*
* @return boolean
* @exception com.ximpleware.NavException
* See description in method toElement() in VTDNav class.
*/
public boolean iterate() throws PilotException, NavException {
// count++;
// System.out.println("count-=>"+count);
switch (iter_type) {
case SIMPLE:
// System.out.println("iterating ---> "+name+ " depth ---> "+depth);
/*
* if (elementName == null) throw new PilotException(
* " Element name not set ");
*/
if (vn.atTerminal)
return false;
if (ft == false)
return vn.iterate(depth, name, special);
else {
ft = false;
if (special || vn.matchElement(name)) {
return true;
} else
return vn.iterate(depth, name, special);
}
case SIMPLE_NS:
if (vn.atTerminal)
return false;
if (ft == false)
return vn.iterateNS(depth, URL, localName);
else {
ft = false;
if (vn.matchElementNS(URL, localName)) {
return true;
} else
return vn.iterateNS(depth, URL, localName);
}
case DESCENDANT:
if (vn.atTerminal)
return false;
return vn.iterate(depth, name, special);
case DESCENDANT_NS:
if (vn.atTerminal)
return false;
return vn.iterateNS(depth, URL, localName);
case FOLLOWING:
/*
* if (vn.atTerminal) return false;
*/
if (ft == false)
return vn.iterate_following(name, special);
else {
if (vn.atTerminal && ((vn.getTokenType(vn.LN) == VTDNav.TOKEN_ATTR_NAME)
|| vn.getTokenType(vn.LN) == VTDNav.TOKEN_ATTR_NS))
return false;
ft = false;
// find the first next sibling of
while (true) {
while (vn.toElement(VTDNav.NS)) {
if (special || vn.matchElement(name)) {
return true;
}
return vn.iterate_following(name, special);
}
if (vn.toElement(VTDNav.P) == false) {
// return vn.iterate_following(name, special);
return false;
}
}
}
case FOLLOWING_NS:
/*if (vn.atTerminal)
return false;*/
if (ft == false)
return vn.iterate_followingNS(URL, localName);
else {
if (vn.atTerminal && ((vn.getTokenType(vn.LN) == VTDNav.TOKEN_ATTR_NAME)
|| vn.getTokenType(vn.LN) == VTDNav.TOKEN_ATTR_NS))
return false;
ft = false;
// find the first next sibling of
while (true) {
while (vn.toElement(VTDNav.NS)) {
if (vn.matchElementNS(URL, localName)) {
return true;
}
return vn.iterate_followingNS(URL, localName);
}
if (vn.toElement(VTDNav.P) == false) {
return false;
}
}
}
case PRECEDING:
if (ft) {
if (vn.atTerminal && ((vn.getTokenType(vn.LN) == VTDNav.TOKEN_ATTR_NAME)
|| vn.getTokenType(vn.LN) == VTDNav.TOKEN_ATTR_NS))
return false;
ft = false;
vn.toElement(VTDNav.ROOT);
}
return vn.iterate_preceding(name, contextCopy, endIndex);
case PRECEDING_NS:
if (ft) {
if (vn.atTerminal && ((vn.getTokenType(vn.LN) == VTDNav.TOKEN_ATTR_NAME)
|| vn.getTokenType(vn.LN) == VTDNav.TOKEN_ATTR_NS))
return false;
ft = false;
vn.toElement(VTDNav.ROOT);
}
return vn.iterate_precedingNS(URL, localName, contextCopy, endIndex);
default:
throw new PilotException(" iteration action type undefined");
}
}
/**
* This method implements the namespace axis for XPath
*
* @return
* @throws PilotException
* @throws NavException
*/
protected int iterateNameSpace() throws PilotException, NavException {
if (vn.ns == false)
return -1;
if (ft != false) {
ft = false;
index = vn.getCurrentIndex2() + 1;
} else
index += 2;
while (index < size) {
int type = vn.getTokenType(index);
if (type == VTDNav.TOKEN_ATTR_NAME || type == VTDNav.TOKEN_ATTR_NS) {
if (type == VTDNav.TOKEN_ATTR_NS) {
if (name.equals("*") || vn.matchRawTokenString(index, name2)) {
// check to see if the namespace has appeared before
if (checkNsUniqueness(index)) {
vn.LN = index;
vn.atTerminal = true;
return index;
}
}
}
index += 2;
} else {
vn.atTerminal = false;
if (vn.toElement(VTDNav.P) == false) {
return -1;
} else {
index = vn.getCurrentIndex2() + 1;
}
}
}
return -1;
}
protected boolean checkNsUniqueness(int i) throws NavException {
for (int j = 0; j < fib.size(); j++) {
if (vn.compareTokens(fib.intAt(j), vn, i) == 0)
return false;
}
fib.append(i);
return true;
}
/**
* This method implements the attribute axis for XPath
*
* @return the integer of the selected VTD index for attribute name
* @throws PilotException
*/
protected int iterateAttr2() throws PilotException, NavException {
switch (iter_type) {
case ATTR:
if (name.compareTo("*") == 0) {
if (ft != false) {
ft = false;
index = vn.getCurrentIndex2() + 1;
} else
index += 2;
if (vn.ns == false) {
while (index < size) {
int type = vn.getTokenType(index);
if (type == VTDNav.TOKEN_ATTR_NAME || type == VTDNav.TOKEN_ATTR_NS) {
vn.LN = index;
// vn.atTerminal=true;
return index;
} else {
return -1;
}
}
return -1;
} else {
while (index < size) {
int type = vn.getTokenType(index);
if (type == VTDNav.TOKEN_ATTR_NAME || type == VTDNav.TOKEN_ATTR_NS) {
if (type == VTDNav.TOKEN_ATTR_NAME) {
vn.LN = index;
// vn.atTerminal=true;
return index;
} else
index += 2;
} else {
return -1;
}
}
return -1;
}
} else {
if (ft == false) {
return -1;
} else {
ft = false;
int i = vn.getAttrVal(name);
if (i != -1) {
vn.LN = i - 1;
// vn.atTerminal=true;
return i - 1;
} else {
return -1;
}
}
}
case ATTR_NS:
if (ft == false) {
return -1;
} else {
ft = false;
int i = vn.getAttrValNS(URL, localName);
if (i != -1) {
vn.LN = i - 1;
// vn.atTerminal=true;
return i - 1;
} else {
return -1;
}
}
default:
throw new PilotException("invalid iteration type");
}
}
/**
* This method is meant to be called after calling selectAttr() or
* selectAttrNs(), it will return the vtd index attribute name or -1 if
* there is none left
*
* @return vtd index attribute name or -1 if there is none left
* @throws PilotException
* @throws NavException
*/
public int iterateAttr() throws PilotException, NavException {
switch (iter_type) {
case ATTR:
if (name.compareTo("*") == 0) {
if (ft != false) {
ft = false;
index = vn.getCurrentIndex2() + 1;
} else
index += 2;
if (vn.ns == false) {
while (index < size) {
int type = vn.getTokenType(index);
if (type == VTDNav.TOKEN_ATTR_NAME || type == VTDNav.TOKEN_ATTR_NS) {
// vn.LN = index;
return index;
} else {
return -1;
}
}
return -1;
} else {
while (index < size) {
int type = vn.getTokenType(index);
if (type == VTDNav.TOKEN_ATTR_NAME || type == VTDNav.TOKEN_ATTR_NS) {
if (type == VTDNav.TOKEN_ATTR_NAME) {
// vn.LN = index;
return index;
} else
index += 2;
} else {
return -1;
}
}
return -1;
}
} else {
if (ft == false) {
return -1;
} else {
ft = false;
int i = vn.getAttrVal(name);
if (i != -1) {
// vn.LN = i-1;
return i - 1;
} else
return -1;
}
}
case ATTR_NS:
if (ft == false) {
return -1;
} else {
ft = false;
int i = vn.getAttrValNS(URL, localName);
if (i != -1) {
// vn.LN = i -1;
return i - 1;
} else
return -1;
}
default:
throw new PilotException("invalid iteration type");
}
}
final protected void selectNode() {
ft = true;
depth = vn.getCurrentDepth();
iter_type = SIMPLE_NODE;
}
final protected void selectPrecedingNode() {
ft = true;
depth = vn.getCurrentDepth();
contextCopy = (int[]) vn.context.clone();
if (contextCopy[0] != -1) {
for (int i = contextCopy[0] + 1; i < contextCopy.length; i++) {
contextCopy[i] = 0;
}
} // else{
// for (int i=1;i" + s.substring(0, e.getOffset()));
throw e;
} catch (Exception e) {
throw new XPathParseException("Error occurred");
}
}
/**
* Reset the XPath so the XPath Expression can be reused and revaluated in
* anther context position
*
*/
final public void resetXPath() {
if (xpe != null && vn != null) {
xpe.reset(vn);
ft = true;
vn.contextStack2.size = stackSize;
if (enableCaching)
xpe.clearCache();
}
}
/**
* evalXPathToNumber() evaluates the xpath expression to a double
*
* @return double
*
*/
final public double evalXPathToNumber() {
return xpe.evalNumber(vn);
}
/**
* evalXPathToString() evaluates the xpath expression to a String
*
* @return String
*
*/
final public String evalXPathToString() {
return xpe.evalString(vn);
}
/**
* evalXPathToBoolean() evaluates the xpath expression to a boolean
*
* @return boolean
*
*/
final public boolean evalXPathToBoolean() {
return xpe.evalBoolean(vn);
}
/**
* This method returns the next node in the nodeset it returns -1 if there
* is no more node Afer finishing evaluating, don't forget to
* reset the xpath
*
* @return int corresponding to the VTD index
*/
public int evalXPath() throws XPathEvalException, NavException {
if (xpe != null) {
if (ft == true) {
if (vn != null) {
stackSize = vn.contextStack2.size;
}
ft = false;
xpe.adjust(vn.getTokenCount());
}
return xpe.evalNodeSet(vn);
}
throw new PilotException(" Null XPath expression ");
}
/**
* Setspecial is used by XPath evaluator to distinguish between node() and *
* node() corresponding to b= true;
*
* @param b
*/
final protected void setSpecial(boolean b) {
special = b;
}
/**
* Convert the expression to a string For debugging purpose
*
* @return String
*/
final public String getExprString() {
return xpe.toString();
}
/**
* set state to false to disable caching, which by default is enabled This
* method will turn on the internal caching feature during xpath evaluation,
* which is to store the evaluation results of absolute expressions when
* they resides in a predicate examples: //a[//bb=//cc] //bb and //cc are
* cached internally to avoid repeitive computation..
*
* @param state
*/
final public void enableCaching(boolean state) {
enableCaching = state;
}
final public VTDNav getNav() {
return vn;
}
}