# XML Implementation in mq

# Parses an XML string and returns the corresponding data structure.
def xml_parse(input):
  _xml_parse(to_string(input))
end

def _xml_stringify(data):
  def _format_attributes(attributes):
    if (is_empty(keys(attributes))):
      ""
    else:
      " " + join(map(entries(attributes), fn(entry): first(entry) + "=\"" + last(entry) + "\"";), " ")
  end

  def _format_xml_element(element):
    let tag = element["tag"]
    | let attributes = element["attributes"]
    | let children = element["children"]
    | let text = element["text"]
    | let attr_str = _format_attributes(attributes)
    | if (is_empty(children) && is_none(text)):
        "<" + tag + attr_str + "/>"
      else:
        _format_xml_element_with_content(tag, attr_str, children, text)
  end

  def _format_xml_element_with_content(tag, attr_str, children, text):
    let content = if (!is_none(text)):
      text
    else:
      ""
    | let child_content = if (!is_empty(children)):
          join(map(children, _xml_stringify), "")
        else:
          ""
    | let all_content = content + child_content
    | "<" + tag + attr_str + ">" + all_content + "</" + tag + ">"
  end

  | if (is_dict(data) && !is_none(data["tag"])):
      _format_xml_element(data)
    else:
      to_string(data)
end

# Serializes a value to an XML string.
def xml_stringify(data):
  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + _xml_stringify(data) + "\n"
end

def _xml_to_markdown_table(data, depth):
  def _create_element_markdown_table(element):
    let headers = ["Tag", "Attributes", "Text", "Children"]
    | let header_row = "| " + join(headers, " | ") + " |"
    | let separator_row = "| " + join(map(headers, fn(_): "---";), " | ") + " |"
    | let tag_value = element["tag"]
    | let attributes_value = if (is_empty(keys(element["attributes"]))):
          ""
        else:
          join(map(entries(element["attributes"]), fn(entry): first(entry) + "=" + last(entry);), ", ")
    | let text_value = if (is_none(element["text"])):
          ""
        else:
          replace(element["text"], "\n", "\\n")
    | let children_count = to_string(len(element["children"]))
    | let data_row = "| " + tag_value + " | " + attributes_value + " | " + text_value + " | " + children_count + " |"
    | join([header_row, separator_row, data_row], "\n")
  end

  def _create_children_markdown_table(children, depth):
    let headers = ["Index", "Tag", "Attributes", "Text"]
    | let header_row = "| " + join(headers, " | ") + " |"
    | let separator_row = "| " + join(map(headers, fn(_): "---";), " | ") + " |"
    | let children_len = len(children) - 1
    | let data_rows = map(range(0, children_len), fn(i):
          let child = children[i]
          | let tag_value = child["tag"]
          | let attributes_value = if (is_empty(keys(child["attributes"]))):
                      ""
                    elif (!is_none(child["attributes"])):
                      join(map(entries(child["attributes"]), fn(entry): first(entry) + "=" + last(entry);), ", ")
                    else: ""
          | let text_value = if (is_none(child["text"])):
                      ""
                    else:
                      replace(child["text"], "\n", "\\n")
          | "| " + to_string(i) + " | " + tag_value + " | " + attributes_value + " | " + text_value + " |"
        end)
    | let main_table = join([header_row, separator_row] + data_rows, "\n")
    | let child_tables = map(children, fn(child):
          if (!is_empty(child["tag"])):
            "\n\n" + repeat("#", depth + 1) + " Children of " + child["tag"] + ":\n\n" + _xml_to_markdown_table(child, depth + 1)
          else:
            ""
        end)
    | main_table + join(child_tables, "")
  end

  def _create_simple_markdown_table(data):
    "| Value |\n| --- |\n| " + to_string(data) + " |"
  end

  | if (is_dict(data) && !is_none(data["tag"])):
      if (is_empty(data["children"])):
        _create_element_markdown_table(data)
      else:
        _create_children_markdown_table(data["children"], depth)
    else:
      _create_simple_markdown_table(data)
end

# Converts an XML data structure to a Markdown table.
def xml_to_markdown_table(data):
  _xml_to_markdown_table(data, 1)
end
