Ich muss Informationen von einer Produktseite sammeln, die keine Klasse oder ID hat. Ich verwende htmlagilitypack und c # 4.0.
Der Quellcode dieser Produktseite enthält viele Tabellen. Die Preistabelle enthält den String "KDV". Also möchte ich diese "KDV" -String-Tabelle erhalten. Wie kann ich das machen ?
Der darunter liegende x-Pfad würde beispielsweise alle Tabellen auswählen
string srxPathOfCategory = "//table";
var selectedNodes = myDoc.DocumentNode.SelectNodes(srxPathOfCategory);
Der folgende Code wählt die Tabelle aus, aber beginnend mit der äußersten Tabelle. Ich muss die innerste Tabelle auswählen, die die angegebene Zeichenfolge enthält
//table[contains(., ' KDV')]
c #, xpath, htmlagilitypack
Der folgende Code wählt die Tabelle aus, aber beginnend mit der äußersten Tabelle. Ich muss die innerste Tabelle auswählen, die die angegebene Zeichenfolge enthält
Verwenden :
//table
[not(descendant::table)
and
.//text()[contains(., ' KDV')]
]
Dadurch wird jede table
im XML-Dokument ausgewählt, die keine nachgeordnete table
enthält und über einen Nachkommen mit " KDV"
verfügt, der die Zeichenfolge " KDV"
.
Im Allgemeinen könnte der obige Ausdruck viele solcher table
auswählen.
Wenn Sie nur eine von ihnen auswählen möchten (sagen wir die erste), verwenden Sie diesen XPath-Ausdruck - beachten Sie die Klammern :
(//table
[not(descendant::table)
and
.//text()[contains(., ' KDV')]
]
)[1]
Denken Sie daran: Wenn Sie das erste auswählen mögen someName
Element in dem Dokument, das (wie in der aktuellen Antwort akzeptiert) ist falsch:
//someName[1]
Dies ist die zweithäufigste FAQ in XPath (nach der Auswahl von Elementen mit Namen ohne Präfix in einem XML-Dokument mit einem Standardnamespace).
Der obige Ausdruck wählt tatsächlich ein beliebiges someName
Element im Dokument aus, das ist das erste Kind des Elternteils - probiere es aus.
Der Grund für dieses nicht intuitive Verhalten liegt darin, dass der Operator XPath []
eine höhere Priorität (Priorität) als der //
Pseudooperator hat.
Der richtige Ausdruck, der wirklich nur das erste someName
Element (in einem beliebigen XML-Dokument) auswählt, sofern vorhanden, ist:
(//someName)[1]
Hier werden die Klammern verwendet, um die Standardpräferenz für XPath-Operatoren explizit zu überschreiben.
Es könnte einen effizienteren Weg geben, dies zu tun. Wie auch immer, dies ist der gesamte Code, den ich für Ihren Fall verwendet habe und er funktioniert für mich:
HtmlDocument doc = new HtmlDocument();
string url = "http://www.pratikev.com/fractalv33/pratikEv/pages/viewProduct.jsp?pInstanceId=3138821";
using (var response = (WebRequest.Create(url).GetResponse()))
{
doc.LoadHtml(new StreamReader(response.GetResponseStream()).ReadToEnd());
}
/*There is an bug in the xpath used here. Should have been
(//table/tr/td/font[contains(.,'KDV')])[1]/ancestor::table[2]
See Dimitre's answer for an explanation and an alternative /
more generic / (needless to say) better approach */
string xpath = "//table/tr/td/font[contains(.,'KDV')][1]/ancestor::table[2]";
HtmlNode table = doc.DocumentNode.SelectSingleNode(xpath);