Variant c_SimpleXMLElement::t_addchild(const String& qname,
                                       const String& value /* = null_string */,
                                       const String& ns /* = null_string */) {
  if (qname.empty()) {
    raise_warning("Element name is required");
    return uninit_null();
  }
  if (m_is_attribute) {
    raise_warning("Cannot add element to attributes");
    return uninit_null();
  }
  if (!m_node) {
    raise_warning("Parent is not a permanent member of the XML tree");
    return uninit_null();
  }

  xmlChar *prefix = nullptr;
  xmlChar *localname = xmlSplitQName2((xmlChar *)qname.data(), &prefix);
  if (localname == nullptr) {
    localname = xmlStrdup((xmlChar *)qname.data());
  }

  xmlNsPtr nsptr = nullptr;
  xmlNodePtr newnode = xmlNewChild(m_node, nullptr, localname,
                                   (xmlChar *)value.data());
  if (!ns.isNull()) {
    if (ns.empty()) {
      newnode->ns = nullptr;
      nsptr = xmlNewNs(newnode, (xmlChar *)ns.data(), prefix);
    } else {
      nsptr = xmlSearchNsByHref(m_node->doc, m_node, (xmlChar *)ns.data());
      if (nsptr == nullptr) {
        nsptr = xmlNewNs(newnode, (xmlChar *)ns.data(), prefix);
      }
      newnode->ns = nsptr;
    }
  }

  String newname((char*)localname, CopyString);
  String newns((char*)prefix, CopyString);
  xmlFree(localname);
  if (prefix) {
    xmlFree(prefix);
  }

  Object child = create_element(m_root, m_doc, newnode, newns, false);
  if (m_children.toArray().exists(newname)) {
    Variant &tmp = m_children.lvalAt(newname);
    if (tmp.isArray()) {
      tmp.append(child);
    } else {
      Array arr;
      arr.append(tmp);
      arr.append(child);
      m_children.set(newname, arr);
    }
  } else {
    m_children.set(newname, child);
  }
  return child;
}
Variant c_SimpleXMLElement::t_addchild(const String& qname,
                                       const String& value  ,
                                       const String& ns  ) {
  if (qname.empty()) {
    raise_warning("Element name is required");
    return uninit_null();
  }
  if (m_is_attribute) {
    raise_warning("Cannot add element to attributes");
    return uninit_null();
  }
  if (!m_node) {
    raise_warning("Parent is not a permanent member of the XML tree");
    return uninit_null();
  }

  xmlChar *prefix = nullptr;
  xmlChar *localname = xmlSplitQName2((xmlChar *)qname.data(), &prefix);
  if (localname == nullptr) {
    localname = xmlStrdup((xmlChar *)qname.data());
  }

  xmlNsPtr nsptr = nullptr;
  xmlNodePtr newnode = xmlNewChild(m_node, nullptr, localname,
                                   (xmlChar *)value.data());
  if (!ns.isNull()) {
    if (ns.empty()) {
      newnode->ns = nullptr;
      nsptr = xmlNewNs(newnode, (xmlChar *)ns.data(), prefix);
    } else {
      nsptr = xmlSearchNsByHref(m_node->doc, m_node, (xmlChar *)ns.data());
      if (nsptr == nullptr) {
        nsptr = xmlNewNs(newnode, (xmlChar *)ns.data(), prefix);
      }
      newnode->ns = nsptr;
    }
  }

  String newname((char*)localname, CopyString);
  String newns((char*)prefix, CopyString);
  xmlFree(localname);
  if (prefix) {
    xmlFree(prefix);
  }

  Object child = create_element(m_root, m_doc, newnode, newns, false);
  if (m_children.toArray().exists(newname)) {
    Variant &tmp = m_children.lvalAt(newname);
    if (tmp.isArray()) {
      tmp.append(child);
    } else {
      Array arr;
      arr.append(tmp);
      arr.append(child);
      m_children.set(newname, arr);
    }
  } else {
    m_children.set(newname, child);
  }
  return child;
}