2010-12-09 5 views
1

Ich habe ein XML-Dokument wie folgt:Sortierung XPath Ergebnisse in der gleichen Reihenfolge wie mehrere Parameter auswählen

doc.xpath("//object[@uid=2 or @uid=0 or @uid=1]") 

Aber das gibt die:

<objects> 
    <object uid="0" /> 
    <object uid="1" /> 
    <object uid="2" /> 
</objects> 

ich mehrere Elemente mithilfe der folgenden Abfrage auswählen können Elemente in der gleichen Reihenfolge, in der sie im XML-Dokument deklariert sind (uid = 0, uid = 1, uid = 2) und die Ergebnisse in der gleichen Reihenfolge wie die XPath-Abfrage (uid = 2, uid = 0, uid = 1).

Ich bin nicht sicher, ob das mit XPath allein möglich ist, und habe in XSLT-Sortierung geschaut, aber ich habe kein Beispiel gefunden, das erklärt, wie ich das erreichen konnte.

Ich arbeite in Ruby mit der Nokogiri-Bibliothek.

+0

Gute Frage, +1. Sehen Sie meine Antwort für eine Erklärung und zwei verschiedene Lösungen: eine XPath 2.0 und eine XSLT 1.0 Lösung. –

Antwort

0

Ein XSLT Beispiel:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:param name="pSequence" select="'2 1'"/> 
    <xsl:template match="objects"> 
     <xsl:for-each select="object[contains(concat(' ',$pSequence,' '), 
               concat(' ',@uid,' '))]"> 
      <xsl:sort select="substring-before(concat(' ',$pSequence,' '), 
               concat(' ',@uid,' '))"/> 
      <xsl:copy-of select="."/> 
     </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 

Output:

<object uid="2" /><object uid="1" /> 
1

Ich gehe davon aus, dass Sie XPath 1.0 verwenden. Die W3C Spezifikation sagt: Das primäre syntaktische Konstrukt in XPath ist der Ausdruck. Ein Ausdruck entspricht der Produktion Expr. Ein Ausdruck wird ausgewertet, um ein Objekt zu erhalten, das eine der folgenden vier Grundtypen hat:

* node-set (an unordered collection of nodes without duplicates) 
* boolean (true or false) 
* number (a floating-point number) 
* string (a sequence of UCS characters) 

So kann ich nicht denken, Sie nachbestellen einfach XPath verwenden. (Der Rest der Spezifikation definiert die Dokumentreihenfolge und umgekehrte Dokumentreihenfolge. Wenn Letzterer das tut, was Sie wollen, können Sie es mit der entsprechenden Achse (z. B. vorhergehend) abrufen.

In XSLT können Sie <xsl:sort> mit dem Namen() verwenden Das XSLT FAQ ist sehr gut und Sie sollten eine Antwort dort finden.

0

Ich glaube nicht, dass es eine Möglichkeit gibt, es in Xpath zu tun, aber wenn Sie zu XSLT wechseln möchten, können Sie das XSL: Sort verwenden tag:

<xsl:for-each select="//object[@uid=1 or @uid=2]"> 
    <xsl:sort: select="@uid" data-type="number" /> 
    {insert new logic here} 
</xsl:for-each> 

vollständigere Informationen hier: http://www.w3schools.com/xsl/el_sort.asp

4

Es gibt keine Möglichkeit, in XPath 1.0 die Reihenfolge der ausgewählten Knoten zu spezifizieren.

XPath 2.0 ermöglicht eine sequence von Knoten mit einer bestimmten Reihenfolge:

//object[@uid=2], //object[@uid=1] 

auswertet zu einer Sequenz, in der alle object Elemente mit @uid=2 precede alle object Elemente mit @uid=1

Wenn man doesn‘ Wenn eine anXPath 2.0-Engine verfügbar ist, ist es immer noch möglich, XSLT zu verwenden, um Knoten in beliebiger Reihenfolge auszugeben.

In diesem speziellen Fall die Reihenfolge der folgenden XSLT-Anweisungen:

<xsl:copy-of select="//object[@uid=2]"/> 

<xsl:copy-of select="//object[@uid=1]"/> 

erzeugt den gewünschten Ausgang:

<object uid="2" /><object uid="1" /> 
+0

Danke Dimitre, das habe ich als nützlich markiert. Ich habe mich dafür entschieden, Alejandros Antwort als akzeptiert zu wählen, da es genau das ist, was ich brauche - einschließlich der Möglichkeit, einen Parameter mit den IDs, die ich suche, zu übergeben. –

+0

@Cameron: Sie haben in Ihrer Frage nicht erwähnt, dass Sie eine Parametrisierung wünschen. Wenn die Parametrisierung gewünscht ist, ist das Sortieren natürlich der richtige Weg. Wahrscheinlich habe ich vor einem Monat eine ähnliche Frage mit einer Lösung beantwortet, die Parameter und Sortierung verwendete - das ist überhaupt nichts Neues. :) –

0

Dies ist, wie ich es in Nokogiri tun würde:

require 'nokogiri' 

xml = '<objects><object uid="0" /><object uid="1" /><object uid="2" /></objects>' 

doc = Nokogiri::XML(xml) 
objects_by_uid = doc.search('//object[@uid="2" or @uid="1"]').sort_by { |n| n['uid'].to_i }.reverse 
puts objects_by_uid 

Lauf der Ausgänge:

<object uid="2"/> 
<object uid="1"/> 

Eine Alternative zur Suche wäre:

objects_by_uid = doc.search('//object[@uid="2" or @uid="1"]').sort { |a,b| b['uid'].to_i <=> a['uid'].to_i } 

wenn Sie nicht wie sort_by mit den reverse verwenden.

XPath ist nützlich für das Auffinden und Abrufen der Knoten, aber oft wird die Filterung, die wir machen wollen, im Accessor zu verschachtelt, also lasse ich die Sprache es tun, ob es Ruby, Perl oder Python ist. Wo ich die Filterlogik einsetze, hängt davon ab, wie groß der XML-Datensatz ist und ob es viele verschiedene uid Werte gibt, die ich mir ansehen möchte. Manchmal macht es Sinn, die XPath-Engine schwerfällig zu machen, manchmal ist es einfacher, XPath alle object-Knoten greifen zu lassen und in der aufrufenden Sprache zu filtern.

+0

Danke für die Antwort Greg. Leider brauche ich die Ergebnisse nicht sortiert nach UID, ich muss die genaue Reihenfolge angeben, in der sie zurückgegeben werden. Mein Beispiel für die Verwendung von 1,2 und 2,1 in der Frage könnte verwirrend sein - ich habe seit der Übersichtlichkeit aktualisiert. –

+0

@Cameron Yule, ja es war verwirrend. –

Verwandte Themen