Вопрос

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

<foo xmlns="uri" />

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

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

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

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

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

Это было полезно?

Решение

Я попробовал что-то похожее на то, что предложил palehorse, и не смог заставить это сработать.Поскольку я получал данные из опубликованного сервиса, я не мог изменить 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

Другие советы

Вам нужно локальное имя():

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

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

Помните также, что префикс для пространства имен является всего лишь сокращенным соглашением, реальное имя элемента (полное имя или сокращенно QName) состоит из полного пространства имен и локального имени.Изменение префикса для пространства имен не изменяет "идентичность" элемента - если он находится в том же пространстве имен и с тем же локальным именем, то это элемент того же типа, даже если префикс отличается.

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

Если вы пытаетесь использовать 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>

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

Используя 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);
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top