2008-09-23 7 views
35

ich eine XML-Datei, die wie folgt beginnt:Wie abzurufen Namespaces in XML-Dateien mit Xpath

<Elements name="Entities" xmlns="XS-GenerationToolElements"> 

Ich werde viele dieser Dateien öffnen müssen. Jeder von ihnen hat einen anderen Namespace, hat aber immer nur einen Namespace (ich werde niemals zwei Namespaces finden, die in einer XML-Datei definiert sind).

Mit XPath möchte ich eine automatische Möglichkeit haben, den angegebenen Namespace dem Namespace-Manager hinzuzufügen. Bis jetzt konnte ich den Namespace nur durch das Parsen der XML-Datei bekommen, aber ich habe eine XPathNavigator-Instanz und es sollte eine schöne und saubere Möglichkeit geben, die Namespaces zu bekommen, richtig?

- ODER -

Da ich nur einen Namensraum haben, irgendwie XPath die einzige machen verwenden, die in der XML vorhanden ist, damit vermieden wird, den Code unübersichtlich durch immer den Namensraum angehängt wird.

+0

Sind diese immer im Standard-Namespace? oder haben Sie jemals: xmlns: myns = "namespace-uri" Auch lesen Sie die Dateien in ihrer Gesamtheit in ein DOM-Dokument oder Parsen mit etwas wie der XmlValidatingReader? – Kev

+0

Sie befinden sich immer im Standardnamespace. Ich lese die Datei noch nicht vollständig, da ich in dieser Sache stecken geblieben bin; Ich denke, dass ich nicht vollständig verstehe, wenn Sie "in ein DOM-Dokument fragen oder mit etwas wie dem XmlValidatingReader analysieren"; Ich würde XPath nur verwenden, um das XML zu lesen, ist es schlecht? –

Antwort

76

Es gibt ein paar Techniken, die Sie ausprobieren könnten; Was Sie verwenden, hängt davon ab, welche Informationen Sie benötigen, um aus dem Dokument herauszukommen, wie streng Sie sein möchten und wie konform die von Ihnen verwendete XPath-Implementierung ist.

Eine Möglichkeit zum Abrufen des Namespace-URI, der einem bestimmten Präfix zugeordnet ist, ist die namespace::-Achse. Dadurch erhalten Sie einen Namespace-Knoten, dessen Name das Präfix ist und dessen Wert der Namespace-URI ist. Zum Beispiel könnten Sie den Standard-Namespace-URI auf dem Dokumentelement erhalten den Pfad:

/*/namespace::*[name()=''] 

Sie könnten in der Lage sein, das verwenden, um die Namespace-Zuordnungen für Ihren XPathNavigator einzurichten. Seien Sie jedoch gewarnt, dass die Achse namespace:: eine der Ecken von XPath 1.0 ist, die nicht immer implementiert ist.

Eine zweite Möglichkeit, diesen Namespace-URI zu erhalten, besteht darin, die namespace-uri()-Funktion für das Dokumentelement zu verwenden (von dem Sie gesagt haben, dass es immer in diesem Namespace sein wird). Der Ausdruck:

namespace-uri(/*) 

wird Ihnen diesen Namespace geben.

Eine Alternative wäre, zu vergessen, ein Präfix mit diesem Namespace zu verknüpfen, und nur Ihren Pfad Namespace-frei machen. Sie können dies tun, indem Sie die Funktion local-name() immer dann verwenden, wenn Sie auf ein Element verweisen müssen, dessen Namespace Sie nicht kennen.Zum Beispiel:

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

Sie einen Schritt weiter gehen und den Namespace-URI des Elements gegen die des Dokumentelements testen, wenn Sie wirklich wollte:

//*[local-name() = 'Element' and namespace-uri() = namespace-uri(/*)] 

Eine letzte Option, da Der Namespace scheint Ihnen nichts zu bedeuten, würde Ihren XML-Code durch einen Filter laufen lassen, der die Namespaces ausblendet. Dann müssen Sie sich in Ihrem XPath überhaupt nicht darum kümmern. Am einfachsten wäre es, das Attribut xmlns mit einem regulären Ausdruck zu entfernen, aber Sie könnten etwas Komplexeres tun, wenn Sie gleichzeitig andere Aufräumarbeiten durchführen müssen.

+2

Vielen Dank für Ihre ausführliche Antwort Es scheint, dass ich noch keinen Ruf habe, um Sie zu wählen –

+1

eine beispielhafte Antwort, danke, JeniT – kostja

+0

Die zweite Methode funktioniert gut in Qt mit QXmlQuery. Gute Antwort. –

4

Leider hat XPath kein Konzept von "Standard-Namespace". Sie müssen Namespaces mit Präfixen im XPath-Kontext registrieren und diese Präfixe dann in Ihren XPath-Ausdrücken verwenden. Es bedeutet für einen sehr ausführlichen XPath, aber es ist ein grundlegender Mangel von XPath 1. Anscheinend wird XPath 2 dies angehen, aber das nützt dir jetzt nichts.

Ich schlage vor, dass Sie Ihr XML-Dokument für den Namespace programmatisch untersuchen, diesen Namespace mit einem Präfix im XPath-Kontext verknüpfen und dann das Präfix in den Xpath-Ausdrücken verwenden.

+0

Es scheint, dass es dazu kommen muss ..! Danke –

+0

Ich vermute, dies ist die tatsächliche Antwort, da es der Wunsch zu sein scheint, die zusätzliche Komplexität der Abfrage eines Namespace in XPath zu vermeiden. Vergiss nicht, die passende Antwort zu akzeptieren. – AnthonyWJones

10

Diese 40-line XSLT-Transformation alle nützlichen Informationen über die Namensräume in einem bestimmten XML-Dokument bietet: auf die folgende XML-Dokument

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:ext="http://exslt.org/common" 
    exclude-result-prefixes="ext" 
> 

<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:strip-space elements="*"/> 

<xsl:key name="kNsByNsUri" match="ns" use="@uri"/> 

<xsl:variable name="vXmlNS" 
    select="'http://www.w3.org/XML/1998/namespace'"/> 

<xsl:template match="/"> 
    <xsl:variable name="vrtfNamespaces"> 
    <xsl:for-each select= 
     "//namespace::* 
      [not(. = $vXmlNS) 
      and 
       . = namespace-uri(..) 
      ]"> 
     <ns element="{name(..)}" 
      prefix="{name()}" uri="{.}"/> 
    </xsl:for-each> 
    </xsl:variable> 

    <xsl:variable name="vNamespaces" 
    select="ext:node-set($vrtfNamespaces)/*"/> 

    <namespaces> 
      <xsl:for-each select= 
      "$vNamespaces[generate-id() 
         = 
         generate-id(key('kNsByNsUri',@uri)[1]) 
         ]"> 
      <namespace uri="{@uri}"> 
       <xsl:for-each select="key('kNsByNsUri',@uri)/@element"> 
       <element name="{.}" prefix="{../@prefix}"/> 
       </xsl:for-each> 
      </namespace> 
      </xsl:for-each> 
    </namespaces> 
</xsl:template> 

Bei der Anwendung:

<a xmlns="my:def1" xmlns:n1="my:n1" 
    xmlns:n2="my:n2" xmlns:n3="my:n3"> 
    <b> 
    <n1:d/> 
    </b> 
    <n1:c> 
    <n2:e> 
     <f/> 
    </n2:e> 
    </n1:c> 
    <n2:g/> 
</a> 

das gewünschte Ergebnis wird produziert:

+0

Wie man dies anwendet? –