XPATHS y espacios de nombres predeterminados

¿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 tienen un espacio de nombre predeterminado:

 

Parece que algunas de las bibliotecas de procesadores XPath no reconocerán //foo debido al espacio de nombres, mientras que otras 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 algún estándar que se aplique a esto?

Mi enfoque es un poco hackish pero parece funcionar bien; xmlns statement 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?

Intenté algo similar a lo que el caballo de los pálanos 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 

Necesita nombre-local ():

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

A la cuna de http://jcooney.net/archive/2005/08/09/6517.aspx :

      

Esta expresión coincidirá con el elemento “bar”:

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

Este no:

  //bar 

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 en el espacio de nombres nulo.

Recuerde también que el prefijo para un espacio de nombres es solo una convención abreviada, el nombre real del elemento (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.

Si está intentando usar xslt, puede agregar el espacio de nombres en la statement 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.

Hoja de estilo

      

O algo así.

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