A toolkit for working with phylogenetic data.
v0.24.0
tree/formats/phyloxml/writer.cpp
Go to the documentation of this file.
1 /*
2  Genesis - A toolkit for working with phylogenetic data.
3  Copyright (C) 2014-2020 Lucas Czech and HITS gGmbH
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  Contact:
19  Lucas Czech <lucas.czech@h-its.org>
20  Exelixis Lab, Heidelberg Institute for Theoretical Studies
21  Schloss-Wolfsbrunnenweg 35, D-69118 Heidelberg, Germany
22 */
23 
32 
33 #include "genesis/tree/tree.hpp"
34 
37 
44 
45 #include <cassert>
46 #include <stdexcept>
47 #include <vector>
48 
49 namespace genesis {
50 namespace tree {
51 
52 // =================================================================================================
53 // Printing
54 // =================================================================================================
55 
56 void PhyloxmlWriter::write( Tree const& tree, std::shared_ptr<utils::BaseOutputTarget> target ) const
57 {
59  to_document( tree, xml );
60  utils::XmlWriter().write( xml, target );
61 }
62 
63 void PhyloxmlWriter::to_document ( Tree const& tree, utils::XmlDocument& xml ) const
64 {
65  xml.clear();
66 
67  // Call all preparatory plugins.
68  for( auto const& prepare_plugin : prepare_writing_plugins ) {
69  prepare_plugin( tree, xml );
70  }
71 
72  // Set XML declaration.
73  // xml.xml_tag = "xml";
74  // xml.declarations.emplace("version", "1.0");
75  // xml.declarations.emplace("encoding", "UTF-8");
76 
77  // Set XML root element.
78  xml.tag = "phyloxml";
79  xml.attributes.emplace("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
80  xml.attributes.emplace(
81  "xsi:schemaLocation",
82  "http://www.phyloxml.org http://www.phyloxml.org/1.10/phyloxml.xsd"
83  );
84  xml.attributes.emplace("xmlns", "http://www.phyloxml.org");
85 
86  // Add the (phylogeny) element.
87  auto phylogeny = utils::make_unique< utils::XmlElement >();
88  phylogeny->tag = "phylogeny";
89  phylogeny->attributes.emplace("rooted", "true");
90  //~ phylogeny.attributes.emplace("rerootable", "true");
91 
92  // Create a stack where we will push the tree elements to. Use the phylogeny element as root.
93  std::vector< utils::XmlElement* > stack;
94  stack.push_back(phylogeny.get());
95  xml.content.push_back(std::move(phylogeny));
96  size_t cur_d = 0;
97 
98  // Store the distance from each node to the root. Will be used to determine the position on the
99  // stack that is used for adding clades to the phylogeny.
100  auto depths = node_path_length_vector(tree);
101 
102  for( auto it : preorder(tree) ) {
103  // Depth can never increase more than one between two nodes when doing a preoder traversal.
104  assert(depths[it.node().index()] <= cur_d + 1);
105 
106  // Delete end of stack when moving up the tree, unless we are already at the root.
107  while (cur_d >= depths[it.node().index()] && depths[it.node().index()] > 0) {
108  assert(stack.size() > 0);
109  stack.pop_back();
110  --cur_d;
111  }
112  // Set current depth (explicitly needed in case we are moving further into the tree, which
113  // means that the loop above is not executed).
114  cur_d = depths[it.node().index()];
115 
116  // Create clade element, append it to the stack, so that all sub-elements will use it as
117  // parent.
118  auto clade = utils::make_unique< utils::XmlElement >();
119  clade->tag = "clade";
120 
121  // Call all plugins to translate node and edge data to xml.
122  for( auto const& node_plugin : node_to_element_plugins ) {
123  node_plugin( it.node(), *clade.get() );
124  }
125  for( auto const& edge_plugin : edge_to_element_plugins ) {
126  edge_plugin( it.edge(), *clade.get() );
127  }
128 
129  // Append the clade to the current parent (end of the stack), then use it as the new parent
130  // for the next iteration of the loop.
131  auto clade_ptr = clade.get();
132  stack.back()->content.push_back(std::move(clade));
133  stack.push_back(clade_ptr);
134  }
135 
136  // Call all finalizing plugins.
137  for( auto const& finish_plugin : finish_writing_plugins ) {
138  finish_plugin( tree, xml );
139  }
140 }
141 
142 } // namespace tree
143 } // namespace genesis
std::vector< node_to_element_function > node_to_element_plugins
Collect all functions to be called for each TreeNode in order to translate it to a Phyloxml represent...
std::vector< size_t > node_path_length_vector(Tree const &tree, TreeNode const &node)
Return a vector containing the depth of all nodes with respect to the given start node...
void write(Tree const &tree, std::shared_ptr< utils::BaseOutputTarget > target) const
Write a Tree to an output target, using the Phyloxml format.
Container namespace for all symbols of genesis in order to keep them separate when used as a library...
Provides some valuable additions to STD.
void to_document(Tree const &tree, utils::XmlDocument &xml) const
Store the information of the tree into an Phyloxml-formatted XmlDocument.
std::vector< prepare_writing_function > prepare_writing_plugins
Collect all functions to be called before starting the actual tree writing.
Class for representing phylogenetic trees.
Definition: tree/tree.hpp:97
A collection of classes for working with XML documents. See XmlDocument for more. ...
Provides functions for accessing the file system.
Provides easy and fast logging functionality.
std::vector< std::unique_ptr< XmlValue > > content
utils::Range< IteratorPreorder< true > > preorder(ElementType const &element)
Header of Tree class.
Header of Tree distance methods.
void write(XmlDocument const &document, std::shared_ptr< utils::BaseOutputTarget > target) const
std::vector< finish_writing_function > finish_writing_plugins
Collect all functions to be called after finishing the actual tree writing.
std::vector< edge_to_element_function > edge_to_element_plugins
Collect all functions to be called for each TreeEdge in order to translate it to a Phyloxml represent...