Question

Quelle est l’histoire derrière XPath et la prise en charge des espaces de noms ?XPath en tant que spécification a-t-il précédé les espaces de noms ?Si j'ai un document dans lequel les éléments ont reçu un espace de noms par défaut :

<foo xmlns="uri" />

Il semble que certaines bibliothèques de processeurs XPath ne reconnaissent pas //foo à cause de l'espace de noms alors que d'autres le feront.L'option à laquelle mon équipe a pensé est d'ajouter un préfixe d'espace de noms à l'aide d'expressions régulières à XPath (vous pouvez ajouter un préfixe d'espace de noms via XmlNameTable), mais cela semble fragile puisque XPath est un langage très flexible en matière de tests de nœuds.

Existe-t-il une norme qui s'applique à cela ?

Mon approche est un peu hackish mais elle semble bien fonctionner ;J'enlève le xmlns déclaration avec une recherche/remplacement, puis appliquez XPath.

string readyForXpath = Regex.Replace(xmldocument, "xmlns=\".+\"", String.Empty );

Est-ce une approche équitable ou quelqu'un a-t-il résolu le problème différemment ?

Était-ce utile?

La solution

J'ai essayé quelque chose de similaire à ce que Palehorse proposait et je n'ai pas réussi à le faire fonctionner.Étant donné que je recevais des données d'un service publié, je ne pouvais pas modifier le fichier XML.J'ai fini par utiliser XmlDocument et XmlNamespaceManager comme ceci :

XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlWithBogusNamespace);            
XmlNamespaceManager nSpace = new XmlNamespaceManager(doc.NameTable);
nSpace.AddNamespace("myNs", "http://theirUri");

XmlNodeList nodes = doc.SelectNodes("//myNs:NodesIWant",nSpace);
//etc

Autres conseils

Vous avez besoin de local-name() :

http://www.w3.org/TR/xpath#function-local-name

Au berceau à partir de http://jcooney.net/archive/2005/08/09/6517.aspx:

<foo xmlns='urn:foo'>
  <bar>
    <asdf/>
  </bar>            
</foo>

Cette expression correspondra à l'élément « bar » :

  //*[local-name()='bar'] 

Celui-ci ne :

 //bar

Le problème est qu'un élément sans espace de noms est déclaré comme étant dans l'espace de noms NULL - donc si //foo correspond à l'espace de noms que vous considérez comme étant « par défaut », il n'y aurait aucun moyen de faire référence à un élément dans l'espace de noms nul.

N'oubliez pas également que le préfixe d'un espace de noms n'est qu'une convention abrégée, le véritable nom de l'élément (Qualified Name, ou QName en abrégé) se compose de l'espace de noms complet et du nom local.Changer le préfixe d'un espace de noms ne change pas "l'identité" d'un élément - s'il se trouve dans le même espace de noms et le même nom local, alors c'est le même type d'élément, même si le préfixe est différent.

XPath 2.0 (ou plutôt XSLT 2.0) a le concept « d'espace de noms XPath par défaut ».Vous pouvez définir l'attribut xpath-default-namespace sur l'élément xsl:stylesheet.

Si vous essayez d'utiliser xslt, vous pouvez ajouter l'espace de noms à la déclaration de feuille de style.Si vous faites cela, vous devez vous assurer qu'il y a un préfixe, sinon cela ne fonctionnera pas.Si le XML source n'a pas de préfixe, ce n'est pas grave, vous ajoutez votre propre préfixe dans la feuille de style.

Feuille de style

<xsl:stylesheet
    xmlns:fb="uri"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:template match="fb:foo/bar">
        <!--  do stuff here -->
    </xsl:template>
</xsl:stylsheet>

Ou quelque chose comme ça.

En utilisant libxml, cela semble fonctionner :

http://xmlsoft.org/examples/xpath1.c

 int 
register_namespaces(xmlXPathContextPtr xpathCtx, const xmlChar* nsList) {
    xmlChar* nsListDup;
    xmlChar* prefix;
    xmlChar* href;
    xmlChar* next;

    assert(xpathCtx);
    assert(nsList);

    nsListDup = xmlStrdup(nsList);
    if(nsListDup == NULL) {
    fprintf(stderr, "Error: unable to strdup namespaces list\n");
    return(-1); 
    }

    next = nsListDup; 
    while(next != NULL) {
    /* skip spaces */
    while((*next) == ' ') next++;
    if((*next) == '\0') break;

    /* find prefix */
    prefix = next;
    next = (xmlChar*)xmlStrchr(next, '=');
    if(next == NULL) {
        fprintf(stderr,"Error: invalid namespaces list format\n");
        xmlFree(nsListDup);
        return(-1); 
    }
    *(next++) = '\0';   

    /* find href */
    href = next;
    next = (xmlChar*)xmlStrchr(next, ' ');
    if(next != NULL) {
        *(next++) = '\0';   
    }

    /* do register namespace */
    if(xmlXPathRegisterNs(xpathCtx, prefix, href) != 0) {
        fprintf(stderr,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", prefix, href);
        xmlFree(nsListDup);
        return(-1); 
    }
    }

    xmlFree(nsListDup);
    return(0);
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top