<commit_before>// This file is part of MicroRestD <http://github.com/ufal/microrestd/>.
//
// Copyright 2015 Institute of Formal and Applied Linguistics, Faculty of
// Mathematics and Physics, Charles University in Prague, Czech Republic.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#pragma once

#include <string>
#include <vector>

#include "string_piece.h"

namespace ufal {
namespace microrestd {

// Declarations
class xml_builder {
 public:
  // Clear
  inline xml_builder& clear();

  // Encode
  inline xml_builder& element(string_piece name);
  inline xml_builder& attribute(string_piece name, string_piece value);
  inline xml_builder& text(string_piece str);
  inline xml_builder& close();
  inline xml_builder& compact(bool compact);

  // Raw appending
  inline xml_builder& append_raw(string_piece data);

  // Close all open objects and arrays
  inline xml_builder& close_all();

  // Return current xml
  inline string_piece current() const;

  // Remove current xml prefix; for response_generator
  void discard_current_prefix(size_t length);

  // XML mime
  static const char* mime;

 private:
  void encode(string_piece str);

  std::vector<char> xml;
  std::vector<std::string> stack;
  size_t stack_length;
  bool in_element = false;
  bool compacting = false;
};

// Definitions
xml_builder& xml_builder::clear() {
  xml.clear();
  stack.clear();
  stack_length = 0;
  in_element = false;
  return *this;
}

xml_builder& xml_builder::element(string_piece name) {
  if (in_element) {
    xml.push_back('/');
    xml.push_back('>');
    in_element = false;
    if (!compacting) {
      xml.push_back('\n');
      xml.insert(xml.end(), stack_length, ' ');
    }
  }

  xml.push_back('<');
  xml.insert(xml.end(), name.str, name.str + name.len);
  in_element = true;

  if (stack_length >= stack.size())
    stack.emplace_back(name.str, name.len);
  else
    stack[stack_length].assign(name.str, name.len);
  stack_length++;

  return *this;
}

xml_builder& xml_builder::attribute(string_piece name, string_piece value) {
  if (in_element) {
    xml.push_back(' ');
    xml.insert(xml.end(), name.str, name.str + name.len);
    xml.push_back('=');
    xml.push_back('"');
    encode(value);
    xml.push_back('"');
  }
  return *this;
}

xml_builder& xml_builder::text(string_piece str) {
  if (in_element) {
    xml.push_back('/');
    xml.push_back('>');
    in_element = false;
    if (!compacting) {
      xml.push_back('\n');
      xml.insert(xml.end(), stack_length, ' ');
    }
  }
  encode(str);
  return *this;
}

xml_builder& xml_builder::close() {
  if (stack_length) {
    stack_length--;
    if (in_element) {
      xml.push_back('/');
      xml.push_back('>');
    } else {
      if (!compacting) xml.insert(xml.end(), stack_length, ' ');
      xml.push_back('<');
      xml.push_back('/');
      xml.insert(xml.end(), stack[stack_length].begin(), stack[stack_length].end());
      xml.push_back('>');
    }
    if (!compacting) xml.push_back('\n');<commit_msg>Do not close element in element() and close().<commit_after>// This file is part of MicroRestD <http://github.com/ufal/microrestd/>.
//
// Copyright 2015 Institute of Formal and Applied Linguistics, Faculty of
// Mathematics and Physics, Charles University in Prague, Czech Republic.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#pragma once

#include <string>
#include <vector>

#include "string_piece.h"

namespace ufal {
namespace microrestd {

// Declarations
class xml_builder {
 public:
  // Clear
  inline xml_builder& clear();

  // Encode
  inline xml_builder& element(string_piece name);
  inline xml_builder& attribute(string_piece name, string_piece value);
  inline xml_builder& text(string_piece str);
  inline xml_builder& close();
  inline xml_builder& compact(bool compact);

  // Raw appending
  inline xml_builder& append_raw(string_piece data);

  // Close all open objects and arrays
  inline xml_builder& close_all();

  // Return current xml
  inline string_piece current() const;

  // Remove current xml prefix; for response_generator
  void discard_current_prefix(size_t length);

  // XML mime
  static const char* mime;

 private:
  void encode(string_piece str);

  std::vector<char> xml;
  std::vector<std::string> stack;
  size_t stack_length = 0;
  bool in_element = false;
  bool compacting = false;
};

// Definitions
xml_builder& xml_builder::clear() {
  xml.clear();
  stack.clear();
  stack_length = 0;
  in_element = false;
  return *this;
}

xml_builder& xml_builder::element(string_piece name) {
  if (in_element) {
    xml.push_back('>');
    in_element = false;
    if (!compacting) {
      xml.push_back('\n');
      xml.insert(xml.end(), stack_length, ' ');
    }
  }

  xml.push_back('<');
  xml.insert(xml.end(), name.str, name.str + name.len);
  in_element = true;

  if (stack_length < stack.size())
    stack[stack_length].assign(name.str, name.len);
  else
    stack.emplace_back(name.str, name.len);
  stack_length++;

  return *this;
}

xml_builder& xml_builder::attribute(string_piece name, string_piece value) {
  if (in_element) {
    xml.push_back(' ');
    xml.insert(xml.end(), name.str, name.str + name.len);
    xml.push_back('=');
    xml.push_back('"');
    encode(value);
    xml.push_back('"');
  }
  return *this;
}

xml_builder& xml_builder::text(string_piece str) {
  if (in_element) {
    xml.push_back('>');
    in_element = false;
    if (!compacting) {
      xml.push_back('\n');
      xml.insert(xml.end(), stack_length, ' ');
    }
  }
  encode(str);
  return *this;
}

xml_builder& xml_builder::close() {
  if (stack_length) {
    stack_length--;
    if (in_element) {
      xml.push_back('/');
      xml.push_back('>');
      in_element = false;
    } else {
      if (!compacting) xml.insert(xml.end(), stack_length, ' ');
      xml.push_back('<');
      xml.push_back('/');
      xml.insert(xml.end(), stack[stack_length].begin(), stack[stack_length].end());
      xml.push_back('>');
    }
    if (!compacting) xml.push_back('\n');
{'fraction_non_alphanumeric': 0.148751185583307, 'fraction_numerical': 0.0030034777110338287, 'mean_word_length': 3.5064102564102564, 'pattern_counts': {'":': 0, '<': 18, '<?xml version=': 0, '>': 22, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 102}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2949574', 'n_tokens_mistral': 2175, 'n_tokens_neox': 2113, 'n_words': 521}