/**
* Portions Copyright 2001 Sun Microsystems, Inc.
* Portions Copyright 1999-2001 Language Technologies Institute,
* Carnegie Mellon University.
* All Rights Reserved. Use is subject to license terms.
*
* See the file "license.terms" for information on usage and
* redistribution of this file, and for a DISCLAIMER OF ALL
* WARRANTIES.
*/
package edu.cmu.sphinx.alignment.tokenizer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Interface that Manages a feature or item path. Allows navigation to the
* corresponding feature or item. This class in controlled by the following
* system properties:
*
* <pre>
* com.sun.speech.freetts.interpretCartPaths - default false
* com.sun.speech.freetts.lazyCartCompile - default true
* </pre>
*
* com.sun.speech.freetts.interpretCartPaths
*
* Instances of this class will optionally pre-compile the paths. Pre-compiling
* paths reduces the processing time and objects needed to extract a feature or
* an item based upon a path.
*/
public class PathExtractor {
/** Logger instance. */
private static final Logger LOGGER = Logger
.getLogger(PathExtractor.class.getName());
/**
* If this system property is set to true, paths will not be compiled.
*/
public final static String INTERPRET_PATHS_PROPERTY =
"com.sun.speech.freetts.interpretCartPaths";
/**
* If this system property is set to true, CART feature/item paths will
* only be compiled as needed.
*/
public final static String LAZY_COMPILE_PROPERTY =
"com.sun.speech.freetts.lazyCartCompile";
private final static boolean INTERPRET_PATHS = System.getProperty(
INTERPRET_PATHS_PROPERTY, "false").equals("true");
private final static boolean LAZY_COMPILE = System.getProperty(
LAZY_COMPILE_PROPERTY, "true").equals("true");
private String pathAndFeature;
private String path;
private String feature;
private Object[] compiledPath;
/**
* Creates a path for the given feature.
* @param pathAndFeature string to use
* @param wantFeature do we need features
*/
public PathExtractor(String pathAndFeature, boolean wantFeature) {
this.pathAndFeature = pathAndFeature;
if (INTERPRET_PATHS) {
path = pathAndFeature;
return;
}
if (wantFeature) {
int lastDot = pathAndFeature.lastIndexOf(".");
// string can be of the form "p.feature" or just "feature"
if (lastDot == -1) {
feature = pathAndFeature;
path = null;
} else {
feature = pathAndFeature.substring(lastDot + 1);
path = pathAndFeature.substring(0, lastDot);
}
} else {
this.path = pathAndFeature;
}
if (!LAZY_COMPILE) {
compiledPath = compile(path);
}
}
/**
* Finds the item associated with this Path.
*
* @param item the item to start at
* @return the item associated with the path or null
*/
public Item findItem(Item item) {
if (INTERPRET_PATHS) {
return item.findItem(path);
}
if (compiledPath == null) {
compiledPath = compile(path);
}
Item pitem = item;
for (int i = 0; pitem != null && i < compiledPath.length;) {
OpEnum op = (OpEnum) compiledPath[i++];
if (op == OpEnum.NEXT) {
pitem = pitem.getNext();
} else if (op == OpEnum.PREV) {
pitem = pitem.getPrevious();
} else if (op == OpEnum.NEXT_NEXT) {
pitem = pitem.getNext();
if (pitem != null) {
pitem = pitem.getNext();
}
} else if (op == OpEnum.PREV_PREV) {
pitem = pitem.getPrevious();
if (pitem != null) {
pitem = pitem.getPrevious();
}
} else if (op == OpEnum.PARENT) {
pitem = pitem.getParent();
} else if (op == OpEnum.DAUGHTER) {
pitem = pitem.getDaughter();
} else if (op == OpEnum.LAST_DAUGHTER) {
pitem = pitem.getLastDaughter();
} else if (op == OpEnum.RELATION) {
String relationName = (String) compiledPath[i++];
pitem =
pitem.getSharedContents()
.getItemRelation(relationName);
} else {
System.out.println("findItem: bad feature " + op + " in "
+ path);
}
}
return pitem;
}
/**
* Finds the feature associated with this Path.
*
* @param item the item to start at
* @return the feature associated or "0" if the feature was not found.
*/
public Object findFeature(Item item) {
if (INTERPRET_PATHS) {
return item.findFeature(path);
}
Item pitem = findItem(item);
Object results = null;
if (pitem != null) {
if (LOGGER.isLoggable(Level.FINER)) {
LOGGER.finer("findFeature: Item [" + pitem + "], feature '"
+ feature + "'");
}
results = pitem.getFeatures().getObject(feature);
}
results = (results == null) ? "0" : results;
if (LOGGER.isLoggable(Level.FINER)) {
LOGGER.finer("findFeature: ...results = '" + results + "'");
}
return results;
}
/**
* Compiles the given path into the compiled form
*
* @param path the path to compile
* @return the compiled form which is in the form of an array path
* traversal enums and associated strings
*/
private Object[] compile(String path) {
if (path == null) {
return new Object[0];
}
List<Object> list = new ArrayList<Object>();
StringTokenizer tok = new StringTokenizer(path, ":.");
while (tok.hasMoreTokens()) {
String token = tok.nextToken();
OpEnum op = OpEnum.getInstance(token);
if (op == null) {
throw new Error("Bad path compiled " + path);
}
list.add(op);
if (op == OpEnum.RELATION) {
list.add(tok.nextToken());
}
}
return list.toArray();
}
// inherited for Object
public String toString() {
return pathAndFeature;
}
// TODO: add these to the interface should we support binary
// files
/*
* public void writeBinary(); public void readBinary();
*/
}
/**
* An enumerated type associated with path operations.
*/
class OpEnum {
static private Map<String, OpEnum> map = new HashMap<String, OpEnum>();
public final static OpEnum NEXT = new OpEnum("n");
public final static OpEnum PREV = new OpEnum("p");
public final static OpEnum NEXT_NEXT = new OpEnum("nn");
public final static OpEnum PREV_PREV = new OpEnum("pp");
public final static OpEnum PARENT = new OpEnum("parent");
public final static OpEnum DAUGHTER = new OpEnum("daughter");
public final static OpEnum LAST_DAUGHTER = new OpEnum("daughtern");
public final static OpEnum RELATION = new OpEnum("R");
private String name;
/**
* Creates a new OpEnum.. There is a limited set of OpEnums
*
* @param name the path name for this Enum
*/
private OpEnum(String name) {
this.name = name;
map.put(name, this);
}
/**
* gets an OpEnum thats associated with the given name.
*
* @param name the name of the OpEnum of interest
*/
public static OpEnum getInstance(String name) {
return (OpEnum) map.get(name);
}
// inherited from Object
public String toString() {
return name;
}
}