XPATHS и пространства имен по умолчанию - PullRequest
16 голосов
/ 14 августа 2008

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

<foo xmlns="uri" />

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

Существует ли какой-либо стандарт, применимый к этому?

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

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

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

Ответы [ 5 ]

15 голосов
/ 14 августа 2008

Вам нужно 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
10 голосов
/ 29 сентября 2008

Я попробовал нечто похожее на то, что предложил 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
4 голосов
/ 19 августа 2008

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

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

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

0 голосов
/ 01 марта 2018

При использовании 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 голосов
/ 14 августа 2008

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...