libwordring
simple_parser.hpp
1 #pragma once
2 
3 // https://html.spec.whatwg.org/multipage/parsing.html
4 // https://triple-underscore.github.io/HTML-parsing-ja.html
5 
6 #include <wordring/html/html_defs.hpp>
7 
8 #include <wordring/html/simple_node.hpp>
9 #include <wordring/html/simple_traits.hpp>
10 
11 #include <wordring/whatwg/html/parsing/tree_construction_dispatcher.hpp>
12 #include <wordring/whatwg/encoding/api.hpp>
13 
14 #include <cassert>
15 #include <type_traits>
16 #include <utility>
17 
18 namespace wordring::html
19 {
31  template <typename T, typename Container>
32  class simple_parser_base : public wordring::whatwg::html::parsing::tree_construction_dispatcher<T, node_traits<typename Container::iterator>>
33  {
34  public:
36 
38  using this_type = T;
39 
40  using container = Container;
41 
42  using string_type = typename traits::string_type;
43  using node_type = typename traits::node_type;
44  using node_pointer = typename traits::node_pointer;
45 
46  using document_type = typename traits::document_type;
47  using document_type_type = typename traits::document_type_type;
48  using document_fragment_type = typename traits::document_fragment_type;
49  using element_type = typename traits::element_type;
50  using text_type = typename traits::text_type;
51  using processing_instruction_type = typename traits::processing_instruction_type;
52  using comment_type = typename traits::comment_type;
53 
54  using attribute_type = typename traits::attribute_type;
55  using attribute_pointer = typename traits::attribute_pointer;
56 
59 
60  public:
62  encoding_confidence_name confidence = encoding_confidence_name::irrelevant,
63  encoding_name enc = static_cast<encoding_name>(0),
64  bool fragments_parser = false)
65  : base_type(confidence, enc, fragments_parser)
66  {
67  m_document = m_c.insert(m_c.end(), document_type());
68  m_temporary = m_c.insert(m_c.end(), node_type());
69  }
70 
73  void clear(encoding_confidence_name confidence, encoding_name enc)
74  {
75  base_type::clear(confidence, enc);
76  m_c.clear();
77  m_document = m_c.insert(m_c.end(), document_type());
78  m_temporary = m_c.insert(m_c.end(), node_type());
79  }
80 
81  // ----------------------------------------------------------------------------------------
82  // 文書
83  // ----------------------------------------------------------------------------------------
84 
89  node_pointer get_document() { return m_document; }
90 
91  // ----------------------------------------------------------------------------------------
92  // 文書型
93  // ----------------------------------------------------------------------------------------
94 
95  node_pointer insert_document_type(node_pointer pos, document_type_type&& doctype)
96  {
97  return m_c.insert(pos, std::move(doctype));
98  }
99 
100  // ----------------------------------------------------------------------------------------
101  // 要素
102  // ----------------------------------------------------------------------------------------
103 
104  /* @brief 要素を作成する
105 
106  @sa https://dom.spec.whatwg.org/#concept-create-element
107  @sa https://triple-underscore.github.io/DOM4-ja.html#concept-create-element
108  */
109  node_pointer create_element(node_pointer doc, std::u32string name, ns_name ns)
110  {
111  return m_c.insert(m_temporary.end(), element_type(ns, string_type(), encoding_cast<string_type>(name)));
112  }
113 
114  node_pointer create_element(node_pointer doc, tag_name name, ns_name ns)
115  {
116  return m_c.insert(m_temporary.end(), element_type(ns, string_type(), name));
117  }
118 
119  node_pointer insert_element(node_pointer pos, node_pointer it)
120  {
121  return m_c.move(pos, it);
122  }
123 
124  node_pointer get_node_document(node_pointer it)
125  {
126  return get_document();
127  }
128 
131  void erase_element(node_pointer it)
132  {
133  m_c.erase(it);
134  }
135 
140  void move_node(node_pointer pos, node_pointer it)
141  {
142  m_c.move(pos, it);
143  }
144 
145  // ----------------------------------------------------------------------------------------
146  // 属性
147  // ----------------------------------------------------------------------------------------
148 
149  void append_attribute(node_pointer it, ns_name ns, std::u32string const& prefix, std::u32string const& name, std::u32string const& value)
150  {
151  it->push_back(attribute_type(ns, encoding_cast<string_type>(prefix), encoding_cast<string_type>(name), encoding_cast<string_type>(value)));
152  }
153 
154  /*
155  on_in_body_insertion_mode() 内の2カ所から呼ばれている。
156  */
157  bool contains(node_pointer it, ns_name ns, std::u32string const& prefix, std::u32string const& name)
158  {
159  return it->contains(ns, encoding_cast<string_type>(prefix), encoding_cast<string_type>(name));
160  }
161 
162  // ----------------------------------------------------------------------------------------
163  // テキスト
164  // ----------------------------------------------------------------------------------------
165 
166  node_pointer insert_text(node_pointer pos, text_type&& text)
167  {
168  return m_c.insert(pos, std::move(text));
169  }
170 
171  // ----------------------------------------------------------------------------------------
172  // コメント
173  // ----------------------------------------------------------------------------------------
174 
175  node_pointer insert_comment(node_pointer pos, comment_type&& comment)
176  {
177  return m_c.insert(pos, std::move(comment));
178  }
179 
180  // ----------------------------------------------------------------------------------------
181  // 解析エラー
182  //
183  // 12.2.2 Parse errors
184  // https://html.spec.whatwg.org/multipage/parsing.html#parse-errors
185  // ----------------------------------------------------------------------------------------
186 
191  void on_report_error(error_name e) {}
192 
193  // ----------------------------------------------------------------------------------------
194  // 符号化法
195  //
196  // 12.2.3.3 Character encodings
197  // https://html.spec.whatwg.org/multipage/parsing.html#character-encodings
198  // ----------------------------------------------------------------------------------------
199 
204  void on_change_encoding(encoding_name name) {}
205 
206  protected:
207  container m_c;
208  node_pointer m_document;
209  node_pointer m_temporary;
210  };
211 
212  /* @brief 文字エンコーディングに対応する HTML パーサー
213  *
214  * @tparam Container 木コンテナ
215  * @tparam ForwardIterator 入力文字列に対するイテレータ
216  *
217  * 木コンテナは、 wordring::tree と wordring::tag_tree でテストされています。
218  *
219  * 文書内にエンコーディングの指定を発見した場合、入力文字列を最初から読み直します。
220  */
221  template <typename Container, typename ForwardIterator>
222  class basic_simple_parser : public simple_parser_base<basic_simple_parser<Container, ForwardIterator>, Container>
223  {
224  public:
226  using container = Container;
227  using iterator = ForwardIterator;
228 
229  static_assert(std::is_base_of_v<std::forward_iterator_tag, typename std::iterator_traits<iterator>::iterator_category>);
230 
231  public:
239  encoding_confidence_name confidence = encoding_confidence_name::irrelevant,
240  encoding_name enc = static_cast<encoding_name>(0),
241  bool fragments_parser = false)
242  : base_type(confidence, enc, fragments_parser)
243  , m_updated_encoding_name(static_cast<encoding_name>(0))
244  , m_first()
245  , m_last()
246  {
247  }
248 
251  void clear(encoding_confidence_name confidence, encoding_name enc)
252  {
253  base_type::clear(confidence, enc);
254  m_updated_encoding_name = static_cast<encoding_name>(0);
255  }
256 
264  void parse(iterator first, iterator last)
265  {
266  if constexpr (sizeof(*first) == 4)
267  {
268  while (first != last)
269  {
270  push_back(*first);
271  ++first;
272  }
273  }
274  else if constexpr (sizeof(*first) == 2)
275  {
276  std::u32string s;
277  encoding_cast(first, last, std::back_inserter(s));
278  for (char32_t cp : s) push_back(cp);
279  }
280  else if constexpr (sizeof(*first) == 1)
281  {
282  using namespace wordring::whatwg::encoding;
283 
284  text_decoder dec;
285  Start:
286  if (base_type::m_encoding_name == static_cast<encoding_name>(0)) base_type::m_encoding_name = encoding_name::UTF_8;
287  dec = text_decoder(base_type::m_encoding_name, false, false);
288  std::u32string s = dec.decode(first, last);
289  for (auto cp : s)
290  {
292  if (m_updated_encoding_name != static_cast<encoding_name>(0))
293  {
294  clear(base_type::m_encoding_confidence, m_updated_encoding_name);
295  goto Start;
296  }
297  }
298  }
299  else assert(false);
300  }
301 
302  container get()
303  {
304  base_type::m_c.erase(base_type::m_temporary);
305  container c;
306  std::swap(base_type::m_c, c);
307  return c;
308  }
309 
310  void push_back(char32_t cp) { base_type::push_code_point(cp); }
311 
312  void on_change_encoding(encoding_name name)
313  {
314  m_updated_encoding_name = name;
315  }
316 
317  protected:
318  encoding_name m_updated_encoding_name;
319 
320  iterator m_first;
321  iterator m_last;
322  };
323 
324  template <typename Container>
325  class simple_parser : public simple_parser_base<simple_parser<Container>, Container>
326  {
327  };
328 }
wordring::html::simple_parser_base::clear
void clear(encoding_confidence_name confidence, encoding_name enc)
初期状態に戻し、パーサーを再利用可能とする
Definition: simple_parser.hpp:73
wordring::html::simple_parser_base::erase_element
void erase_element(node_pointer it)
ノードを削除する
Definition: simple_parser.hpp:131
wordring::html::node_traits
HTMLノードへの操作を仲介するアダプタ
Definition: html/html_defs.hpp:29
wordring::html::simple_parser_base
simple_node 用の HTML5 パーサー
Definition: simple_parser.hpp:32
wordring::html::simple_parser_base::on_change_encoding
void on_change_encoding(encoding_name name)
文字エンコーディングを変更する時に呼び出されるコールバック
Definition: simple_parser.hpp:204
wordring::whatwg::encoding
wordring::html::basic_simple_parser::basic_simple_parser
basic_simple_parser(encoding_confidence_name confidence=encoding_confidence_name::irrelevant, encoding_name enc=static_cast< encoding_name >(0), bool fragments_parser=false)
パーサー・インスタンスを構築する
Definition: simple_parser.hpp:238
wordring::whatwg::html::parsing::input_stream< basic_simple_parser< Container, ForwardIterator > >::push_code_point
void push_code_point(value_type cp)
コード・ポイントを末尾に追加する
Definition: whatwg/html/parsing/input_stream.hpp:107
wordring::whatwg::html::parsing::tokenizer::clear
void clear()
初期状態に戻し、再利用可能とする
Definition: whatwg/html/parsing/tokenization.hpp:92
wordring::html::basic_simple_parser::parse
void parse(iterator first, iterator last)
文字列を解析し、 HTML 木を作成する
Definition: simple_parser.hpp:264
wordring::whatwg::encoding::text_decoder
TextDecoderCommon
Definition: whatwg/encoding/api.hpp:98
wordring::html
wordring::html::simple_parser_base::get_document
node_pointer get_document()
文書ノードを返す
Definition: simple_parser.hpp:89
wordring::whatwg::html::basic_html_atom
列挙体と文字列の相互変換を行うクラス
Definition: whatwg/html/html_atom.hpp:28
wordring::html::basic_simple_parser
Definition: simple_parser.hpp:222
wordring::html::basic_simple_parser::clear
void clear(encoding_confidence_name confidence, encoding_name enc)
初期状態に戻し、パーサーを再利用可能とする
Definition: simple_parser.hpp:251
wordring::html::simple_parser_base::move_node
void move_node(node_pointer pos, node_pointer it)
ノードを移動する
Definition: simple_parser.hpp:140
wordring::html::simple_parser
Definition: simple_parser.hpp:325
wordring::whatwg::encoding::text_decoder::decode
std::u32string decode(InputIterator first=nullptr, InputIterator last=nullptr, bool stream=false)
デコード
Definition: whatwg/encoding/api.hpp:140
wordring::html::simple_parser_base::on_report_error
void on_report_error(error_name e)
エラーが起きた時に呼び出されるコールバック
Definition: simple_parser.hpp:191
wordring::whatwg::html::parsing::tree_construction_dispatcher
HTML5 パーサーの木構築段階
Definition: tree_construction_dispatcher.hpp:41