Variant c_SimpleXMLElement::t_xpath(const String& path) {
  if (m_is_attribute || !m_node) {
    return uninit_null();
  }

  xmlDocPtr doc = m_node->doc;

  int nsnbr = 0;
  xmlNsPtr *ns = xmlGetNsList(doc, m_node);
  if (ns != nullptr) {
    while (ns[nsnbr] != nullptr) {
      nsnbr++;
    }
  }

  if (m_xpath == nullptr) {
    m_xpath = xmlXPathNewContext(doc);
  }
  m_xpath->node = m_node;
  m_xpath->namespaces = ns;
  m_xpath->nsNr = nsnbr;

  xmlXPathObjectPtr retval = xmlXPathEval((xmlChar *)path.data(), m_xpath);
  if (ns != nullptr) {
    xmlFree(ns);
    m_xpath->namespaces = nullptr;
    m_xpath->nsNr = 0;
  }

  if (!retval) {
    return false;
  }

  xmlNodeSetPtr result = retval->nodesetval;
  if (!result) {
    xmlXPathFreeObject(retval);
    return false;
  }

  Array ret = Array::Create();
  for (int i = 0; i < result->nodeNr; ++i) {
    xmlNodePtr nodeptr = result->nodeTab[i];
    Object sub;
    if (m_node == nodeptr) {
      sub = this;
    } else {
      switch (nodeptr->type) {
        case XML_TEXT_NODE:
        case XML_CDATA_SECTION_NODE:
        case XML_ATTRIBUTE_NODE:
          sub = find_node(m_root->m_children, nodeptr->parent);
          break;
        case XML_ELEMENT_NODE:
          sub = find_node(m_root->m_children, nodeptr);
        default:
          break;
      }
    }
    ret.append(sub);
  }

  xmlXPathFreeObject(retval);
  return ret;
}
Variant c_SimpleXMLElement::t_xpath(const String& path) {
  if (m_is_attribute || !m_node) {
    return uninit_null();
  }

  xmlDocPtr doc = m_node->doc;

  int nsnbr = 0;
  xmlNsPtr *ns = xmlGetNsList(doc, m_node);
  if (ns != nullptr) {
    while (ns[nsnbr] != nullptr) {
      nsnbr++;
    }
  }

  if (m_xpath == nullptr) {
    m_xpath = xmlXPathNewContext(doc);
  }
  m_xpath->node = m_node;
  m_xpath->namespaces = ns;
  m_xpath->nsNr = nsnbr;

  xmlXPathObjectPtr retval = xmlXPathEval((xmlChar *)path.data(), m_xpath);
  if (ns != nullptr) {
    xmlFree(ns);
    m_xpath->namespaces = nullptr;
    m_xpath->nsNr = 0;
  }

  if (!retval) {
    return false;
  }

  xmlNodeSetPtr result = retval->nodesetval;
  if (!result) {
    xmlXPathFreeObject(retval);
    return false;
  }

  Array ret = Array::Create();
  for (int i = 0; i < result->nodeNr; ++i) {
    xmlNodePtr nodeptr = result->nodeTab[i];
    Object sub;
    if (m_node == nodeptr) {
      sub = this;
    } else {
      switch (nodeptr->type) {
        case XML_TEXT_NODE:
        case XML_CDATA_SECTION_NODE:
        case XML_ATTRIBUTE_NODE:
          sub = find_node(m_root->m_children, nodeptr->parent);
          break;
        case XML_ELEMENT_NODE:
          sub = find_node(m_root->m_children, nodeptr);
        default:
          break;
      }
    }
    ret.append(sub);
  }

  xmlXPathFreeObject(retval);
  return ret;
}