2009-12-31 18 views
5

Ich möchte XPath verwenden, um eine Liste der Namen aller Elemente zu erhalten, die in einer XML-Datei angezeigt werden. Ich möchte jedoch keine Namen wiederholen, daher sollte ein Element mit demselben Namen wie ein vorhergehendes Element nicht übereinstimmen. Bisher ich habe:XPath, um eindeutige Elementnamen zu erhalten

*[not(local-name() = local-name(preceding::*))] 

Diese Ordnung ausgeführt wird, aber es spuckt Duplikate. Warum spuckt es die Duplikate aus und wie kann ich sie eliminieren? (Ich verwende Firefox XPath-Engine.)

+0

Ihr Code Spießen Duplikate, weil die Liste nicht geordnet ist. Es würde auf einer geordneten Liste funktionieren. –

Antwort

5

Sie erhalten Duplikate, weil Ihr Filter nicht die Art und Weise bewertet, wie Sie es für richtig halten.

Die local-name() Funktion gibt den lokalen Namen des ersten Knoten im nodeset.

Der Prädikatfilter funktioniert nur, wenn das Element den gleichen Namen wie das erste vorangehende Element hat.

Ich denke nicht, dass Sie in der Lage sein werden, was Sie mit einem reinen XPATH 1.0 tun wollen. Sie könnten es in XPATH 2.0 tun, aber das würde nicht mit Firefox funktionieren.

In XSLT können Sie die meunchien method verwenden, um zu erreichen, was Sie wollen.

Unten ist ein Beispiel. Sie lieferten keine Probe XML, also hielt ich es sehr allgemein (zB // * für alle Elemente im doc Spiele):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"><xsl:output method="xml"/> 
<xsl:key name="names" match="//*" use="local-name(.)"/> 
<xsl:template match="/"> 
    <xsl:for-each select="//*[generate-id(.) = generate-id(key('names', local-name(.)))]"> 
     <!--Do something with the unique list of elements--> 
    </xsl:for-each> 
</xsl:template> 
</xsl:stylesheet> 
+0

Danke für den Hinweis. Sie haben Recht mit dem local-name(), der den ersten Knoten zurückgibt.Eigentlich wollte ich dies als die akzeptierte Antwort markieren, klickte aber auf das falsche Häkchen. Allerdings habe ich am Ende die Filterung in Javascript durchgeführt, also sind beide Antworten Teil meiner Lösung. Vielen Dank. – mawrya

1

Ich würde empfehlen, zuerst eine Liste aller Elemente zu erhalten und dann durch die Liste zu iterieren und sie einem Wörterbuch hinzuzufügen, um Duplikate zu entdecken.

Zum Beispiel in Pseudocode:

var allElements = doc.select("//node()"); 
var distinctElementTypes = new object(); 
foreach (var elem in allElements) { 
    distinctElementTypes[elem.name] = elem.name; 
} 

Und jetzt distinctElementTypes wird ein Wörterbuch von unterschiedlichen Elementnamen sein.

+0

Danke für die Antwort. Ich könnte diesen Ansatz verwenden, aber Xpath benötigt nur eine Codezeile. Dies ist genau die Art von Problem, für die xpath entwickelt wurde. Ich würde gerne wissen, was mit dem gegebenen Beispiel falsch ist, da ich meine XPath-Ausbildung weiterführen möchte. Soweit ich das beurteilen kann, sollte es funktionieren, aber nicht. – mawrya

+0

Ich bin mir nicht sicher, warum 'vorangehen' nicht funktioniert. Könnte es sein, dass es nur mit den vorhergehenden Geschwisterknoten des fraglichen Knotens vergleicht, im Gegensatz zu * allen * vorhergehenden Knoten? – Eilon

+0

Das wäre die vorhergehende-Geschwister :: Achse. W3C sagt: Die vorhergehende Achse enthält alle Knoten im selben Dokument wie der Kontextknoten, die vor dem Kontextknoten in der Dokumentreihenfolge liegen, ausgenommen alle Vorgänger und exklusive Attributknoten und Namespace-Knoten. So kann ich sehen, warum ich Duplikate bekommen könnte, wenn Elemente mit dem gleichen Namen Vorfahren sind, aber ich bekomme auch Duplikate von Geschwisterelementen! – mawrya

6

Gültig in XPath 2.0:

distinct-values(//*/name()) 
Verwandte Themen