title: How to use XPath in XMLReader API of libxml2?
body: <p>The tutorial <a href="http://xmlsoft.org/xmlreader.html#Mixing" rel="nofollow">here</a> says we can used XPath in XMLReader API if we expand the current node and set it to be the context node of the <code>xmlXPathContext</code> object. Unfortunately, the example the tutorial provides is in Python, which language I don't understand at all. I tried to create my own example in C++, but got stuck. The problem is function <code>xmlXPathSetContextNode</code> always fails. Below is my codes and a XML document to be read by the example application.</p>
  
  <pre><code>// BUILD: g++ thisFile.cpp -std=c++11 -Wall $(xml2-config --cflags --libs)
  #include &lt;cstdio&gt; // for function fopen, fseek, rewind, fread and fclose
  #include &lt;libxml/xmlreader.h&gt; // for data type xmlTextReader
  #include &lt;libxml/xpath.h&gt; // for data type xmlXPathContext
  #include &lt;memory&gt; // for class template shared_ptr
  #include &lt;stdexcept&gt; // for class runtime_error;
  #define _X(s) ((const xmlChar *)s)
  int main(int argc, char *argv[])
  {
      using std::shared_ptr;
      // Create a text reader.
      shared_ptr&lt;xmlTextReader&gt; reader(::xmlReaderForFile("sample.xml", NULL, 0), &amp;::xmlFreeTextReader);
      // Create a XPath context.
      xmlDocPtr doc = ::xmlTextReaderCurrentDoc(reader.get());
      shared_ptr&lt;xmlXPathContext&gt; ctxt(::xmlXPathNewContext(doc), &amp;::xmlXPathFreeContext);
      // Use the text reader to read the stream.
      int ret;
      try {
          while ((ret = ::xmlTextReaderRead(reader.get())) == 1) {
              // Ignore all nodes except &lt;storyinfo&gt;.
  #if 0
              xmlNodePtr node = ::xmlTextReaderCurrentNode(reader.get());
  #else
              xmlNodePtr node = ::xmlTextReaderExpand(reader.get());
  #endif
              if (::xmlStrncmp(node-&gt;name, _X("storyinfo"), 10) != 0) continue;
              // Set the current node as the context node.
              ::printf("node: 0x%08X\n", (size_t)node);
              if (::xmlXPathSetContextNode(node, ctxt.get()) == -1) {
                  ::fprintf(stderr, "ERROR(%d): %s\n", ctxt-&gt;lastError.code, ctxt-&gt;lastError.message);
                  throw std::runtime_error("err_xpath_set_context");
              }
              // Use a XPath to find &lt;datewritten&gt;.
              shared_ptr&lt;xmlXPathObject&gt; xpathFound(::xmlXPathEvalExpression(_X("datewritten"), ctxt.get()), &amp;::xmlXPathFreeObject);
              if (xmlXPathNodeSetGetLength(xpathFound-&gt;nodesetval) == 0) throw std::runtime_error("err_xpath_not_fonud");
              shared_ptr&lt;xmlChar&gt; zTextContent(::xmlXPathCastToString(xpathFound.get()), ::xmlFree);
              ::printf("found: %s\n", zTextContent.get());
              break;
          }
          if (ret == -1) {
              ::fprintf(stderr, "ERROR: %s\n", "xmlTextReaderRead failure!");
              return 1;
          }
      }
      catch (const std::runtime_error&amp; e) {
          ::fprintf(stderr, "ERROR: %s\n", e.what());
      }
      // Exit the program.
      return 0;
  }
  </code></pre>
  
  <p>The contents of the XML document is</p>
  
  <pre><code>&lt;?xml version="1.0"?&gt;
  &lt;story&gt;
      &lt;storyinfo&gt;
          &lt;author&gt;John Fleck&lt;/author&gt;
          &lt;datewritten&gt;June 2, 2002&lt;/datewritten&gt;
          &lt;keyword&gt;example keyword&lt;/keyword&gt;
      &lt;/storyinfo&gt;
      &lt;body&gt;
          &lt;headline&gt;This is the headline&lt;/headline&gt;
          &lt;para&gt;This is the body text.&lt;/para&gt;
      &lt;/body&gt;
  &lt;/story&gt;
  </code></pre>
  
  <p>Any hint will be appreciated. Thanks in advance. m(_ _)m</p>