1 /*============================================================================= 2 Copyright (c) 2017 Daniel James 3 4 Use, modification and distribution is subject to the Boost Software 5 License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 6 http://www.boost.org/LICENSE_1_0.txt) 7 =============================================================================*/ 8 9 #include "boostbook_chunker.hpp" 10 #include <boost/algorithm/string/replace.hpp> 11 #include <boost/lexical_cast.hpp> 12 #include <boost/unordered_set.hpp> 13 14 namespace quickbook 15 { 16 namespace detail 17 { 18 boost::unordered_set<std::string> chunk_types; 19 boost::unordered_set<std::string> chunkinfo_types; 20 21 static struct init_chunk_type 22 { init_chunk_typequickbook::detail::init_chunk_type23 init_chunk_type() 24 { 25 chunk_types.insert("book"); 26 chunk_types.insert("article"); 27 chunk_types.insert("library"); 28 chunk_types.insert("chapter"); 29 chunk_types.insert("part"); 30 chunk_types.insert("appendix"); 31 chunk_types.insert("preface"); 32 chunk_types.insert("qandadiv"); 33 chunk_types.insert("qandaset"); 34 chunk_types.insert("reference"); 35 chunk_types.insert("set"); 36 chunk_types.insert("section"); 37 38 for (boost::unordered_set<std::string>::const_iterator it = 39 chunk_types.begin(); 40 it != chunk_types.end(); ++it) { 41 chunkinfo_types.insert(*it + "info"); 42 } 43 } 44 } init_chunk; 45 46 struct chunk_builder : tree_builder<chunk> 47 { 48 int count; 49 chunk_builderquickbook::detail::chunk_builder50 chunk_builder() : count(0) {} 51 next_path_namequickbook::detail::chunk_builder52 std::string next_path_name() 53 { 54 ++count; 55 std::string result = "page-"; 56 result += boost::lexical_cast<std::string>(count); 57 ++count; 58 return result; 59 } 60 }; 61 62 void chunk_nodes( 63 chunk_builder& builder, xml_tree& tree, xml_element* node); 64 std::string id_to_path(quickbook::string_view); 65 void inline_chunks(chunk*); 66 chunk_document(xml_tree & tree)67 chunk_tree chunk_document(xml_tree& tree) 68 { 69 chunk_builder builder; 70 for (xml_element* it = tree.root(); it;) { 71 xml_element* next = it->next(); 72 chunk_nodes(builder, tree, it); 73 it = next; 74 } 75 76 return builder.release(); 77 } 78 inline_sections(chunk * c,int depth)79 void inline_sections(chunk* c, int depth) 80 { 81 if (c->contents_.root()->name_ == "section" && depth > 1) { 82 --depth; 83 } 84 85 // When depth is 0, inline leading sections. 86 chunk* it = c->children(); 87 if (depth == 0) { 88 for (; it && it->contents_.root()->name_ == "section"; 89 it = it->next()) { 90 inline_chunks(it); 91 } 92 } 93 94 for (; it; it = it->next()) { 95 inline_sections(it, depth); 96 } 97 } 98 inline_all(chunk * c)99 void inline_all(chunk* c) 100 { 101 for (chunk* it = c->children(); it; it = it->next()) { 102 inline_chunks(it); 103 } 104 } 105 inline_chunks(chunk * c)106 void inline_chunks(chunk* c) 107 { 108 c->inline_ = true; 109 c->path_ = c->parent()->path_; 110 for (chunk* it = c->children(); it; it = it->next()) { 111 inline_chunks(it); 112 } 113 } 114 chunk_nodes(chunk_builder & builder,xml_tree & tree,xml_element * node)115 void chunk_nodes( 116 chunk_builder& builder, xml_tree& tree, xml_element* node) 117 { 118 chunk* parent = builder.parent(); 119 120 if (parent && node->type_ == xml_element::element_node && 121 node->name_ == "title") { 122 parent->title_ = tree.extract(node); 123 } 124 else if ( 125 parent && node->type_ == xml_element::element_node && 126 chunkinfo_types.find(node->name_) != chunkinfo_types.end()) { 127 parent->info_ = tree.extract(node); 128 } 129 else if ( 130 node->type_ == xml_element::element_node && 131 chunk_types.find(node->name_) != chunk_types.end()) { 132 chunk* chunk_node = new chunk(tree.extract(node)); 133 builder.add_element(chunk_node); 134 135 chunk_node->id_ = node->has_attribute("id") 136 ? node->get_attribute("id").to_s() 137 : builder.next_path_name(); 138 chunk_node->path_ = id_to_path(chunk_node->id_); 139 140 builder.start_children(); 141 for (xml_element* it = node->children(); it;) { 142 xml_element* next = it->next(); 143 chunk_nodes(builder, tree, it); 144 it = next; 145 } 146 builder.end_children(); 147 } 148 } 149 id_to_path(quickbook::string_view id)150 std::string id_to_path(quickbook::string_view id) 151 { 152 std::string result(id.begin(), id.end()); 153 boost::replace_all(result, ".", "/"); 154 result += ".html"; 155 return result; 156 } 157 } 158 } 159