XPATHS и пространства имен по умолчанию

Какова история XPath и поддержки пространств имен? XPath как спецификация предшествовал пространствам имен? Если у меня есть документ, где элементам дано пространство имен по умолчанию:

<foo xmlns="uri" />

Похоже, что некоторые библиотеки процессора XPath не распознают //fooиз-за пространства имен, тогда как другие это сделают. Моя команда подумала о том, чтобы добавить префикс пространства имен с помощью регулярных выражений в XPath (вы можете добавить префикс пространства имен через XmlNameTable), но это кажется хрупким, поскольку XPath является таким гибким языком, когда дело доходит до тестов узлов.

Есть ли стандарт, который применяется к этому?

Мой подход немного хакерский, но, похоже, работает нормально; Я удаляю xmlnsобъявление с поиском / заменой и затем применяю XPath.

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

Это справедливый подход или кто-то решил это по-другому?

14.08.2008 17:09:43
5 ОТВЕТОВ
РЕШЕНИЕ

Я попробовал что-то похожее на то, что предложил Палехорс, и не смог заставить его работать. Так как я получал данные из опубликованного сервиса, я не мог изменить XML. В итоге я использовал XmlDocument и XmlNamespaceManager, вот так:

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
10
24.07.2015 16:54:44
Если вы хотите выбрать использование узлов на нескольких глубинах, вам придется сделать что-то вроде:xml.SelectNodes("kml:kml/kml:Document/kml:Folder", manager)
Drew Noakes 2.09.2010 15:39:20

Вам нужно local-name ():

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

Для кроватки с http://jcooney.net/archive/2005/08/09/6517.aspx :

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

Это выражение будет соответствовать элементу «bar»:

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

Этот не будет:

 //bar
15
4.09.2015 14:18:40
Если у вашего документа есть другой barиз другого пространства имен, то ваше решение выберет оба.
Micha Wiedenmann 7.12.2017 13:16:54
Правильно, но я думаю, что это все же лучше, чем регулярное выражение пространств имен, как это планировал сделать OP.
Stu 8.05.2018 07:35:33

Если вы пытаетесь использовать xslt, вы можете добавить пространство имен в объявление таблицы стилей. Если вы это сделаете, вы должны убедиться, что есть префикс, иначе он не будет работать. Если исходный XML-код не имеет префикса, это нормально, вы добавляете свой собственный префикс в таблицу стилей.

стилей

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

Или что-то вроде того.

0
13.04.2015 14:49:30

Проблема заключается в том, что элемент без пространства имен объявляется находящимся в пространстве имен NULL - поэтому, если // foo сопоставляется с пространством имен, которое вы считаете «по умолчанию», не будет никакого способа сослаться на элемент в пустом пространстве имен.

Также помните, что префикс для пространства имен - это только условное обозначение, реальное имя элемента (Qualified Name или QName для краткости) состоит из полного пространства имен и локального имени. Изменение префикса для пространства имен не меняет «идентичность» элемента - если он находится в том же пространстве имен и с тем же локальным именем, то это тот же тип элемента, даже если префикс отличается.

XPath 2.0 (точнее, XSLT 2.0) имеет концепцию «пространства имен xpath по умолчанию». Вы можете установить атрибут xpath-default-namespace в элементе xsl: stylesheet.

4
19.08.2008 14:38:33

Использование libxml кажется, что это работает:

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);
}
0
1.03.2018 07:07:42