Странное поведение XPath в libxml2 - PullRequest
2 голосов
/ 17 марта 2010

У меня есть это дерево XML, которое выглядит следующим образом (я изменил имена тегов, но если вы действительно умны, вы можете понять, что я на самом деле делаю.)

<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>

В libxml2 я хочу программно вставить новый тег Thing в ListOfThings с индексом, являющимся самым высоким текущим индексом, плюс один. Я делаю это так (проверка краткости снята для краткости):

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);

Но если я вызову эту функцию дважды (чтобы добавить две вещи), выражение XPath не уловит новую запись, которую я сделал. Есть ли какая-то функция, которую мне нужно вызвать, чтобы пнуть XPath в голени и получить ее, чтобы убедиться, что она действительно просматривает весь xmlDocPtr снова? Он явно добавляется в документ, потому что когда я его сохраняю, я получаю новые теги, которые я добавил.

Для ясности вывод выглядит так:

<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>

Я использовал отладчик, чтобы проверить, что произошло после вызова xmlXPathEvalExpression, и я увидел, что nodes->nodeNr всегда был одинаковым.

Помоги мне, лентяйка, ты моя единственная надежда!

1 Ответ

2 голосов
/ 18 марта 2010

Исходя из вашего XPath, похоже, что это просто фрагмент документа с пространством имен (при этом используется пространство имен по умолчанию). Могу поспорить, что вы сделали предварительный вызов, чтобы зарегистрировать «urn» в качестве префикса для пространства имен, используя xmlXPathRegisterNs. Когда вы добавляете новые узлы, вы не создаете их в пространствах имен, поэтому XPath правильно выбирает только элементы «Index» из пространства имен.

...