Weird XPath behavior in libxml2

Posted by Josh K on Stack Overflow See other posts from Stack Overflow or by Josh K
Published on 2010-03-17T01:51:26Z Indexed on 2010/03/17 19:31 UTC
Read the original article Hit count: 421

Filed under:
|
|
|

I have this XML tree that looks like this (I've changed the tag names but if you're really clever you may figure out what I'm actually doing.)

<ListOfThings>
   <Thing foo:action="add">
      <Bar>doStuff --slowly</Bar>
      <Index>1</Index>
   </Thing>
   <Thing foo:action="add">
      <Bar>ping yourMother.net</Bar>
      <Index>2</Index>
   </Thing>
</ListOfThings>

With libxml2, I want to programmatically insert a new Thing tag into the ListOfThings with the Index being the highest current index, plus one. I do it like this (sanity checking removed for brevity):

xpath = "//urn:myformat[@foo='bar']/"
        "urn:mysection[@name='baz']/"
        "urn:ListOfThings/urn:Thing/urn:Index";

xpathObj = xmlXPathEvalExpression(xpath, xpathCtx);
nodes = xpathObj->nodesetval;

/* Find last value and snarf the value of the tag */
highest = atoi(nodes->nodeTab[nodes->nodeNr - 1]->children->content);
snprintf(order, sizeof(order), "%d", highest + 1); /* highest index plus one */

/* now move up two levels.. */
cmdRoot = nodes->nodeTab[nodes->nodeNr - 1];
ASSERT(cmdRoot->parent && cmdRoot->parent->parent);
cmdRoot = cmdRoot->parent->parent;

/* build the child tag */
newTag = xmlNewNode(NULL, "Thing");
xmlSetProp(newTag, "foo:action", "add");

/* set new node values */
xmlNewTextChild(newTag, NULL, "Bar", command);
xmlNewChild(newTag, NULL, "Index", order);

/* append this to cmdRoot */
xmlAddChild(cmdRoot, newTag);

But if I call this function twice (to add two Things), the XPath expression doesn't catch the new entry I made. Is there a function I need to call to kick XPath in the shins and get it to make sure it really looks over the whole xmlDocPtr again? It clearly does get added to the document, because when I save it, I get the new tags I added.

To be clear, the output looks like this:

<ListOfThings>
   <Thing foo:action="add">
      <Bar>doStuff --slowly</Bar>
      <Index>1</Index>
   </Thing>
   <Thing foo:action="add">
      <Bar>ping yourMother.net</Bar>
      <Index>2</Index>
   </Thing>
   <Thing foo:action="add">
      <Bar>newCommand1</Bar>
      <Index>3</Index>
   </Thing>
   <Thing foo:action="add">
      <Bar>newCommand2</Bar>
      <Index>3</Index> <!-- this is WRONG! -->
   </Thing>
</ListOfThings>

I used a debugger to check what happened after xmlXPathEvalExpression got called and I saw that nodes->nodeNr was the same each time.

Help me, lazyweb, you're my only hope!

© Stack Overflow or respective owner

Related posts about libxml2

Related posts about xpath