/** * Portions Copyright 2001-2003 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.StringTokenizer; /** * Represents a node in a Relation. Items can have shared contents but each * item has its own set of Daughters. The shared contents of an item * (represented by ItemContents) includes the feature set for the item and the * set of all relations that this item is contained in. An item can be * contained in a number of relations and as daughters to other items. This * class is used to keep track of all of these relationships. There may be many * instances of item that reference the same shared ItemContents. */ public class Item { private Relation ownerRelation; private ItemContents contents; private Item parent; private Item daughter; private Item next; private Item prev; /** * Creates an item. The item is coupled to a particular Relation. If shared * contents is null a new sharedContents is created. * * @param relation the relation that owns this item * @param sharedContents the contents that is shared with others. If null, * a new sharedContents is created. */ public Item(Relation relation, ItemContents sharedContents) { ownerRelation = relation; if (sharedContents != null) { contents = sharedContents; } else { contents = new ItemContents(); } parent = null; daughter = null; next = null; prev = null; getSharedContents().addItemRelation(relation.getName(), this); } /** * Finds the item in the given relation that has the same shared contents. * * @param relationName the relation of interest * * @return the item as found in the given relation or null if not found */ public Item getItemAs(String relationName) { return getSharedContents().getItemRelation(relationName); } /** * Retrieves the owning Relation. * * @return the relation that owns this item */ public Relation getOwnerRelation() { return ownerRelation; } /** * Retrieves the shared contents for this item. * * @return the shared item contents */ public ItemContents getSharedContents() { return contents; } /** * Determines if this item has daughters. * * @return true if this item has daughters */ public boolean hasDaughters() { return daughter != null; } /** * Retrieves the first daughter of this item. * * @return the first daughter or null if none */ public Item getDaughter() { return daughter; } /** * Retrieves the Nth daughter of this item. * * @param which the index of the daughter to return * * @return the Nth daughter or null if none at the given index */ public Item getNthDaughter(int which) { Item d = daughter; int count = 0; while (count++ != which && d != null) { d = d.next; } return d; } /** * Retrieves the last daughter of this item. * * @return the last daughter or null if none at the given index */ public Item getLastDaughter() { Item d = daughter; if (d == null) { return null; } while (d.next != null) { d = d.next; } return d; } /** * Adds the given item as a daughter to this item. * * @param item for the new daughter * @return created item */ public Item addDaughter(Item item) { Item newItem; ItemContents contents; Item p = getLastDaughter(); if (p != null) { newItem = p.appendItem(item); } else { if (item == null) { contents = new ItemContents(); } else { contents = item.getSharedContents(); } newItem = new Item(getOwnerRelation(), contents); newItem.parent = this; daughter = newItem; } return newItem; } /** * Creates a new Item, adds it as a daughter to this item and returns the * new item. * * @return the newly created item that was added as a daughter */ public Item createDaughter() { return addDaughter(null); } /** * Returns the parent of this item. * * @return the parent of this item */ public Item getParent() { Item n; for (n = this; n.prev != null; n = n.prev) { } return n.parent; } /** * Sets the parent of this item. * * @param parent the parent of this item */ /* * private void setParent(Item parent) { this.parent = parent; } */ /** * Returns the utterance associated with this item. * * @return the utterance that contains this item */ public Utterance getUtterance() { return getOwnerRelation().getUtterance(); } /** * Returns the feature set of this item. * * @return the feature set of this item */ public FeatureSet getFeatures() { return getSharedContents().getFeatures(); } /** * Finds the feature by following the given path. Path is a string of ":" * or "." separated strings with the following interpretations: * <ul> * <li>n - next item * <li>p - previous item * <li>parent - the parent * <li>daughter - the daughter * <li>daughter1 - same as daughter * <li>daughtern - the last daughter * <li>R:relname - the item as found in the given relation 'relname' * </ul> * The last element of the path will be interpreted as a voice/language * specific feature function (if present) or an item feature name. If the * feature function exists it will be called with the item specified by the * path, otherwise, a feature will be retrieved with the given name. If * neither exist than a String "0" is returned. * * @param pathAndFeature the path to follow * @return created object */ public Object findFeature(String pathAndFeature) { int lastDot; String feature; String path; Item item; Object results = null; 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); } item = findItem(path); if (item != null) { results = item.getFeatures().getObject(feature); } results = (results == null) ? "0" : results; // System.out.println("FI " + pathAndFeature + " are " + results); return results; } /** * Finds the item specified by the given path. * * Path is a string of ":" or "." separated strings with the following * interpretations: * <ul> * <li>n - next item * <li>p - previous item * <li>parent - the parent * <li>daughter - the daughter * <li>daughter1 - same as daughter * <li>daughtern - the last daughter * <li>R:relname - the item as found in the given relation 'relname' * </ul> * If the given path takes us outside of the bounds of the item graph, then * list access exceptions will be thrown. * * @param path the path to follow * * @return the item at the given path */ public Item findItem(String path) { Item pitem = this; StringTokenizer tok; if (path == null) { return this; } tok = new StringTokenizer(path, ":."); while (pitem != null && tok.hasMoreTokens()) { String token = tok.nextToken(); if (token.equals("n")) { pitem = pitem.getNext(); } else if (token.equals("p")) { pitem = pitem.getPrevious(); } else if (token.equals("nn")) { pitem = pitem.getNext(); if (pitem != null) { pitem = pitem.getNext(); } } else if (token.equals("pp")) { pitem = pitem.getPrevious(); if (pitem != null) { pitem = pitem.getPrevious(); } } else if (token.equals("parent")) { pitem = pitem.getParent(); } else if (token.equals("daughter") || token.equals("daughter1")) { pitem = pitem.getDaughter(); } else if (token.equals("daughtern")) { pitem = pitem.getLastDaughter(); } else if (token.equals("R")) { String relationName = tok.nextToken(); pitem = pitem.getSharedContents() .getItemRelation(relationName); } else { System.out.println("findItem: bad feature " + token + " in " + path); } } return pitem; } /** * Gets the next item in this list. * * @return the next item or null */ public Item getNext() { return next; } /** * Gets the previous item in this list. * * @return the previous item or null */ public Item getPrevious() { return prev; } /** * Appends an item in this list after this item. * * @param originalItem new item has shared contents with this item (or * * null) * * @return the newly appended item */ public Item appendItem(Item originalItem) { ItemContents contents; Item newItem; if (originalItem == null) { contents = null; } else { contents = originalItem.getSharedContents(); } newItem = new Item(getOwnerRelation(), contents); newItem.next = this.next; if (this.next != null) { this.next.prev = newItem; } attach(newItem); if (this.ownerRelation.getTail() == this) { this.ownerRelation.setTail(newItem); } return newItem; } /** * Attaches/appends an item to this one. * * @param item the item to append */ void attach(Item item) { this.next = item; item.prev = this; } /** * Prepends an item in this list before this item. * * @param originalItem new item has shared contents with this item (or * * null) * * @return the newly appended item */ public Item prependItem(Item originalItem) { ItemContents contents; Item newItem; if (originalItem == null) { contents = null; } else { contents = originalItem.getSharedContents(); } newItem = new Item(getOwnerRelation(), contents); newItem.prev = this.prev; if (this.prev != null) { this.prev.next = newItem; } newItem.next = this; this.prev = newItem; if (this.parent != null) { this.parent.daughter = newItem; newItem.parent = this.parent; this.parent = null; } if (this.ownerRelation.getHead() == this) { this.ownerRelation.setHead(newItem); } return newItem; } // Inherited from object public String toString() { // if we have a feature called 'name' use that // otherwise fall back on the default. String name = getFeatures().getString("name"); if (name == null) { name = ""; } return name; } /** * Determines if the shared contents of the two items are the same. * * @param otherItem the item to compare * * @return true if the shared contents are the same */ public boolean equalsShared(Item otherItem) { if (otherItem == null) { return false; } else { return getSharedContents().equals(otherItem.getSharedContents()); } } }