Reputation: 1781
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
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
Reputation: 12177
you could concatinate your xpath expressions.
edit
//FORECAST/DAY/descendant::content/meteo/desc should work
Upvotes: 1
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