package edu.stanford.nlp.semparse.open.model.tree; import java.util.*; import fig.basic.LogInfo; import fig.basic.StrUtils; /** * A node in the knowledge tree. * * Nodes can be one of the following: * <ul> * <li>type = QUERY, value = search query (e.g., "us cities")</li> * <li>type = URL, value = url (e.g., http://en.wikipedia.org/wiki/List_of_United_States_cities_by_population)</li> * <li>type = TAG, value = tag of the DOM node (e.g., "h1")</li> * <li>type = ATTR, value = attribute (e.g., "class")</li> * <li>type = TEXT, value = a string (e.g., "San Francisco")</li> * </ul> */ public class KNode { public enum Type { QUERY, URL, TAG, ATTR, TEXT }; public final Type type; public final String value; private final List<KNode> children; private final List<KNode> attributes; // fullText == '' if the node is empty // fullText == null if the full text is longer than the specified length. public final String fullText; // parent of root node is null public final KNode parent; // depth of root node is 0 public final int depth; // timestamps of depth first search (used for firing range features) public int timestampIn, timestampOut, timestampInCollapsed; public KNode(KNode parent, Type type, String value) { this(parent, type, value, ""); } public KNode(KNode parent, Type type, String value, String fullText) { this.type = type; this.value = value; this.children = new ArrayList<>(); this.attributes = new ArrayList<>(); this.fullText = fullText; this.parent = parent; if (this.parent == null) { this.depth = 0; } else { this.depth = this.parent.depth + 1; if (type == Type.ATTR) { this.parent.attributes.add(this); } else { this.parent.children.add(this); } } } /** * Create a child and return the child. */ public KNode createChild(Type type, String value) { return new KNode(this, type, value); } /** * Create a child and return the child. */ public KNode createChild(Type type, String value, String fullText) { return new KNode(this, type, value, fullText); } /** * Create a child using the information from the `original` node and return the child. */ public KNode createChild(KNode original) { return new KNode(this, original.type, original.value, original.fullText); } public KNode createAttribute(String attributeName, String attributeValue) { KNode attributeNode = createChild(Type.ATTR, attributeName, attributeValue); attributeNode.createChild(Type.TEXT, attributeValue, attributeValue); return attributeNode; } // Getters public List<KNode> getChildren() { return Collections.unmodifiableList(children); } public List<KNode> getChildrenOfTag(String tag) { List<KNode> answer = new ArrayList<>(); for (KNode child : children) { if (child.type == Type.TAG && (tag.equals(child.value) || tag.equals("*"))) { answer.add(child); } } return answer; } // The index is 0-based public KNode getChildrenOfTag(String tag, int index) { int count = 0; for (KNode child : children) { if (child.type == Type.TAG && (tag.equals(child.value) || tag.equals("*"))) { if (count == index) return child; count++; } } return null; } public List<KNode> getAttributes() { return Collections.unmodifiableList(attributes); } public String getAttribute(String attributeName) { for (KNode attributeNode : attributes) { if (attributeNode.value.equals(attributeName)) return attributeNode.fullText; } return ""; } public String[] getAttributeList(String attributeName) { for (KNode attributeNode : attributes) { if (attributeNode.value.equals(attributeName) && !attributeNode.fullText.isEmpty()) return attributeNode.fullText.split(" "); } return new String[0]; } // The index is 0-based public int getChildIndex() { return this.parent.children.indexOf(this); } // The index is 0-based public int getChildIndexOfSameTag() { int count = 0; for (KNode child : this.parent.children) { if (child.type == Type.TAG && child.value.equals(this.value)){ if (child == this) return count; count++; } } return -1; } public int countChildren() { return this.children.size(); } public int countChildren(String tag) { int count = 0; for (KNode child : children) { if (child.type == Type.TAG && child.value.equals(tag)) count++; } return count; } // Debug Print public void debugPrint(int indent) { LogInfo.logs(StrUtils.repeat(" ", indent) + "%s '%s'", type, value); for (KNode child : children) { child.debugPrint(indent + 2); } } // Timestamp public void generateTimestamp() { generateTimestamp(1); generateTimestampInCollapsed(1); } protected int generateTimestamp(int currentTimestamp) { timestampIn = currentTimestamp++; for (KNode node : children) { currentTimestamp = node.generateTimestamp(currentTimestamp); } timestampOut = currentTimestamp++; return currentTimestamp; } protected int generateTimestampInCollapsed(int currentTimestampInCollapsed) { timestampInCollapsed = currentTimestampInCollapsed++; for (KNode node : children) { currentTimestampInCollapsed = node.generateTimestampInCollapsed(currentTimestampInCollapsed); } return currentTimestampInCollapsed; } }