2012-03-29 12 views
2

Ich habe ein HTML/XML-Dokument ähnlich dem folgenden. Es kann ein oder mehrere "tr" der gleichen Farbe geben, bevor in einem willkürlich wiederholenden Muster zu der anderen Farbe gewechselt wird. Dies ist ein Beispiel:XPath Auswählen der Knoten bis zur Bedingung

<tr class='red'></tr> 
<tr class='blue'></tr> 
<tr class='red'></tr> 
<tr class='red'></tr> 
<tr class='red'></tr> 
<tr class='blue'></tr> 
<tr class='blue'></tr> 
<tr class='red'></tr> 
<tr class='red'></tr> 
<tr class='blue'></tr> 

Was ich suche ist ein XPath (1.0) Ausdruck, der von der ersten ‚tr‘ beginnend in jeder Farbe ‚Block‘ (beachten Sie, dass es kein Markup diese Angabe Blöcke, nur Änderungen in der Farbe), wählt die folgenden nachfolgenden 'tr' nur innerhalb dieses Blocks aus.

Ich habe den folgenden Ausdruck versucht

./following-sibling::tr[@class=preceding-sibling::tr[1]/@class] 

aber wählt auch die zweite + ‚tr die von nachfolgenden Blöcken. Ich habe das Gefühl, dass ich nah an dem bin, was ich brauche, aber ich komme damit nicht zurecht.

Vielen Dank im Voraus.

Edit: Die gewünschte Ausgabe ist ein Knotensatz, der die nachfolgenden 'tr's innerhalb des Blocks enthält (und nur diesen Block).

+0

Ich bin ein bisschen verwirrt ... Können Sie die gewünschte Ausgabe auch posten? –

+0

Zum Beispiel, wenn mein Startpunkt der 3. "tr" (rot) wäre, würde ich nur die 4. und 5. tr auswählen. – user1300244

Antwort

1

Dieser XPath 1.0 Expression des ersten "Block" des blauen tr Elemente wählt:

 (/*/tr[@class='blue'][1] | /*/tr[@class='blue'][1]/following-sibling::tr) 
     [count(. | /*/tr[@class='blue'][1] 
          /following-sibling::tr 
            [not(@class='blue')][1] 
             /preceding-sibling::* 
       ) 
     = 
     count(/*/tr[@class='blue'][1] 
          /following-sibling::tr 
            [not(@class='blue')][1] 
             /preceding-sibling::* 
     ) 
     ] 

Erläuterung:

den bekannten Kayessian unter Verwendung der Formel für die Knotenmenge Schnitt:

$ns1[count(.|$ns2) = count($ns2)] 

Dieser XPath-Ausdruck wählt genau die Knoten aus, die zu den Knoten $ns1und der Knotengruppe $ns2 gehören.

In diesem speziellen Fall wir $ns1 und $ns2 mit ihren entsprechenden spezifischen XPath-Ausdrücke einfach ersetzen - man ist der erste blaue tr und alle seine folgenden Geschwister, die andere ist die erste nicht-blau tr nach dem ersten blauen tr und alle seine vorhergehenden Geschwister. Der Schnittpunkt dieser beiden Knoten-Sets ist genau der gewünschte erste Block von Blau tr s.

XSLT - basierte Verifikation:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:template match="node()|@*"> 
    <xsl:copy-of select= 
    "(/*/tr[@class='blue'][1] | /*/tr[@class='blue'][1]/following-sibling::tr) 
      [count(. | /*/tr[@class='blue'][1] 
           /following-sibling::tr 
             [not(@class='blue')][1] 
              /preceding-sibling::* 
        ) 
      = 
      count(/*/tr[@class='blue'][1] 
           /following-sibling::tr 
             [not(@class='blue')][1] 
              /preceding-sibling::* 
       ) 
      ] 
    "/> 
</xsl:template> 
</xsl:stylesheet> 

wenn diese Transformation auf das folgende XML-Dokument angewendet wird:

<t> 
    <tr class='red'></tr> 
    <tr class='red'></tr> 
    <tr class='red'></tr> 
    <tr class='red'></tr> 
    <tr class='blue'></tr> 
    <tr class='blue'></tr> 
    <tr class='red'></tr> 
    <tr class='red'></tr> 
    <tr class='blue'></tr> 
</t> 

der XPath-Ausdruck ausgewertet wird und die ausgewählten Knoten kopiert werden zum Ausgang:

<tr class="blue"/> 
<tr class="blue"/> 
+0

Danke für die Antwort. Ich suche jedoch nach einem allgemeinen XPath, um irgendeinen Block mit seinem ersten als Startpunkt auszuwählen. Ich verstehe das Set-Schnittpunkt-Konzept und ich versuche, den Ausdruck selbst umzuschreiben, aber ich kann es nicht zum Laufen bringen. Wenn Sie Zeit haben, würde ich eine allgemeine Lösung schätzen :) – user1300244

+0

@ user1300244: Diese Antwort löst vollständig das Problem, das derzeit in der Frage beschrieben wird. Wenn Sie andere Anforderungen haben, bearbeiten Sie die Frage und geben Sie genau die Knoten an, die der XPath auswählen soll. –

+0

Sorry, ich stimme nicht zu. Die Frage lautet: "Was ich suche, ist ein XPath (1.0) -Ausdruck, der beginnend mit dem ersten 'tr' in ** einem beliebigen 'Farbblock' die folgenden nachfolgenden 'tr' nur innerhalb dieses Blocks auswählt." – user1300244

0

Wenn Sie eine Variable v $ an den Startknoten gebunden dann denke ich, es (mit horrender Ineffizienz), wie dies getan werden kann:

$v/following-sibling::tr[@class = $v/@class and count(preceding-sibling::tr[not(@class=$v/@class)] = count($v/preceding-sibling::tr[not(@class=$v/@class)])] 

Wenn Ihr API gibt Ihnen nicht die Gelegenheit, zu binden eine Variable, dann glaube ich nicht, dass es getan werden kann, obwohl ich bereit bin, mich als falsch zu erweisen.

Sie haben nicht gesagt, was Ihre Einschränkungen sind, aber XPath 1.0 scheint keine gute Wahl der Technologie für dieses spezielle Problem.

Auch in XPath 2.0 ist es nicht besonders nett. Sie brauchen wirklich Rekursion, und das bedeutet, dass Sie XQuery oder XSLT anstelle von reinem XPath verwenden.

+0

Leider kann ich keine Variable binden. Die Einschränkungen sind, dass ich nur XPath 1.0 verwenden kann, aber Ineffizienz ist kein Problem aufgrund kleiner Datensätze. Danke für die Zeit zu beantworten :) – user1300244

Verwandte Themen