2008-08-14 13 views
16

¿Cuál es la historia detrás de XPath y soporte para espacios de nombres? ¿XPath como especificación precede a los espacios de nombres? Si tengo un documento donde los elementos se les ha dado un espacio de nombres por defecto:XPATHS y espacios de nombres predeterminados

<foo xmlns="uri" /> 

Parece como si alguna de las bibliotecas procesador XPath no reconocerá //foo debido al espacio de nombres, mientras que otros lo harán. La opción que mi equipo ha pensado es agregar un prefijo de espacio de nombres usando expresiones regulares al XPath (puede agregar un prefijo de espacio de nombres a través de XmlNameTable) pero esto parece quebradizo ya que XPath es un lenguaje tan flexible cuando se trata de pruebas de nodos.

¿Hay alguna norma que se aplique a esto?

Mi enfoque es un poco hackish pero parece funcionar bien; Elimino la declaración xmlns con una búsqueda/reemplazo y luego aplico XPath.

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

¿Es eso un enfoque justo o alguien ha resuelto esto de manera diferente?

Respuesta

10

Intenté algo similar a lo que el caballo de batalla propuso y no pude lograr que funcionara. Como obtenía datos de un servicio publicado, no pude cambiar el xml.Terminé usando XmlDocument y XmlNamespaceManager así:

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

Si desea seleccionar el uso de nodos a múltiples profundidades, termina teniendo que hacer algo como: 'xml.SelectNodes (" kml: kml/kml: Documento/kml: Carpeta ", administrador)' –

0

Si está intentando usar xslt puede agregar el espacio de nombres en la declaración de la hoja de estilo. Si lo haces, debes asegurarte de que haya un prefijo o no funcionará. Si el código fuente XML no tiene un prefijo, eso todavía está bien, agregue su propio prefijo en la hoja de estilo.

de estilo

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

O algo por el estilo.

4

El problema es que un elemento sin un espacio de nombres se declara en el espacio de nombres NULL; por lo tanto, si // foo coincide con el espacio de nombres que considera el 'predeterminado' no habría forma de referirse a un elemento el espacio de nombres nulo.

Recuerde también que el prefijo de un espacio de nombres es solo una convención abreviada, el nombre del elemento real (Nombre calificado o QName para abreviar) consiste en el espacio de nombre completo y el nombre local. Cambiar el prefijo de un espacio de nombres no cambia la 'identidad' de un elemento; si está en el mismo espacio de nombre y el mismo nombre local, entonces es el mismo tipo de elemento, incluso si el prefijo es diferente.

XPath 2.0 (o más bien XSLT 2.0) tiene el concepto del "espacio de nombres xpath predeterminado". Puede establecer el atributo xpath-default-namespace en el elemento xsl: stylesheet.

0

Usando libxml parece que esto funciona:

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); 
} 
Cuestiones relacionadas