Comment trouver la correspondance la plus proche du nœud de contexte actuel

c# html-agility-pack xpath

Question

J'ai un fichier XML assez volumineux que j'essaie d'analyser à l'aide d'une application C # et de HtmlAgilityPack. Le XML ressemble à ceci:

...
<tr>
<td><b>ABC-123</b></td>
<td>15</td>
<td>4</td>
</tr>
<tr>
<td>AB-4-320</td>
<td>11</td>
<td>2</td>
</tr>
<tr>
<td><b>ABC-123</b></td>
<td>15</td>
<td>4</td>
</tr>
<tr>
<td>AB-4-320</td>
<td>11</td>
<td>2</td>
</tr>
<tr>
<td>CONTROLLER1</td>
<td>4</td>
<td>3</td>
</tr>
<td>CONTROLLER2</td>
<td>4</td>
<td>3</td>
</tr>
...

Fondamentalement, une série de lignes et de colonnes de tableau qui se répète. Je commence par rechercher un contrôleur en utilisant:

...
<tr>
<td><b>ABC-123</b></td>
<td>15</td>
<td>4</td>
</tr>
<tr>
<td>AB-4-320</td>
<td>11</td>
<td>2</td>
</tr>
<tr>
<td><b>ABC-123</b></td>
<td>15</td>
<td>4</td>
</tr>
<tr>
<td>AB-4-320</td>
<td>11</td>
<td>2</td>
</tr>
<tr>
<td>CONTROLLER1</td>
<td>4</td>
<td>3</td>
</tr>
<td>CONTROLLER2</td>
<td>4</td>
<td>3</td>
</tr>
...

Ce qui retourne le bon noeud. Maintenant, je veux chercher en arrière (haut) le premier noeud (le plus proche) correspondant <td> qui commence par le texte "ABC":

...
<tr>
<td><b>ABC-123</b></td>
<td>15</td>
<td>4</td>
</tr>
<tr>
<td>AB-4-320</td>
<td>11</td>
<td>2</td>
</tr>
<tr>
<td><b>ABC-123</b></td>
<td>15</td>
<td>4</td>
</tr>
<tr>
<td>AB-4-320</td>
<td>11</td>
<td>2</td>
</tr>
<tr>
<td>CONTROLLER1</td>
<td>4</td>
<td>3</td>
</tr>
<td>CONTROLLER2</td>
<td>4</td>
<td>3</td>
</tr>
...

Cela renvoie tous les nœuds correspondants, pas seulement le nœud le plus proche. Lorsque j'ai essayé d'ajouter [1] à la fin de cette chaîne XPath, cela ne semblait pas fonctionner et je n'ai trouvé aucun exemple montrant qu'un prédicat était utilisé avec une fonction d'axes comme celle-ci. Ou, plus probablement, je le fais mal. Aucune suggestion?

Réponse acceptée

Vous pouvez utiliser ce XPath:

/parent::tr/preceding-sibling::tr[td[starts-with(.,'ABC-')]][1]/td[starts-with(.,'ABC-')]

Cela recherchera le <tr> précédent ayant l'enfant <td> plus proche commençant par 'ABC-'. Ensuite, obtenez cet élément <td> particulier.

Il existe au moins deux approches possibles lorsque vous utilisez HtmlAgilityPack:

/parent::tr/preceding-sibling::tr[td[starts-with(.,'ABC-')]][1]/td[starts-with(.,'ABC-')]

Réponse populaire

Si vous pouvez utiliser LINQ-to-XML au lieu du protocole HAP, cela fonctionne:

var node = xml.Root.Elements("tr")
    .TakeWhile(tr => !tr.Elements("td")
        .Any(td => td.Value.StartsWith("CONTROLLER2")))
    .SelectMany(tr => tr.Elements("td"))
    .Where(td => td.Value.StartsWith("ABC-"))
    .Last();

J'ai eu ce résultat:

var node = xml.Root.Elements("tr")
    .TakeWhile(tr => !tr.Elements("td")
        .Any(td => td.Value.StartsWith("CONTROLLER2")))
    .SelectMany(tr => tr.Elements("td"))
    .Where(td => td.Value.StartsWith("ABC-"))
    .Last();

(Ce que j'ai vérifié était le deuxième noeud correspondant dans votre échantillon, pas le premier.)




Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi