Utilizzo di XPath per selezionare attributi con caratteri jolly

c# html html-agility-pack xpath

Domanda

Ho ottenuto l'HTML che ho bisogno di analizzare, e sto usando C # e Html Agility Pack Library per fare la selezione dei nodi. Il mio html sarà simile a uno dei due:

<input data-translate-atrr-placeholder="FORGOT_PASSWORD.FORM.EMAIL">

o :

<h1 data-translate="FORGOT_PASSWORD.FORM.EMAIL"></h1>

dove data-translate-attr-**** è il nuovo modello di attributi che ho bisogno di trovare

Potrei usare qualcosa del genere:

//[contains(@??,'data-translate-attr')]

ma sfortunatamente, cercherà solo il valore INSIDE di un attributo. Come posso cercare l'attributo stesso, con un carattere jolly?

Aggiornamento: @ Mathias Muller

HtmlAgilityPack.HtmlDocument htmlDoc    
// this is the old code (returns nodes)
var nodes = htmlDoc.DocumentNode.SelectNodes("//@data-translate");  
// these suggestions return no nodes using the same data
var nodes = htmlDoc.DocumentNode.SelectNodes("//@*[contains(name(),'data-translate')]");  
var nodes = htmlDoc.DocumentNode.SelectNodes("//@*[starts-with(name(),'data-translate')]");

Aggiornamento 2

Questo sembra essere un problema di Html Agility Pack più che un problema XPath, ho usato chrome per testare le mie espressioni XPath e tutte le seguenti operazioni hanno funzionato in chrome ma non in Html Agility Pack:

//@*[contains(local-name(),'data-translate')]
//@*[starts-with(name(),'data-translate')]
//attribute::*[starts-with(local-name(.),'data-translate')]

La mia soluzione

Ho finito per fare le cose alla vecchia maniera ...

var nodes = htmlDoc.DocumentNode.SelectNodes("//@*");

if (nodes != null) {
    foreach (HtmlNode node in nodes) {
        if (node.HasAttributes) {
            foreach (HtmlAttribute attr in node.Attributes) {
                if (attr.Name.StartsWith("data-translate")) {
                    // code in here to handle translation node
                }
            }
        }
    }
}

Risposta accettata

Usa le funzioni XPath contains() o starts-with() . Hai bisogno di un'espressione XPath come

//@*[contains(name(),'data-translate')]

o forse

//@*[starts-with(name(),'data-translate')]

che in realtà recupera i nodi degli attributi . Sopra, @* è l'attributo jolly che stavi cercando.


Risposta popolare

piuttosto che usare name() , usa local-name() come:

var nodes = htmlDoc.DocumentNode.SelectNodes("//@*[starts-with(local-name(),'data-translate')]");

la differenza è che name() dovrebbe darti il ​​nome dell'attributo con un prefisso come un namespace in xml, e local-name() emetterà quel prefisso se è lì, nel tuo caso name() e local-name() dovrebbero funziona allo stesso modo perché il suo html e non ci sono spazi dei nomi, ma sembra che non lo facciano e probabilmente è un bug.

Test:

    var html = "<h3 x='foo'></h3>";
    var doc = new HtmlAgilityPack.HtmlDocument();
    doc.LoadHtml(html);
    var ElementByName = doc.DocumentNode.SelectSingleNode("//*[name()='h3']");                //Works
    var ElementByLocalName = doc.DocumentNode.SelectSingleNode("//*[local-name()='h3']");     //Works
    var ElementByAttributeLocalName = doc.DocumentNode.SelectSingleNode("//*[@*[local-name()='x']]"); //Works
    var ElementByAttributeName = doc.DocumentNode.SelectSingleNode("//*[@*[name()='x']]");  //Does NOT

    //Mathias Way
    var ElementByAttributeLocalName_ = doc.DocumentNode.SelectSingleNode("//@*[local-name() = 'x']"); //Works
    var ElementByAttributeName_ = doc.DocumentNode.SelectSingleNode("//@*[name() = 'x']");  //Does NOT


Related

Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché