Quentin
Quentin

Reputation: 1781

How to apply successively two xpath expressions with libxml?

To sum up, i'm a totally beginner in libxml and I have to use an existing source code. The main idea is to apply a first xpath expression to extract a set of nodes from an xml file. Then, for each node, the second xpath expression shall be applied to extract some values.

Existing source code is:

int xt_parseXmlResult(xmlDocPtr doc, const char *xpath, assoc_arrayc_t expr, arrayc_t *result)
{
    xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc);

    // Register namespaces ...

    /*
     * Evaluate main xpath expression
     */
    xmlXPathObjectPtr xpathNodes = xmlXPathEvalExpression((xmlChar *)xpath, xpathCtx);

    /*
     * Now we apply the xpath expressions on each node returned by the first xpath request
     */
    // First loop is on the XML document as we have to create a new context each
    // time we change the document
    int nbDocs = xpathNodes->nodesetval->nodeNr;

    for (row = 0; row < nbDocs; row++)
    {
        xmlXPathContextPtr  subCtx = xmlXPathNewContext(doc);

        // Register namespaces ...

        // Update context to use the nodeset related to this row
        subCtx->node = xpathNodes->nodesetval->nodeTab[row];

        for (col = 0; col < expr.nbItems; col++)
        {
            // Evaluate expression
            xpathRows = xmlXPathEvalExpression((xmlChar *)expr.itemList[col].val, subCtx);

            result->data[(row + 1) * result->nbCols + col] = strdup((char *)xmlXPathCastToString(xpathRows)); 
            xmlXPathFreeObject(xpathRows);
        }
        xmlXPathFreeContext(subCtx);
        subCtx = NULL;
    }

    xmlFreeDoc(doc); 
    xmlXPathFreeContext(xpathCtx);
    xmlXPathFreeObject(xpathNodes);
    return 0;
}

I think that the problem comes from this line

    // Update context to use the nodeset related to this row
subCtx->node = xpathNodes->nodesetval->nodeTab[row];

Because the second xpath expression is applied from the root of the xml file, not the root of each node.

Any idea on how to do such thing?

Upvotes: 2

Views: 3416

Answers (3)

Fantastory
Fantastory

Reputation: 1984

as i see in the xmlXPathContext::node is for internal library use, so we can not use it

Probably xmlXPtrNewContext should help, but i am not able to use it.

I currently do the trick with concatenating both xpaths and quering the whole. The new xpath is: "(" + xpath1 + ")" + "[num]" + xpath2. Where num can be replaced with any number betwen 1 and the size of xpath1 result set. And it seem to work.

Upvotes: 1

Jeremy French
Jeremy French

Reputation: 12177

you could concatinate your xpath expressions.

edit

//FORECAST/DAY/descendant::content/meteo/desc should work

Upvotes: 1

Brian
Brian

Reputation: 25834

Some sample code. Modify to suit your needs and language. This is C#, but it should be largely the same. Notice the second xpath is not starting with a "/" and is using an instance of the node returned from the first one. Neither of the xpaths end in a "/".

XmlDocument doc = new XmlDocument();
doc.Load(docfile);
XmlNodeList items = doc.SelectNodes("/part1/part2");
foreach (item in items)
{
    XMLNode x = item.SelectNodes("part3");
    //Dostuff
}

Upvotes: 0

Related Questions