2 // FORESTER -- software libraries and applications
3 // for evolutionary biology research and applications.
5 // Copyright (C) 2008-2009 Christian M. Zmasek
6 // Copyright (C) 2008-2009 Burnham Institute for Medical Research
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 // Contact: phylosoft @ gmail . com
24 // WWW: https://sites.google.com/site/cmzmasek/home/software/forester
26 package org.forester.io.writers;
28 import java.io.BufferedWriter;
30 import java.io.IOException;
31 import java.io.PrintWriter;
32 import java.io.StringWriter;
33 import java.io.Writer;
34 import java.util.ArrayList;
35 import java.util.Iterator;
36 import java.util.List;
37 import java.util.Stack;
39 import org.forester.io.parsers.nexus.NexusConstants;
40 import org.forester.io.parsers.phyloxml.PhyloXmlMapping;
41 import org.forester.phylogeny.Phylogeny;
42 import org.forester.phylogeny.PhylogenyNode;
43 import org.forester.phylogeny.PhylogenyNode.NH_CONVERSION_SUPPORT_VALUE_STYLE;
44 import org.forester.phylogeny.data.PhylogenyDataUtil;
45 import org.forester.phylogeny.iterators.PhylogenyNodeIterator;
46 import org.forester.phylogeny.iterators.PostOrderStackObject;
47 import org.forester.util.ForesterConstants;
48 import org.forester.util.ForesterUtil;
50 public final class PhylogenyWriter {
52 public final static boolean INDENT_PHYLOXML_DEAFULT = true;
53 public final static String PHYLO_XML_INTENDATION_BASE = " ";
54 public final static String PHYLO_XML_VERSION_ENCODING_LINE = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
55 public final static String PHYLO_XML_NAMESPACE_LINE = "<phyloxml xmlns:xsi=\""
56 + ForesterConstants.XML_SCHEMA_INSTANCE
57 + "\" xsi:schemaLocation=\""
58 + ForesterConstants.PHYLO_XML_LOCATION
60 + ForesterConstants.PHYLO_XML_LOCATION
62 + ForesterConstants.PHYLO_XML_VERSION
63 + "/" + ForesterConstants.PHYLO_XML_XSD
65 + ForesterConstants.PHYLO_XML_LOCATION
67 public final static String PHYLO_XML_END = "</phyloxml>";
68 private boolean _saw_comma;
69 private StringBuffer _buffer;
70 private Writer _writer;
71 private PhylogenyNode _root;
72 private boolean _has_next;
73 private Stack<PostOrderStackObject> _stack;
74 private boolean _nh_write_distance_to_parent;
75 NH_CONVERSION_SUPPORT_VALUE_STYLE _nh_conversion_support_style;
76 private boolean _indent_phyloxml;
77 private int _node_level;
78 private int _phyloxml_level;
79 private FORMAT _format;
81 public PhylogenyWriter() {
82 setIndentPhyloxml( INDENT_PHYLOXML_DEAFULT );
83 setNhConversionSupportStyle( NH_CONVERSION_SUPPORT_VALUE_STYLE.NONE );
86 private void appendPhylogenyLevelPhyloXml( final Writer writer, final Phylogeny tree ) throws IOException {
87 final String indentation = new String();
88 if ( !ForesterUtil.isEmpty( tree.getName() ) ) {
89 PhylogenyDataUtil.appendElement( writer, PhyloXmlMapping.PHYLOGENY_NAME, tree.getName(), indentation );
91 if ( tree.getIdentifier() != null ) {
92 if ( ForesterUtil.isEmpty( tree.getIdentifier().getProvider() ) ) {
93 PhylogenyDataUtil.appendElement( writer,
94 PhyloXmlMapping.IDENTIFIER,
95 tree.getIdentifier().getValue(),
98 PhylogenyDataUtil.appendElement( writer,
99 PhyloXmlMapping.IDENTIFIER,
100 tree.getIdentifier().getValue(),
101 PhyloXmlMapping.IDENTIFIER_PROVIDER_ATTR,
102 tree.getIdentifier().getProvider(),
105 if ( !ForesterUtil.isEmpty( tree.getDescription() ) ) {
106 PhylogenyDataUtil.appendElement( writer,
107 PhyloXmlMapping.PHYLOGENY_DESCRIPTION,
108 tree.getDescription(),
111 if ( tree.getConfidence() != null ) {
112 if ( ForesterUtil.isEmpty( tree.getConfidence().getType() ) ) {
113 PhylogenyDataUtil.appendElement( writer, PhyloXmlMapping.CONFIDENCE, tree.getConfidence().getValue()
116 PhylogenyDataUtil.appendElement( writer,
117 PhyloXmlMapping.CONFIDENCE,
118 tree.getConfidence().getValue() + "",
119 PhyloXmlMapping.CONFIDENCE_TYPE_ATTR,
120 tree.getConfidence().getType(),
125 private StringBuffer createIndentation() {
126 if ( !isIndentPhyloxml() ) {
129 final StringBuffer sb = new StringBuffer( getNodeLevel() * 2 );
130 for( int i = 0; i < getNodeLevel(); ++i ) {
131 sb.append( PhylogenyWriter.PHYLO_XML_INTENDATION_BASE );
136 private void decreaseNodeLevel() {
140 private StringBuffer getBuffer() {
144 private int getNodeLevel() {
148 private StringBuffer getOutput( final Phylogeny tree ) throws IOException {
149 if ( getOutputFormt() == FORMAT.PHYLO_XML ) {
150 throw new RuntimeException( "method inappropriately called" );
152 if ( tree != null ) {
154 while ( isHasNext() ) {
157 if ( getOutputFormt() == FORMAT.NH ) {
158 getBuffer().append( ';' );
163 return new StringBuffer( 0 );
167 private FORMAT getOutputFormt() {
171 private int getPhyloXmlLevel() {
172 return _phyloxml_level;
175 private PhylogenyNode getRoot() {
179 private Stack<PostOrderStackObject> getStack() {
183 private Writer getWriter() {
187 private void increaseNodeLevel() {
191 private boolean isHasNext() {
195 private boolean isIndentPhyloxml() {
196 return _indent_phyloxml;
199 private boolean isSawComma() {
203 private boolean isWriteDistanceToParentInNH() {
204 return _nh_write_distance_to_parent;
207 private void next() throws IOException {
209 final PostOrderStackObject si = getStack().pop();
210 final PhylogenyNode node = si.getNode();
211 final int phase = si.getPhase();
212 if ( phase > node.getNumberOfDescendants() ) {
213 setHasNext( node != getRoot() );
214 if ( ( getOutputFormt() != FORMAT.PHYLO_XML ) || node.isExternal() ) {
215 if ( !node.isRoot() && node.isFirstChildNode() ) {
218 if ( getOutputFormt() == FORMAT.PHYLO_XML ) {
219 writeNode( node, createIndentation() );
222 writeNode( node, null );
225 if ( !node.isRoot() ) {
226 if ( !node.isLastChildNode() ) {
227 writeCladeSeparator();
236 getStack().push( new PostOrderStackObject( node, ( phase + 1 ) ) );
237 if ( node.isInternal() ) {
238 getStack().push( new PostOrderStackObject( node.getChildNode( phase - 1 ), 1 ) );
239 writeOpenClade( node );
240 if ( getOutputFormt() == FORMAT.PHYLO_XML ) {
242 writeNode( node, createIndentation() );
250 private void reset( final Phylogeny tree ) {
251 setBuffer( new StringBuffer() );
253 setSawComma( false );
255 setRoot( tree.getRoot() );
256 setStack( new Stack<PostOrderStackObject>() );
257 getStack().push( new PostOrderStackObject( tree.getRoot(), 1 ) );
261 private void reset( final Writer writer, final Phylogeny tree ) {
264 setSawComma( false );
266 setRoot( tree.getRoot() );
267 setStack( new Stack<PostOrderStackObject>() );
268 getStack().push( new PostOrderStackObject( tree.getRoot(), 1 ) );
272 private void setBuffer( final StringBuffer buffer ) {
276 private void setHasNext( final boolean has_next ) {
277 _has_next = has_next;
280 public void setIndentPhyloxml( final boolean indent_phyloxml ) {
281 _indent_phyloxml = indent_phyloxml;
284 private void setNodeLevel( final int level ) {
288 private void setOutputFormt( final FORMAT format ) {
292 private void setPhyloXmlLevel( final int phyloxml_level ) {
293 _phyloxml_level = phyloxml_level;
296 private void setRoot( final PhylogenyNode root ) {
300 private void setSawComma( final boolean saw_comma ) {
301 _saw_comma = saw_comma;
304 private void setStack( final Stack<PostOrderStackObject> stack ) {
308 private void setWriteDistanceToParentInNH( final boolean nh_write_distance_to_parent ) {
309 _nh_write_distance_to_parent = nh_write_distance_to_parent;
312 private void setWriter( final Writer writer ) {
316 public void toNewHampshire( final List<Phylogeny> trees,
317 final boolean write_distance_to_parent,
319 final String separator ) throws IOException {
320 final Iterator<Phylogeny> it = trees.iterator();
321 final StringBuffer sb = new StringBuffer();
322 while ( it.hasNext() ) {
323 sb.append( toNewHampshire( it.next(), write_distance_to_parent ) );
324 sb.append( separator );
326 writeToFile( sb, out_file );
329 public StringBuffer toNewHampshire( final Phylogeny tree,
330 final boolean nh_write_distance_to_parent,
331 final NH_CONVERSION_SUPPORT_VALUE_STYLE svs ) throws IOException {
332 setOutputFormt( FORMAT.NH );
333 setNhConversionSupportStyle( svs );
334 setWriteDistanceToParentInNH( nh_write_distance_to_parent );
335 return getOutput( tree );
338 public StringBuffer toNewHampshire( final Phylogeny tree, final boolean nh_write_distance_to_parent )
340 setOutputFormt( FORMAT.NH );
341 setWriteDistanceToParentInNH( nh_write_distance_to_parent );
342 return getOutput( tree );
345 public void toNewHampshire( final Phylogeny tree, final boolean write_distance_to_parent, final File out_file )
347 writeToFile( toNewHampshire( tree, write_distance_to_parent ), out_file );
350 public void toNewHampshire( final Phylogeny tree,
351 final boolean write_distance_to_parent,
352 final NH_CONVERSION_SUPPORT_VALUE_STYLE svs,
353 final File out_file ) throws IOException {
354 writeToFile( toNewHampshire( tree, write_distance_to_parent, svs ), out_file );
357 public void toNewHampshire( final Phylogeny[] trees,
358 final boolean write_distance_to_parent,
360 final String separator ) throws IOException {
361 final StringBuffer sb = new StringBuffer();
362 for( final Phylogeny element : trees ) {
363 sb.append( toNewHampshire( element, write_distance_to_parent ) );
364 sb.append( separator );
366 writeToFile( sb, out_file );
369 public void toNewHampshireX( final List<Phylogeny> trees, final File out_file, final String separator )
371 final Iterator<Phylogeny> it = trees.iterator();
372 final StringBuffer sb = new StringBuffer();
373 while ( it.hasNext() ) {
374 sb.append( toNewHampshireX( it.next() ) );
375 sb.append( separator );
377 writeToFile( sb, out_file );
380 public StringBuffer toNewHampshireX( final Phylogeny tree ) throws IOException {
381 setOutputFormt( FORMAT.NHX );
382 return getOutput( tree );
385 public void toNewHampshireX( final Phylogeny tree, final File out_file ) throws IOException {
386 writeToFile( toNewHampshireX( tree ), out_file );
389 public void toNewHampshireX( final Phylogeny[] trees, final File out_file, final String separator )
391 final StringBuffer sb = new StringBuffer();
392 for( final Phylogeny element : trees ) {
393 sb.append( toNewHampshireX( element ) );
394 sb.append( separator );
396 writeToFile( sb, out_file );
399 public void toNexus( final File out_file, final Phylogeny tree, final NH_CONVERSION_SUPPORT_VALUE_STYLE svs )
401 final Writer writer = new BufferedWriter( new PrintWriter( out_file, ForesterConstants.UTF_8 ) );
402 final List<Phylogeny> trees = new ArrayList<Phylogeny>( 1 );
404 writeNexusStart( writer );
405 writeNexusTaxaBlock( writer, tree );
406 writeNexusTreesBlock( writer, trees, svs );
411 public StringBuffer toNexus( final Phylogeny tree, final NH_CONVERSION_SUPPORT_VALUE_STYLE svs ) throws IOException {
412 final StringWriter string_writer = new StringWriter();
413 final Writer writer = new BufferedWriter( string_writer );
414 final List<Phylogeny> trees = new ArrayList<Phylogeny>( 1 );
416 writeNexusStart( writer );
417 writeNexusTaxaBlock( writer, tree );
418 writeNexusTreesBlock( writer, trees, svs );
421 return string_writer.getBuffer();
424 public void toPhyloXML( final File out_file,
425 final List<Phylogeny> trees,
426 final int phyloxml_level,
427 final String separator ) throws IOException {
428 final Writer writer = new BufferedWriter( new PrintWriter( out_file, ForesterConstants.UTF_8 ) );
429 toPhyloXML( writer, trees, phyloxml_level, separator );
434 public void toPhyloXML( final File out_file, final Phylogeny tree, final int phyloxml_level ) throws IOException {
435 final Writer writer = new BufferedWriter( new PrintWriter( out_file, ForesterConstants.UTF_8 ) );
436 writePhyloXmlStart( writer );
437 toPhyloXMLNoPhyloXmlSource( writer, tree, phyloxml_level );
438 writePhyloXmlEnd( writer );
443 public StringBuffer toPhyloXML( final Phylogeny tree, final int phyloxml_level ) throws IOException {
444 final StringWriter string_writer = new StringWriter();
445 final Writer writer = new BufferedWriter( string_writer );
446 setPhyloXmlLevel( phyloxml_level );
447 setOutputFormt( FORMAT.PHYLO_XML );
448 writePhyloXmlStart( writer );
449 writeOutput( writer, tree );
450 writePhyloXmlEnd( writer );
453 return string_writer.getBuffer();
456 public void toPhyloXML( final Phylogeny[] trees,
457 final int phyloxml_level,
459 final String separator ) throws IOException {
460 final Writer writer = new BufferedWriter( new PrintWriter( out_file ) );
461 toPhyloXML( writer, trees, phyloxml_level, separator );
466 public void toPhyloXML( final Phylogeny phy, final int phyloxml_level, final File out_file ) throws IOException {
467 final Writer writer = new BufferedWriter( new PrintWriter( out_file ) );
468 toPhyloXML( writer, phy, phyloxml_level );
473 public void toPhyloXML( final Writer writer,
474 final List<Phylogeny> trees,
475 final int phyloxml_level,
476 final String separator ) throws IOException {
477 writePhyloXmlStart( writer );
478 final Iterator<Phylogeny> it = trees.iterator();
479 while ( it.hasNext() ) {
480 toPhyloXMLNoPhyloXmlSource( writer, it.next(), phyloxml_level );
481 writer.write( separator );
483 writePhyloXmlEnd( writer );
486 public void toPhyloXML( final Writer writer, final Phylogeny tree, final int phyloxml_level ) throws IOException {
487 setPhyloXmlLevel( phyloxml_level );
488 setOutputFormt( FORMAT.PHYLO_XML );
489 writePhyloXmlStart( writer );
490 writeOutput( writer, tree );
491 writePhyloXmlEnd( writer );
494 public void toPhyloXML( final Writer writer,
495 final Phylogeny[] trees,
496 final int phyloxml_level,
497 final String separator ) throws IOException {
498 writePhyloXmlStart( writer );
499 for( final Phylogeny phylogeny : trees ) {
500 toPhyloXMLNoPhyloXmlSource( writer, phylogeny, phyloxml_level );
501 writer.write( separator );
503 writePhyloXmlEnd( writer );
506 private void toPhyloXMLNoPhyloXmlSource( final Writer writer, final Phylogeny tree, final int phyloxml_level )
508 setPhyloXmlLevel( phyloxml_level );
509 setOutputFormt( FORMAT.PHYLO_XML );
510 writeOutput( writer, tree );
513 private void writeCladeSeparator() {
515 if ( ( getOutputFormt() == FORMAT.NHX ) || ( getOutputFormt() == FORMAT.NH ) ) {
516 getBuffer().append( "," );
520 private void writeCloseClade() throws IOException {
522 if ( getOutputFormt() == FORMAT.PHYLO_XML ) {
523 getWriter().write( ForesterUtil.LINE_SEPARATOR );
524 if ( isIndentPhyloxml() ) {
525 getWriter().write( createIndentation().toString() );
527 PhylogenyDataUtil.appendClose( getWriter(), PhyloXmlMapping.CLADE );
529 else if ( ( getOutputFormt() == FORMAT.NHX ) || ( getOutputFormt() == FORMAT.NH ) ) {
530 getBuffer().append( ")" );
534 private void writeNode( final PhylogenyNode node, final StringBuffer indentation ) throws IOException {
535 if ( getOutputFormt() == FORMAT.PHYLO_XML ) {
536 if ( node.isExternal() ) {
537 getWriter().write( ForesterUtil.LINE_SEPARATOR );
538 if ( indentation != null ) {
539 getWriter().write( indentation.toString() );
541 PhylogenyDataUtil.appendOpen( getWriter(), PhyloXmlMapping.CLADE );
543 PhyloXmlNodeWriter.toPhyloXml( getWriter(),
546 indentation != null ? indentation.toString() : "" );
547 if ( node.isExternal() ) {
548 getWriter().write( ForesterUtil.LINE_SEPARATOR );
549 if ( indentation != null ) {
550 getWriter().write( indentation.toString() );
552 PhylogenyDataUtil.appendClose( getWriter(), PhyloXmlMapping.CLADE );
555 else if ( getOutputFormt() == FORMAT.NHX ) {
556 getBuffer().append( node.toNewHampshireX() );
558 else if ( getOutputFormt() == FORMAT.NH ) {
559 getBuffer().append( node.toNewHampshire( isWriteDistanceToParentInNH(), getNhConversionSupportStyle() ) );
563 private NH_CONVERSION_SUPPORT_VALUE_STYLE getNhConversionSupportStyle() {
564 return _nh_conversion_support_style;
567 private void setNhConversionSupportStyle( final NH_CONVERSION_SUPPORT_VALUE_STYLE nh_conversion_support_style ) {
568 _nh_conversion_support_style = nh_conversion_support_style;
571 private void writeOpenClade( final PhylogenyNode node ) throws IOException {
572 if ( !isSawComma() ) {
573 if ( !node.isRoot() && node.isFirstChildNode() ) {
576 if ( getOutputFormt() == FORMAT.PHYLO_XML ) {
577 getWriter().write( ForesterUtil.LINE_SEPARATOR );
578 if ( isIndentPhyloxml() ) {
579 getWriter().write( createIndentation().toString() );
581 if ( node.isCollapse() ) {
582 PhylogenyDataUtil.appendOpen( getWriter(),
583 PhyloXmlMapping.CLADE,
584 PhyloXmlMapping.NODE_COLLAPSE,
588 PhylogenyDataUtil.appendOpen( getWriter(), PhyloXmlMapping.CLADE );
591 else if ( ( getOutputFormt() == FORMAT.NHX ) || ( getOutputFormt() == FORMAT.NH ) ) {
592 getBuffer().append( "(" );
595 setSawComma( false );
598 private void writeOutput( final Writer writer, final Phylogeny tree ) throws IOException {
599 if ( getOutputFormt() != FORMAT.PHYLO_XML ) {
600 throw new RuntimeException( "method inappropriately called" );
602 if ( tree != null ) {
603 reset( writer, tree );
606 if ( !ForesterUtil.isEmpty( tree.getDistanceUnit() ) ) {
607 unit = tree.getDistanceUnit();
609 if ( !ForesterUtil.isEmpty( tree.getType() ) ) {
610 type = tree.getType();
612 PhylogenyDataUtil.appendOpen( writer,
613 PhyloXmlMapping.PHYLOGENY,
614 PhyloXmlMapping.PHYLOGENY_IS_ROOTED_ATTR,
615 tree.isRooted() + "",
616 PhyloXmlMapping.PHYLOGENY_BRANCHLENGTH_UNIT_ATTR,
618 PhyloXmlMapping.PHYLOGENY_TYPE_ATTR,
620 PhyloXmlMapping.PHYLOGENY_IS_REROOTABLE_ATTR,
621 tree.isRerootable() + "" );
622 appendPhylogenyLevelPhyloXml( writer, tree );
623 while ( isHasNext() ) {
626 writer.write( ForesterUtil.LINE_SEPARATOR );
627 PhylogenyDataUtil.appendClose( writer, PhyloXmlMapping.PHYLOGENY );
631 private void writeToFile( final StringBuffer sb, final File out_file ) throws IOException {
632 if ( out_file.exists() ) {
633 throw new IOException( "attempt to overwrite existing file \"" + out_file.getAbsolutePath() + "\"" );
635 final PrintWriter out = new PrintWriter( out_file, ForesterConstants.UTF_8 );
641 public static PhylogenyWriter createPhylogenyWriter() {
642 return new PhylogenyWriter();
645 private static void writeNexusStart( final Writer writer ) throws IOException {
646 writer.write( NexusConstants.NEXUS );
647 writer.write( ForesterUtil.LINE_SEPARATOR );
650 public static void writeNexusTaxaBlock( final Writer writer, final Phylogeny tree ) throws IOException {
651 writer.write( NexusConstants.BEGIN_TAXA );
652 writer.write( ForesterUtil.LINE_SEPARATOR );
654 writer.write( NexusConstants.DIMENSIONS );
656 writer.write( NexusConstants.NTAX );
658 writer.write( String.valueOf( tree.getNumberOfExternalNodes() ) );
660 writer.write( ForesterUtil.LINE_SEPARATOR );
662 writer.write( NexusConstants.TAXLABELS );
663 for( final PhylogenyNodeIterator it = tree.iteratorExternalForward(); it.hasNext(); ) {
664 final PhylogenyNode node = it.next();
667 if ( !ForesterUtil.isEmpty( node.getName() ) ) {
668 data = node.getName();
670 else if ( node.getNodeData().isHasTaxonomy() ) {
671 if ( !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getTaxonomyCode() ) ) {
672 data = node.getNodeData().getTaxonomy().getTaxonomyCode();
674 else if ( !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getScientificName() ) ) {
675 data = node.getNodeData().getTaxonomy().getScientificName();
677 else if ( !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getCommonName() ) ) {
678 data = node.getNodeData().getTaxonomy().getCommonName();
681 else if ( node.getNodeData().isHasSequence() ) {
682 if ( !ForesterUtil.isEmpty( node.getNodeData().getSequence().getName() ) ) {
683 data = node.getNodeData().getSequence().getName();
685 else if ( !ForesterUtil.isEmpty( node.getNodeData().getSequence().getSymbol() ) ) {
686 data = node.getNodeData().getSequence().getSymbol();
688 else if ( !ForesterUtil.isEmpty( node.getNodeData().getSequence().getGeneName() ) ) {
689 data = node.getNodeData().getSequence().getGeneName();
692 writer.write( ForesterUtil.santitizeStringForNH( data ).toString() );
695 writer.write( ForesterUtil.LINE_SEPARATOR );
696 writer.write( NexusConstants.END );
697 writer.write( ForesterUtil.LINE_SEPARATOR );
700 public static void writeNexusTreesBlock( final Writer writer,
701 final List<Phylogeny> trees,
702 final NH_CONVERSION_SUPPORT_VALUE_STYLE svs ) throws IOException {
703 writer.write( NexusConstants.BEGIN_TREES );
704 writer.write( ForesterUtil.LINE_SEPARATOR );
706 for( final Phylogeny phylogeny : trees ) {
708 writer.write( NexusConstants.TREE );
710 if ( !ForesterUtil.isEmpty( phylogeny.getName() ) ) {
711 writer.write( "\'" );
712 writer.write( phylogeny.getName() );
713 writer.write( "\'" );
716 writer.write( "tree" );
717 writer.write( String.valueOf( i ) );
720 if ( phylogeny.isRooted() ) {
721 writer.write( "[&R]" );
724 writer.write( "[&U]" );
726 writer.write( phylogeny.toNewHampshire( svs ) );
727 writer.write( ForesterUtil.LINE_SEPARATOR );
730 writer.write( NexusConstants.END );
731 writer.write( ForesterUtil.LINE_SEPARATOR );
734 private static void writePhyloXmlEnd( final Writer writer ) throws IOException {
735 writer.write( ForesterUtil.LINE_SEPARATOR );
736 writer.write( PhylogenyWriter.PHYLO_XML_END );
739 private static void writePhyloXmlStart( final Writer writer ) throws IOException {
740 writer.write( PhylogenyWriter.PHYLO_XML_VERSION_ENCODING_LINE );
741 writer.write( ForesterUtil.LINE_SEPARATOR );
742 writer.write( PhylogenyWriter.PHYLO_XML_NAMESPACE_LINE );
743 writer.write( ForesterUtil.LINE_SEPARATOR );
746 public static enum FORMAT {
747 NH, NHX, PHYLO_XML, NEXUS;