/*
* Copyright (C) 2009 JavaRosa
*
* Licensed 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 org.openrosa.client.jr.xpath.expr;
import java.io.IOException;
import java.util.Vector;
import org.openrosa.client.java.io.DataInputStream;
import org.openrosa.client.java.io.DataOutputStream;
import org.openrosa.client.jr.core.util.externalizable.DeserializationException;
import org.openrosa.client.jr.core.util.externalizable.ExtUtil;
import org.openrosa.client.jr.core.util.externalizable.ExtWrapListPoly;
import org.openrosa.client.jr.core.util.externalizable.ExtWrapNullable;
import org.openrosa.client.jr.core.util.externalizable.Externalizable;
import org.openrosa.client.jr.core.util.externalizable.PrototypeFactory;
public class XPathStep implements Externalizable {
public static final int AXIS_CHILD = 0;
public static final int AXIS_DESCENDANT = 1;
public static final int AXIS_PARENT = 2;
public static final int AXIS_ANCESTOR = 3;
public static final int AXIS_FOLLOWING_SIBLING = 4;
public static final int AXIS_PRECEDING_SIBLING = 5;
public static final int AXIS_FOLLOWING = 6;
public static final int AXIS_PRECEDING = 7;
public static final int AXIS_ATTRIBUTE = 8;
public static final int AXIS_NAMESPACE = 9;
public static final int AXIS_SELF = 10;
public static final int AXIS_DESCENDANT_OR_SELF = 11;
public static final int AXIS_ANCESTOR_OR_SELF = 12;
public static final int TEST_NAME = 0;
public static final int TEST_NAME_WILDCARD = 1;
public static final int TEST_NAMESPACE_WILDCARD = 2;
public static final int TEST_TYPE_NODE = 3;
public static final int TEST_TYPE_TEXT = 4;
public static final int TEST_TYPE_COMMENT = 5;
public static final int TEST_TYPE_PROCESSING_INSTRUCTION = 6;
public static XPathStep ABBR_SELF () {
return new XPathStep(AXIS_SELF, TEST_TYPE_NODE);
}
public static XPathStep ABBR_PARENT () {
return new XPathStep(AXIS_PARENT, TEST_TYPE_NODE);
}
public static XPathStep ABBR_DESCENDANTS () {
return new XPathStep(AXIS_DESCENDANT_OR_SELF, TEST_TYPE_NODE);
}
public int axis;
public int test;
public XPathExpression[] predicates;
//test-dependent variables
public XPathQName name; //TEST_NAME only
public String namespace; //TEST_NAMESPACE_WILDCARD only
public String literal; //TEST_TYPE_PROCESSING_INSTRUCTION only
public XPathStep () { } //for deserialization
public XPathStep (int axis, int test) {
this.axis = axis;
this.test = test;
this.predicates = new XPathExpression[0];
}
public XPathStep (int axis, XPathQName name) {
this(axis, TEST_NAME);
this.name = name;
}
public XPathStep (int axis, String namespace) {
this(axis, TEST_NAMESPACE_WILDCARD);
this.namespace = namespace;
}
public String toString () {
StringBuffer sb = new StringBuffer();
sb.append("{step:");
sb.append(axisStr(axis));
sb.append(",");
sb.append(testStr());
if (predicates.length > 0) {
sb.append(",{");
for (int i = 0; i < predicates.length; i++) {
sb.append(predicates[i].toString());
if (i < predicates.length - 1)
sb.append(",");
}
sb.append("}");
}
sb.append("}");
return sb.toString();
}
public static String axisStr (int axis) {
switch (axis) {
case AXIS_CHILD: return "child";
case AXIS_DESCENDANT: return "descendant";
case AXIS_PARENT: return "parent";
case AXIS_ANCESTOR: return "ancestor";
case AXIS_FOLLOWING_SIBLING: return "following-sibling";
case AXIS_PRECEDING_SIBLING: return "preceding-sibling";
case AXIS_FOLLOWING: return "following";
case AXIS_PRECEDING: return "preceding";
case AXIS_ATTRIBUTE: return "attribute";
case AXIS_NAMESPACE: return "namespace";
case AXIS_SELF: return "self";
case AXIS_DESCENDANT_OR_SELF: return "descendant-or-self";
case AXIS_ANCESTOR_OR_SELF: return "ancestor-or-self";
default: return null;
}
}
public String testStr () {
switch(test) {
case TEST_NAME: return name.toString();
case TEST_NAME_WILDCARD: return "*";
case TEST_NAMESPACE_WILDCARD: return namespace + ":*";
case TEST_TYPE_NODE: return "node()";
case TEST_TYPE_TEXT: return "text()";
case TEST_TYPE_COMMENT: return "comment()";
case TEST_TYPE_PROCESSING_INSTRUCTION: return "proc-instr(" + (literal == null ? "" : "\'" + literal + "\'") + ")";
default: return null;
}
}
public boolean equals (Object o) {
if (o instanceof XPathStep) {
XPathStep x = (XPathStep)o;
//shortcuts for faster evaluation
if(axis != x.axis && test != x.test || predicates.length != x.predicates.length) {
return false;
}
switch (test) {
case TEST_NAME: if(!name.equals(x.name)) {return false;} break;
case TEST_NAMESPACE_WILDCARD: if(!namespace.equals(x.namespace)) {return false;} break;
case TEST_TYPE_PROCESSING_INSTRUCTION: if(!ExtUtil.equals(literal, x.literal)) {return false;} break;
default: break;
}
return ExtUtil.arrayEquals(predicates, x.predicates);
} else {
return false;
}
}
public void readExternal(DataInputStream in, PrototypeFactory pf) throws IOException, DeserializationException {
axis = ExtUtil.readInt(in);
test = ExtUtil.readInt(in);
switch (test) {
case TEST_NAME: name = (XPathQName)ExtUtil.read(in, XPathQName.class); break;
case TEST_NAMESPACE_WILDCARD: namespace = ExtUtil.readString(in); break;
case TEST_TYPE_PROCESSING_INSTRUCTION: literal = (String)ExtUtil.read(in, new ExtWrapNullable(String.class)); break;
}
Vector v = (Vector)ExtUtil.read(in, new ExtWrapListPoly(), pf);
predicates = new XPathExpression[v.size()];
for (int i = 0; i < predicates.length; i++)
predicates[i] = (XPathExpression)v.elementAt(i);
}
public void writeExternal(DataOutputStream out) throws IOException {
ExtUtil.writeNumeric(out, axis);
ExtUtil.writeNumeric(out, test);
switch (test) {
case TEST_NAME: ExtUtil.write(out, name); break;
case TEST_NAMESPACE_WILDCARD: ExtUtil.writeString(out, namespace); break;
case TEST_TYPE_PROCESSING_INSTRUCTION: ExtUtil.write(out, new ExtWrapNullable(literal)); break;
}
Vector v = new Vector();
for (int i = 0; i < predicates.length; i++)
v.addElement(predicates[i]);
ExtUtil.write(out, new ExtWrapListPoly(v));
}
}