[xml] XPath from a specific node instead of document root



Hello.

I apologize if this question has been asked before, but I've looked
all over and I can't seem to find an answer.

I've been using TinyXPath for awhile now, and I've decided to switch
to libxml2 for C portability.

I am trying to execute XPath statements where I need to use a parent
node instead of the document root. For example, take the following xtml:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd";>
<html xmlns="http://www.w3.org/1999/xhtml";>
 <head>
 </head>
 <body>
  <div id="r1">
   <span class="s1"><a class="l1">r1l1</a><a class="l2">r1l2</a></span>
   <span class="s2"><a class="l1">r1l1</a><a class="l2">r1l2</a></span>
  </div>
  <div id="r2">
   <span class="s1"><a class="l1">r1l1</a><a class="l2">r1l2</a></span>
   <span class="s2"><a class="l1">r1l1</a><a class="l2">r1l2</a></span>
  </div>
 </body>
</html>

I'd like to execute three statements here. The first one would get me
spans' who's class is s1:

        /xhtml:html/xhtml:body/xhtml:div/xhtml:span[ class='s1']

That works as expected.

After that, I start having problems. I would then like to get the text
values for as' who's classes are l1 and l2:

        /xhtml:span/xhtml:a[ class='l1']/text()
        /xhtml:span/xhtml:a[ class='l2']/text()

I wrote a wrapper method thinking I could set the xmlXPathContextPtr
node. It works for attributes, but not for nodes:

char* xml_doc_exec_xpath_to_string(XmlDocContext* ctx, const char*
xpath, XmlDocNode* parent_node) {
   char* val = NULL;
   char* tmp = NULL;
   xmlXPathObjectPtr xpathObj;
   xmlXPathContextPtr xpathCtx;

   if (xpathCtx = xmlXPathNewContext(ctx->doc)) {
      if (ctx->doc_type == XML_DOC_TYPE_XHTML) {
         xmlXPathRegisterNs(xpathCtx, "xhtml", "http://www.w3.org/1999/xhtml";);
      }

      if (parent_node) {
         xpathCtx->node = (xmlNodePtr)(parent_node->node);
      }

      if (xpathObj = xmlXPathEvalExpression(xpath, xpathCtx)) {
         if (!xmlXPathNodeSetIsEmpty(xpathObj->nodesetval)) {
            if (xpathObj->nodesetval->nodeTab[0]->type == XML_ATTRIBUTE_NODE) {
               val =
strdup(xpathObj->nodesetval->nodeTab[0]->children[0].content);
            }
            else if (xpathObj->nodesetval->nodeTab[0]->type == XML_TEXT_NODE) {
               val = strdup(xpathObj->nodesetval->nodeTab[0]->content);
            }
         }

         xmlXPathFreeObject(xpathObj);
      }

      xmlXPathFreeContext(xpathCtx);
   }

   return val;
}

Is there anyway to accomplish what I'm trying to do?

Thanks,
-- Jason Millard



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]