Frage

Was ist die Geschichte hinter XPath und der Unterstützung für Namespaces?War XPath als Spezifikation den Namespaces voraus?Wenn ich ein Dokument habe, in dem Elementen ein Standard-Namespace zugewiesen wurde:

<foo xmlns="uri" />

Es scheint, als würden einige der XPath-Prozessorbibliotheken dies nicht erkennen //foo wegen des Namensraums, während andere es tun werden.Die Option, über die mein Team nachgedacht hat, besteht darin, mithilfe regulärer Ausdrücke ein Namespace-Präfix zum XPath hinzuzufügen (Sie können ein Namespace-Präfix über XmlNameTable hinzufügen). Dies erscheint jedoch brüchig, da XPath eine so flexible Sprache ist, wenn es um Knotentests geht.

Gibt es einen Standard, der dafür gilt?

Mein Ansatz ist etwas hackig, aber er scheint gut zu funktionieren.Ich entferne die xmlns Deklaration mit Suchen/Ersetzen und wenden Sie dann XPath an.

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

Ist das ein fairer Ansatz oder hat jemand das anders gelöst?

War es hilfreich?

Lösung

Ich habe etwas Ähnliches wie das von Palehorse vorgeschlagene versucht und konnte es nicht zum Laufen bringen.Da ich Daten von einem veröffentlichten Dienst erhielt, konnte ich die XML-Datei nicht ändern.Am Ende habe ich XmlDocument und XmlNamespaceManager wie folgt verwendet:

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

Andere Tipps

Sie benötigen local-name():

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

Zum Krippenmachen http://jcooney.net/archive/2005/08/09/6517.aspx:

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

Dieser Ausdruck passt zum Element „bar“:

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

Dieser wird nicht:

 //bar

Das Problem besteht darin, dass ein Element ohne Namespace als im NULL-Namespace deklariert wird. Wenn also //foo mit dem Namespace übereinstimmt, den Sie als „Standard“ betrachten, gibt es keine Möglichkeit, auf ein Element im Null-Namespace zu verweisen.

Denken Sie auch daran, dass das Präfix für einen Namespace nur eine Kurzform ist, der eigentliche Elementname (Qualified Name, kurz QName) besteht aus dem vollständigen Namespace und dem lokalen Namen.Das Ändern des Präfixes für einen Namespace ändert nicht die „Identität“ eines Elements – wenn es sich im selben Namespace und mit demselben lokalen Namen befindet, handelt es sich um dieselbe Art von Element, auch wenn das Präfix unterschiedlich ist.

XPath 2.0 (oder besser gesagt XSLT 2.0) verfügt über das Konzept des „Standard-XPath-Namespace“.Sie können das Attribut xpath-default-namespace für das xsl:stylesheet-Element festlegen.

Wenn Sie versuchen, XSLT zu verwenden, können Sie den Namespace zur Stylesheet-Deklaration hinzufügen.Wenn Sie das tun, müssen Sie sicherstellen, dass ein Präfix vorhanden ist, sonst funktioniert es nicht.Wenn das Quell-XML kein Präfix hat, ist das immer noch in Ordnung, Sie fügen im Stylesheet Ihr eigenes Präfix hinzu.

Stylesheet

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

Oder etwas ähnliches.

Mit libxml scheint das zu funktionieren:

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);
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top