001/* 002 * BioJava development code 003 * 004 * This code may be freely distributed and modified under the 005 * terms of the GNU Lesser General Public Licence. This should 006 * be distributed with the code. If you do not have a copy, 007 * see: 008 * 009 * http://www.gnu.org/copyleft/lesser.html 010 * 011 * Copyright for this code is held jointly by the individual 012 * authors. These should be listed in @author doc comments. 013 * 014 * For more information on the BioJava project and its aims, 015 * or to join the biojava-l mailing list, visit the home page 016 * at: 017 * 018 * http://www.biojava.org/ 019 * 020 */ 021package org.biojavax.bio.phylo.io.nexus; 022 023import org.biojava.bio.seq.io.ParseException; 024import org.biojavax.bio.phylo.io.nexus.TreesBlock.NewickTreeString; 025 026/** 027 * Parses Nexus taxa blocks. 028 * 029 * @author Richard Holland 030 * @author Tobias Thierer 031 * @author Jim Balhoff 032 * @author Tiago Antao 033 * @since 1.6 034 */ 035public class TreesBlockParser extends NexusBlockParser.Abstract { 036 037 public void beginComment() { 038 if (!this.expectingTreeRooted) 039 super.beginComment(); 040 } 041 042 public void commentText(String comment) throws ParseException { 043 if (this.expectingTreeRooted) 044 this.currentTreeRoot.append(comment); 045 else 046 super.commentText(comment); 047 } 048 049 public void endComment() { 050 if (!this.expectingTreeRooted) 051 super.endComment(); 052 } 053 054 private boolean expectingTranslate; 055 056 private boolean expectingTaxLabel; 057 058 private boolean expectingTaxName; 059 060 private boolean expectingTree; 061 062 private boolean expectingTreeName; 063 064 private boolean expectingTreeEquals; 065 066 private boolean expectingTreeContent; 067 068 private boolean expectingTreeRooted; 069 070 private String currentTaxLabel; 071 072 private String currentTreeName; 073 074 private boolean currentTreeStarred; 075 076 private StringBuffer currentTreeRoot = new StringBuffer(); 077 078 private StringBuffer currentTreeContent = new StringBuffer(); 079 080 /** 081 * Delegates to NexusBlockParser.Abstract. 082 * 083 * @param blockListener 084 * the listener to send parse events to. 085 */ 086 public TreesBlockParser(TreesBlockListener blockListener) { 087 super(blockListener); 088 } 089 090 public void resetStatus() { 091 this.expectingTranslate = true; 092 this.expectingTaxLabel = false; 093 this.expectingTaxName = false; 094 this.expectingTree = true; 095 this.expectingTreeName = false; 096 this.expectingTreeEquals = false; 097 this.expectingTreeRooted = false; 098 this.expectingTreeContent = false; 099 this.currentTaxLabel = null; 100 this.currentTreeStarred = false; 101 this.currentTreeName = null; 102 this.currentTreeRoot.setLength(0); 103 this.currentTreeContent.setLength(0); 104 } 105 106 public void parseToken(String token) throws ParseException { 107 if (token.trim().length() == 0) { 108 return; 109 } 110 if ( token != null) { 111 if (this.expectingTaxLabel == true && "tree".equalsIgnoreCase(token)) { 112 this.expectingTaxLabel = false; 113 this.expectingTree = true; 114 } 115 } 116 if (this.expectingTranslate && "TRANSLATE".equalsIgnoreCase(token)) { 117 this.expectingTranslate = false; 118 this.expectingTaxLabel = true; 119 this.expectingTree = false; 120 } else if (this.expectingTaxLabel) { 121 this.currentTaxLabel = token; // In case it includes spaces. 122 this.expectingTaxLabel = false; 123 this.expectingTaxName = true; 124 } else if (this.expectingTaxName) { 125 final boolean endsWithComma = token.endsWith(","); 126 final String taxName = endsWithComma ? token.substring(0, token 127 .length() - 1) : token; 128 ((TreesBlockListener) this.getBlockListener()).addTranslation( 129 this.currentTaxLabel, taxName); 130 this.expectingTaxName = false; 131 if (!endsWithComma) { 132 this.expectingTree = true; 133 } else { 134 this.expectingTaxLabel = true; 135 } 136 } else if (this.expectingTree && "TREE".equalsIgnoreCase(token)) { 137 this.expectingTree = false; 138 this.expectingTreeName = true; 139 } else if (this.expectingTreeName) { 140 if ("*".equals(token)) 141 this.currentTreeStarred = true; 142 else { 143 this.expectingTreeName = false; 144 if (token.indexOf("=") >= 0) { 145 final String parts[] = token.split("="); 146 this.currentTreeName = parts[0]; 147 if (parts.length > 1) { 148 this.currentTreeContent.append(token); 149 this.expectingTreeRooted = false; 150 } 151 this.expectingTreeContent = true; 152 } else { 153 this.currentTreeName = token; 154 this.expectingTreeEquals = true; 155 } 156 } 157 } else if (this.expectingTreeEquals && token.startsWith("=")) { 158 this.expectingTreeEquals = false; 159 final String parts[] = token.split("="); 160 if (parts.length > 1) { 161 this.currentTreeContent.append(parts[1]); 162 this.expectingTreeRooted = false; 163 } else 164 this.expectingTreeRooted = true; 165 this.expectingTreeContent = true; 166 } else if (this.expectingTreeContent) { 167 this.currentTreeContent.append(token); // In case it includes 168 // spaces. 169 this.expectingTreeRooted = false; 170 } else 171 throw new ParseException("Found unexpected token " + token 172 + " in TREES block"); 173 } 174 175 public void endTokenGroup() { 176 if (this.expectingTreeContent) { 177 final NewickTreeString tree = new NewickTreeString(); 178 tree.setRootType(this.currentTreeRoot.toString()); 179 tree.setTreeString(this.currentTreeContent.toString()); 180 tree.setStarred(this.currentTreeStarred); 181 ((TreesBlockListener) this.getBlockListener()).addTree( 182 this.currentTreeName, tree); 183 this.currentTreeContent.setLength(0); 184 this.currentTreeName = null; 185 this.currentTreeRoot.setLength(0); 186 this.currentTreeStarred = false; 187 this.expectingTreeRooted = false; 188 this.expectingTreeContent = false; 189 this.expectingTree = true; 190 } else 191 super.endTokenGroup(); 192 } 193 194}