/** ** Copyright (c) 2007-2009 Illumina, Inc. ** ** This software is covered by the "Illumina Genome Analyzer Software ** License Agreement" and the "Illumina Source Code License Agreement", ** and certain third party copyright/licenses, and any user of this ** source file is bound by the terms therein (see accompanying files ** Illumina_Genome_Analyzer_Software_License_Agreement.pdf and ** Illumina_Source_Code_License_Agreement.pdf and third party ** copyright/license notices). ** ** This file is part of the Consensus Assessment of Sequence And VAriation ** (CASAVA) software package. ** ** \file PtreeXml.cpp ** ** \brief Simple utility for boost::ptree to XML transformation. ** ** \author Roman Petrovski **/ #include #include #include #include "io/PtreeXml.hh" namespace casava { namespace io { using namespace boost::property_tree; static const std::string indexed(""); void collapseIndexLayer(const ptree::value_type &nameElementKv, ptree &resultTree) { if ("" == nameElementKv.first) { BOOST_FOREACH(const ptree::value_type &valueElementKv, nameElementKv.second) { resultTree.add_child(valueElementKv.first, valueElementKv.second); } } else if (indexed == nameElementKv.first.substr(0, indexed.length())) { BOOST_FOREACH(const ptree::value_type &indexElementKv, nameElementKv.second) { ptree childTree; std::for_each(indexElementKv.second.begin(), indexElementKv.second.end(), boost::bind(collapseIndexLayer, _1, boost::ref(childTree))); BOOST_ASSERT('<' == indexElementKv.first[0]); size_t attrNameEndPos = indexElementKv.first.find('>', 1); BOOST_ASSERT(std::string::npos != attrNameEndPos); childTree.add("." + indexElementKv.first.substr(1, attrNameEndPos -1), indexElementKv.first.substr(attrNameEndPos+1)); resultTree.add_child(nameElementKv.first.substr(indexed.length()), childTree); } } else { ptree childTree; std::for_each(nameElementKv.second.begin(), nameElementKv.second.end(), boost::bind(collapseIndexLayer, _1, boost::ref(childTree))); resultTree.add_child(nameElementKv.first, childTree); } } /** * @brief Rearranges property tree according to a few basic schema customization rules. * * The original property tree would produce an xml * where each Read, Lane and Tile element has a number of child elements named after * the number of the read, lane of tile respectively. For example: * * Tree: * Summary.Read.1.Lane.4.Tile.5.value.Yield = 123 * .YieldQ30 = 12 * .6.value.Yield = 123 * .YieldQ30 = 12 * * Xml: * * * <1> * * <4> * * <5> * ... * This is inconvenient and against the rest of the CASAVA metadata xml schemas. * Before the tree is written out into the xml, all index nodes are collapsed into * xml attribute nodes so that the resulting xml looks like: * * Tree: * Summary.Read.1.Lane.4.Tile.5.value.Yield = 123 * .YieldQ30 = 12 * .6.value.Yield = 123 * .YieldQ30 = 12 * * Xml: * * * * * 123 * 12 * * * 123 * 12 * ... */ std::ostream &operator << (std::ostream &os, const boost::property_tree::ptree &tree) { boost::property_tree::ptree treeWithIndexAttributes; if (!tree.empty()) { collapseIndexLayer(*tree.begin(), treeWithIndexAttributes); boost::property_tree::write_xml(os, treeWithIndexAttributes, boost::property_tree::xml_writer_make_settings(' ', 2)); } else { boost::property_tree::write_xml(os, tree, boost::property_tree::xml_writer_make_settings(' ', 2)); } return os; } } //namespace io } //namespace casava