com.hp.hpl.sparta.XPathVisitor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pinyin4j-multi Show documentation
Show all versions of pinyin4j-multi Show documentation
Support Chinese character (both Simplified and Tranditional) to most popular Pinyin systems, including
Hanyu Pinyin, Tongyong Pinyin, Wade-Giles, MPS2, Yale and Gwoyeu Romatzyh. Support multiple pronounciations and
customized output.
The newest version!
package com.hp.hpl.sparta;
import com.hp.hpl.sparta.xpath.*;
import java.io.IOException;
import java.util.*;
/**
* Visitor that evaluates an xpath expression relative to a context
* node by walking over the parse tree of the expression.
Copyright (C) 2002 Hewlett-Packard Company.
This file is part of Sparta, an XML Parser, DOM, and XPath library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU
Lesser General Public License as published by the Free Software
Foundation; either version 2.1 of the License, or (at your option)
any later version. This library 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.
@version $Date: 2003/08/11 18:48:39 $ $Revision: 1.9 $
@author Eamonn O'Brien-Strain
* @stereotype visitor */
class XPathVisitor implements Visitor {
/** Evaluate a relative xpath expression relative to a context
* element by walking over the parse tree of th expression. */
private XPathVisitor(XPath xpath, Node context) throws XPathException {
xpath_ = xpath;
contextNode_ = context;
nodelistFiltered_ = new Vector(1);
nodelistFiltered_.addElement(contextNode_);
for (Enumeration i = xpath.getSteps(); i.hasMoreElements();) {
Step step = (Step) i.nextElement();
multiLevel_ = step.isMultiLevel();
nodesetIterator_ = null;
step.getNodeTest().accept(this);
nodesetIterator_ = nodelistRaw_.iterator();
nodelistFiltered_.removeAllElements();
BooleanExpr predicate = step.getPredicate();
while (nodesetIterator_.hasMoreElements()) {
node_ = nodesetIterator_.nextElement();
predicate.accept(this);
Boolean expr = exprStack_.pop();
if (expr.booleanValue()) nodelistFiltered_.addElement(node_);
}
}
}
/** Evaluate a relative xpath expression relative to a context
* element by walking over the parse tree of th expression. */
public XPathVisitor(Element context, XPath xpath) throws XPathException {
this(xpath, context);
if (xpath.isAbsolute())
throw new XPathException(xpath, "Cannot use element as context node for absolute xpath");
}
/** Evaluate an absolute xpath expression in a document by walking
over the parse tree of th expression. */
public XPathVisitor(Document context, XPath xpath) throws XPathException {
this(xpath, context);
}
public void visit(ThisNodeTest a) {
nodelistRaw_.removeAllElements();
nodelistRaw_.add(contextNode_, 1);
}
/** @throws XPathException if ".." applied to node with no parent. */
public void visit(ParentNodeTest a) throws XPathException {
nodelistRaw_.removeAllElements();
Node parent = contextNode_.getParentNode();
if (parent == null)
throw new XPathException(xpath_,
"Illegal attempt to apply \"..\" to node with no parent.");
nodelistRaw_.add(parent, 1);
}
public void visit(AllElementTest a) {
Vector oldNodeList = nodelistFiltered_;
nodelistRaw_.removeAllElements();
for (Enumeration i = oldNodeList.elements(); i.hasMoreElements();) {
Object node = i.nextElement();
if (node instanceof Element)
accumulateElements((Element) node);
else if (node instanceof Document) accumulateElements((Document) node);
}
}
private void accumulateElements(Document doc) {
Element child = doc.getDocumentElement();
nodelistRaw_.add(child, 1);
if (multiLevel_) accumulateElements(child); //recursive call
}
private void accumulateElements(Element element) {
int position = 0;
for (Node n = element.getFirstChild(); n != null; n = n.getNextSibling()) {
if (n instanceof Element) {
nodelistRaw_.add(n, ++position);
if (multiLevel_) accumulateElements((Element) n); //recursive call
}
}
}
public void visit(TextTest a) {
Vector oldNodeList = nodelistFiltered_;
nodelistRaw_.removeAllElements();
for (Enumeration i = oldNodeList.elements(); i.hasMoreElements();) {
Object node = i.nextElement();
if (node instanceof Element) {
Element element = (Element) node;
for (Node n = element.getFirstChild(); n != null; n = n.getNextSibling())
if (n instanceof Text) nodelistRaw_.add(((Text) n).getData());
}
}
}
public void visit(ElementTest test) {
String tagName = test.getTagName();
Vector oldNodeList = nodelistFiltered_;
int n = oldNodeList.size();
nodelistRaw_.removeAllElements();
for (int i = 0; i < n; ++i) {
Object node = oldNodeList.elementAt(i);
if (node instanceof Element)
accumulateMatchingElements((Element) node, tagName);
else if (node instanceof Document)
accumulateMatchingElements((Document) node, tagName);
}
}
private void accumulateMatchingElements(Document document, String tagName) {
Element child = document.getDocumentElement();
if (child == null) return; //no document element
if (child.getTagName() == tagName) //both strings interned
nodelistRaw_.add(child, 1);
if (multiLevel_) accumulateMatchingElements(child, tagName); //recursive call
}
private void accumulateMatchingElements(Element element, String tagName) {
int position = 0;
for (Node n = element.getFirstChild(); n != null; n = n.getNextSibling()) {
if (n instanceof Element) {
Element child = (Element) n;
if (child.getTagName() == tagName) //both strings interned
nodelistRaw_.add(child, ++position);
if (multiLevel_) accumulateMatchingElements(child, tagName); //recursion
}
}
}
public void visit(AttrTest test) {
Vector oldNodeList = nodelistFiltered_;
nodelistRaw_.removeAllElements();
for (Enumeration i = oldNodeList.elements(); i.hasMoreElements();) {
Node node = (Node) i.nextElement();
if (node instanceof Element) {
Element element = (Element) node;
String attr = element.getAttribute(test.getAttrName());
if (attr != null) nodelistRaw_.add(attr);
}
}
}
static private final Boolean TRUE = new Boolean(true);
static private final Boolean FALSE = new Boolean(false);
public void visit(TrueExpr a) {
exprStack_.push(TRUE);
}
public void visit(AttrExistsExpr a) throws XPathException {
if (!(node_ instanceof Element))
throw new XPathException(xpath_, "Cannot test attribute of document");
Element element = (Element) node_;
String attrValue = element.getAttribute(a.getAttrName());
boolean result = attrValue != null && attrValue.length() > 0;
exprStack_.push(result ? TRUE : FALSE);
}
public void visit(AttrEqualsExpr a) throws XPathException {
if (!(node_ instanceof Element))
throw new XPathException(xpath_, "Cannot test attribute of document");
Element element = (Element) node_;
String attrValue = element.getAttribute(a.getAttrName());
boolean result = a.getAttrValue().equals(attrValue);
exprStack_.push(result ? TRUE : FALSE);
}
public void visit(AttrNotEqualsExpr a) throws XPathException {
if (!(node_ instanceof Element))
throw new XPathException(xpath_, "Cannot test attribute of document");
Element element = (Element) node_;
String attrValue = element.getAttribute(a.getAttrName());
boolean result = !a.getAttrValue().equals(attrValue);
exprStack_.push(result ? TRUE : FALSE);
}
public void visit(AttrLessExpr a) throws XPathException {
if (!(node_ instanceof Element))
throw new XPathException(xpath_, "Cannot test attribute of document");
Element element = (Element) node_;
// Use jdk1.1 API to make the code work with PersonalJava.
// double attrValue = Double.parseDouble( element.getAttribute( a.getAttrName() ) );
long attrValue = Long.parseLong(element.getAttribute(a.getAttrName()));
boolean result = attrValue < a.getAttrValue();
exprStack_.push(result ? TRUE : FALSE);
}
public void visit(AttrGreaterExpr a) throws XPathException {
if (!(node_ instanceof Element))
throw new XPathException(xpath_, "Cannot test attribute of document");
Element element = (Element) node_;
// Use jdk1.1 API to make the code work with PersonalJava.
// double attrValue = Double.parseDouble( element.getAttribute( a.getAttrName() ) );
long attrValue = Long.parseLong(element.getAttribute(a.getAttrName()));
boolean result = attrValue > a.getAttrValue();
exprStack_.push(result ? TRUE : FALSE);
}
public void visit(TextExistsExpr a) throws XPathException {
if (!(node_ instanceof Element))
throw new XPathException(xpath_, "Cannot test attribute of document");
Element element = (Element) node_;
for (Node i = element.getFirstChild(); i != null; i = i.getNextSibling()) {
if (i instanceof Text) {
exprStack_.push(TRUE);
return;
}
}
exprStack_.push(FALSE);
}
public void visit(TextEqualsExpr a) throws XPathException {
if (!(node_ instanceof Element))
throw new XPathException(xpath_, "Cannot test attribute of document");
Element element = (Element) node_;
for (Node i = element.getFirstChild(); i != null; i = i.getNextSibling()) {
if (i instanceof Text) {
Text text = (Text) i;
if (text.getData().equals(a.getValue())) {
exprStack_.push(TRUE);
return;
}
}
}
exprStack_.push(FALSE);
}
public void visit(TextNotEqualsExpr a) throws XPathException {
if (!(node_ instanceof Element))
throw new XPathException(xpath_, "Cannot test attribute of document");
Element element = (Element) node_;
for (Node i = element.getFirstChild(); i != null; i = i.getNextSibling()) {
if (i instanceof Text) {
Text text = (Text) i;
if (!text.getData().equals(a.getValue())) {
exprStack_.push(TRUE);
return;
}
}
}
exprStack_.push(FALSE);
}
public void visit(PositionEqualsExpr a) throws XPathException {
if (!(node_ instanceof Element))
throw new XPathException(xpath_, "Cannot test position of document");
Element element = (Element) node_;
boolean result = (nodelistRaw_.position(element) == a.getPosition());
exprStack_.push(result ? TRUE : FALSE);
}
/** Get all the elements or strings that match the xpath expression. */
public Enumeration getResultEnumeration() {
return nodelistFiltered_.elements();
}
/** Get the first element that match the xpath expression, or null. */
public Element getFirstResultElement() {
return nodelistFiltered_.size() == 0 ? null : (Element) nodelistFiltered_.elementAt(0);
}
/** Get the first string that match the xpath expression, or null. */
public String getFirstResultString() {
return nodelistFiltered_.size() == 0 ? null : (String) nodelistFiltered_.elementAt(0)
.toString();
}
/*
static private class BooleanStack extends LinkedList{
void push(Boolean b){
addLast(b);
}
Boolean pop(){
return (Boolean)removeLast();
}
}
*/
/** Profiling found this to be very heavily used so do not use java.util.LinkedList */
static private class BooleanStack {
private Item top_ = null;
static private class Item {
Item(Boolean b, Item p) {
bool = b;
prev = p;
}
final Boolean bool;
final Item prev;
}
void push(Boolean b) {
top_ = new Item(b, top_);
}
Boolean pop() {
Boolean result = top_.bool;
top_ = top_.prev;
return result;
}
}
/** @associates Node. */
private final NodeListWithPosition nodelistRaw_ = new NodeListWithPosition();
private Vector nodelistFiltered_ = new Vector();
private Enumeration nodesetIterator_ = null;
private Object node_ = null; //String or Element
private final BooleanStack exprStack_ = new BooleanStack();
/**
* @label context
*/
private/*final (JDK11 problems)*/
Node contextNode_;
private boolean multiLevel_;
private/*final (JDK11 problems)*/
XPath xpath_;
}
/** A list of nodes, together with the positions in their context of
each node. */
class NodeListWithPosition {
Enumeration iterator() {
return vector_.elements();
}
void removeAllElements() {
vector_.removeAllElements();
positions_.clear();
}
void add(String string) {
vector_.addElement(string);
}
static private final Integer ONE = new Integer(1);
static private final Integer TWO = new Integer(2);
static private final Integer THREE = new Integer(3);
static private final Integer FOUR = new Integer(4);
static private final Integer FIVE = new Integer(5);
static private final Integer SIX = new Integer(6);
static private final Integer SEVEN = new Integer(7);
static private final Integer EIGHT = new Integer(8);
static private final Integer NINE = new Integer(9);
static private final Integer TEN = new Integer(10);
static private Integer identity(Node node) {
return new Integer(System.identityHashCode(node));
}
void add(Node node, int position) {
//Profiling shows thisto be the most heavily used method in Sparta so
//optimize the crap out of it.
vector_.addElement(node);
//Avoid creating new integer objects for common cases
Integer posn;
switch (position) {
case 1:
posn = ONE;
break;
case 2:
posn = TWO;
break;
case 3:
posn = THREE;
break;
case 4:
posn = FOUR;
break;
case 5:
posn = FIVE;
break;
case 6:
posn = SIX;
break;
case 7:
posn = SEVEN;
break;
case 8:
posn = EIGHT;
break;
case 9:
posn = NINE;
break;
case 10:
posn = TEN;
break;
default:
posn = new Integer(position);
break;
}
positions_.put(identity(node), posn);
}
int position(Node node) {
return ((Integer) positions_.get(identity(node))).intValue();
}
public String toString() {
try {
StringBuffer y = new StringBuffer("{ ");
for (Enumeration i = vector_.elements(); i.hasMoreElements();) {
Object e = i.nextElement();
if (e instanceof String)
y.append("String(" + e + ") ");
else {
Node n = (Node) e;
y.append("Node(" + n.toXml() + ")[" + positions_.get(identity(n)) + "] ");
}
}
y.append("}");
return y.toString();
} catch (IOException e) {
return e.toString();
}
}
private final Vector vector_ = new Vector();
private Hashtable positions_ = new Hashtable();
}
// $Log: XPathVisitor.java,v $
// Revision 1.9 2003/08/11 18:48:39 eobrain
// Fix bug in xpath tag[n] when identical elements.
//
// Revision 1.8 2003/07/17 23:58:40 eobrain
// Make compatiblie with J2ME. For example do not use "new"
// java.util classes.
//
// Revision 1.7 2003/05/12 20:06:14 eobrain
// Performance improvements: optimize code in areas that profiling revealed to be bottlenecks.
//
// Revision 1.6 2003/01/27 23:30:58 yuhongx
// Replaced Hashtable with HashMap.
//
// Revision 1.5 2003/01/09 01:10:50 yuhongx
// Use JDK1.1 API to make the code work with PersonalJava.
//
// Revision 1.4 2002/12/05 04:35:39 eobrain
// Add support for greater than and less than in predicates.
//
// Revision 1.3 2002/10/30 16:28:46 eobrain
// Feature request [ 630127 ] Support /a/b[text()='foo']
// http://sourceforge.net/projects/sparta-xml/
//
// Revision 1.2 2002/09/18 05:29:04 eobrain
// Support xpath predicates of the form [1], [2], ...
//
// Revision 1.1.1.1 2002/08/19 05:03:53 eobrain
// import from HP Labs internal CVS
//
// Revision 1.11 2002/08/18 04:47:47 eob
// Make class package-private so as not to clutter up the javadoc.
//
// Revision 1.10 2002/06/21 00:28:33 eob
// Make work with old JDK 1.1.*
//
// Revision 1.9 2002/06/14 19:34:50 eob
// Add handling of "text()" in XPath expressions.
//
// Revision 1.8 2002/06/04 05:29:28 eob
// Simplify use of visitor pattern to make code easier to understand.
// Fix bug when predicate in middle of XPath.
//
// Revision 1.7 2002/05/23 21:18:52 eob
// Better error reporting.
//
// Revision 1.6 2002/05/10 21:39:28 eob
// Allow documents to take relative xpaths.
//
// Revision 1.5 2002/03/26 01:49:53 eob
// Return different results depending on type. Return first result.
//
// Revision 1.4 2002/03/21 23:54:36 eob
// Fix handling of .. when no parent.
//
// Revision 1.3 2002/02/14 02:21:45 eob
// Handle attribute XPaths.
//
// Revision 1.2 2002/02/04 22:09:44 eob
// add visit(AttrTest)
//
// Revision 1.1 2002/02/01 22:46:12 eob
// initial