Wie kann ich mit XPath in XSLT ein Array von Elementen erhalten, einschließlich fehlender Elemente?

8

Gegeben folgender XML-konformer HTML-Code:

%Vor%

doing //a gibt zurück:

%Vor%

Das Problem mit obigem ist, dass die Daten der dritten Spalte jetzt an zweiter Stelle stehen, wenn A nicht gefunden wird, wird es komplett übersprungen.

Wie können Sie einen xpath ausdrücken, um alle A Elemente zu erhalten, die zurückkommen:

%Vor%

Gleicher Fall für //c , ich frage mich, ob es möglich ist,

zu bekommen %Vor%

UPDATE: Betrachte ein anderes Szenario, in dem keine gemeinsamen Eltern <div> sind.

%Vor%

UPDATE: Ich kann jetzt auch XSLT verwenden.

    
KJW 10.03.2012, 17:55
quelle

3 Antworten

10

In XPath gibt es keinen Nullwert. Es gibt hier eine Frage, die teilweise damit zusammenhängt und die auch erklärt: Ссылка

Realistisch gesehen haben Sie drei Möglichkeiten:

  1. Benutze XPath überhaupt nicht.
  2. Benutze dies: //a | //div[not(a)] , was das div Element zurückgeben würde, wenn a nicht drin wäre, und dein Java Code einen beliebigen div als 'no a Element vorhanden' behandelt. . Je nach Kontext können Sie so möglicherweise sogar etwas Nützlicheres ausgeben, wenn Sie dazu aufgefordert werden, da Sie Zugriff auf den gesamten Inhalt des div haben, z. B. einen Fehler 'no a element in div (some identifier)' gefunden .
  3. Verarbeiten Sie Ihren XML-Code mit einem XSLT, der a -Elemente in ein beliebiges div -Element einfügt, das noch keins mit einem geeigneten Standardwert hat.

Ihr zweiter Fall ist etwas knifflig, und um ehrlich zu sein, würde ich tatsächlich empfehlen, XPath überhaupt nicht dafür zu verwenden, aber es kann gemacht werden:

//a | //h1[not(following-sibling::a) or generate-id(.) != generate-id(following-sibling::a[1]/preceding-sibling::h1[1])]

Dies entspricht allen a -Elementen oder allen h1 -Elementen, bei denen kein nachfolgendes a -Element vor dem nächsten h1 -Element oder dem Ende des Dokuments existiert. Wie Dimitre schon sagte, funktioniert das nur, wenn Sie es innerhalb von XSLT verwenden, da generate-id eine XSLT-Funktion ist.

Wenn Sie es nicht in XLST verwenden, können Sie diese eher künstliche Formel verwenden:

//a | //h1[not(following-sibling::a) or count(. | preceding-sibling::h1) != count(following-sibling::a[1]/preceding-sibling::h1)]

Er funktioniert, indem er h1 elements vergleicht, wobei die Anzahl seiner selbst und alle vorhergehenden h1 -Elemente nicht mit der Anzahl aller h1 -Elemente vor der nächsten a übereinstimmen. Es gibt möglicherweise eine effizientere Methode, dies in XPath zu tun, aber wenn es noch komplizierter wird, würde ich definitiv empfehlen, XPath überhaupt nicht zu verwenden.

    
Flynn1179 16.03.2012, 16:43
quelle
3

Lösung für das erste Problem :

Dieser XPath-Ausdruck:

%Vor%

Bei Auswertung anhand des folgenden XML-Dokuments:

%Vor%

wählt die folgenden drei Knoten aus ( a , div , a ):

%Vor%

In Ihrem Java-Array sollte ein beliebiges ausgewähltes nicht a -Element als null behandelt oder durch dieses ersetzt werden.

Hier ist eine Lösung für das zweite Problem :

Verwenden Sie diese XPath-Ausdrücke zum Auswählen der a -Elemente aus jeder Gruppe :

Für die erste Gruppe:

%Vor%

Für die zweite Gruppe :

%Vor%

Und für die dritte Gruppe :

%Vor%

Falls das:

count(/*/h1 )

ist $cnt ,

generiere $cnt solche Ausdrücke (für i = 1 to $cnt ) und werte alle aus. Die von ihnen ausgewählten Knoten enthalten entweder ein a -Element oder nicht. Wenn die $k -te Gruppe (Knoten, die aus der Auswertung des $ k-ten Ausdrucks ausgewählt wurden) ein a enthält, verwenden Sie ihren String-Wert, um das $k -th-Element des gewünschten Arrays zu generieren - andernfalls null generieren für das $k -th-Element des gewünschten Arrays.

Hier ist eine XSLT-basierte Verifizierung der obigen XPath-Ausdrücke :

%Vor%

Wenn diese Transformation auf das folgende XML-Dokument angewendet wird (es wurde vom OP kein vollständiges und wohlgeformtes XML-Dokument zur Verfügung gestellt !!!):

%Vor%

Die drei XPath-Ausdrücke werden ausgewertet und die jeweils ausgewählten Knoten werden ausgegeben :

%Vor%

Erläuterung :

Wir verwenden die bekannte Kayessian-Formel für die Schnittmenge zweier Knotensätze:

%Vor%

Das Ergebnis der Auswertung dieses Ausdrucks enthält genau die Knoten, die sowohl zum Knotensatz $ns1 als auch zum Knotensatz $ns2 gehören.

Was bleibt, ist es, $ns1 und $ns2 durch Ausdrücke zu ersetzen, die für das Problem relevant sind.

Wir ersetzen $ns1 durch:

%Vor%

und wir ersetzen $ns2 durch:

%Vor%

Mit anderen Worten, die a -Elemente, die zwischen dem ersten und zweiten /*/h1 liegen, sind der Schnittpunkt der a -Elemente, die Geschwister von /*/h1[1] und den a -Elementen folgen, die Geschwister von sind /*/h1[2] .

Dieser Ausdruck ist nur für die Elemente a problematisch, die dem letzten Element /*/h1 folgen. Deshalb fügen wir ein zusätzliches Prädikat hinzu, das die Existenz eines nächsten /*/h1 Elements und or mit den folgenden booleschen Ausdrücken prüft.

Schließlich ist hier als Beispiel für eine Java-Implementierung eine komplette XSLT-Transformation zu nennen, die ähnlich vorgeht - ein serialisiertes Array erzeugt und mechanisch in eine entsprechende Java-Lösung übersetzt werden kann :

%Vor%

Wenn diese Transformation auf dasselbe XML-Dokument angewendet wird (oben), wird das gewünschte, korrekte Ergebnis erzeugt: :

%Vor%

Update2 :

Nun hat das OP hinzugefügt, dass er eine XSLT-Lösung verwenden kann. Hier ist eins:

%Vor%

Diese Transformation implementiert zwei verschiedene Lösungen. Der Unterschied besteht darin, welches Element verwendet wird, um "Null" darzustellen. Im ersten Fall ist es das h1 -Element. Dies wird nicht empfohlen, da h1 bereits eine eigene Bedeutung hat, die sich von "null" unterscheidet. Die zweite Lösung verwendet ein spezielles my:null -Element, um null darzustellen.

Wenn diese Umwandlung auf dasselbe XML-Dokument wie oben angewendet wird:

%Vor%

Jeder der beiden XPath-Ausdrücke (mit XSLT key() Referenzen) wird ausgewertet und die ausgewählten Knoten werden ausgegeben (über bzw. unter "========"):

%Vor%

Hinweis zur Leistung :

Da Schlüssel verwendet werden, ist diese Lösung wesentlich effizienter, wenn mehr als eine Suche durchgeführt wird, beispielsweise wenn die entsprechenden Arrays für a , b und c erstellt werden müssen.

    
Dimitre Novatchev 17.03.2012 05:05
quelle
3

Ich schlage vor, dass Sie Folgendes verwenden, das in eine xsl: -Funktion umgeschrieben werden kann, in der der Name des übergeordneten Knotens (hier: div) parametrisiert ist.

%Vor%

Angewandt auf

%Vor%

Die Ausgabe ist

%Vor%     
Maestro13 19.03.2012 09:39
quelle

Tags und Links