2010-03-17 7 views
2

J'ai cet arbre XML qui ressemble à ceci (je l'ai changé le nom de tag, mais si vous êtes vous vraiment intelligent peut comprendre ce que je suis en train de faire.)Comportement étrange de XPath dans libxml2

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

Avec libxml2, je souhaite insérer par programme un nouveau tag Thing dans ListOfThings avec l'index étant l'index actuel le plus élevé, plus un. Je fais comme ça (bon sens vérification supprimé par souci de concision):

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

Mais si j'appelle cette fonction deux fois (à ajouter deux choses), l'expression XPath ne saisit pas la nouvelle entrée que je fait. Y a-t-il une fonction que j'ai besoin d'appeler pour kick XPath dans les shins et l'obtenir pour s'assurer qu'il regarde à nouveau sur l'ensemble du xmlDocPtr? Il est clairement ajouté au document, car lorsque je l'enregistre, j'obtiens les nouvelles balises que j'ai ajoutées.

Pour être clair, la sortie ressemble à ceci:

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

J'ai utilisé un débogueur pour vérifier ce qui est arrivé après xmlXPathEvalExpression été appelé et je vis que nodes->nodeNr était le même à chaque fois. Aidez-moi, lazyweb, vous êtes mon seul espoir!

Répondre

2

Selon votre XPath, il semble que ce soit juste un extrait d'un document avec espace de noms (en utilisant l'espace de noms par défaut). Je parie que vous avez fait un appel préalable pour enregistrer "urn" comme préfixe pour un espace de noms utilisant xmlXPathRegisterNs. Lorsque vous ajoutez les nouveaux nœuds, vous ne les créez pas dans des espaces de noms, XPath sélectionne donc correctement les éléments "Index" avec un espace de nommage.

+0

Merci, c'était ça. C'était déroutant, parce que les éléments non-nommés ont semblé les mêmes dans la sortie finale, en dépit d'agir sémantiquement différents. (Si libxml2 avait relu ce fichier, il aurait assigné l'espace de noms correct à ces nouveaux éléments.) –