XPathを使用してワイルドカードで属性を選択する

c# html html-agility-pack xpath

質問

解析する必要があるHTMLがあり、ノードの選択にはC#とHtml Agility Pack Libraryを使用しています。私のHTMLはどちらかのように見えます:

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

または:

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

ここでdata-translate-attr-****は私が見つけ出す必要がある新しい属性のパターンです

私はこのようなものを使うことができた:

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

残念ながら、それは属性の中だけの値を検索します。 ワイルドカードを使用して属性自体を検索するにはどうすればよいですか?

最新情報: @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')]");

アップデート2

これは、XPathの問題以上のHtml Agility Packの問題のようです。私はXPath式をテストするためにchromeを使用しましたが、次のすべてはChromeで動作しましたが、Html Agility Packでは動作しませんでした。

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

私のソリューション

私はちょうど昔ながらのやり方でやっていました...

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
                }
            }
        }
    }
}

受け入れられた回答

contains()またはstarts-with()というXPath関数を使用します。次のようなXPath式が必要です

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

多分

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

実際には属性ノードを取得します 。上記の@*は、あなたが探していた属性ワイルドカードです。


人気のある回答

name()を使用するのではなく、次のようなlocal-name()使用します。

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

違いは、 name()がxmlの名前空間などの接頭辞を持つ属性名を与えるべきであり、 local-name()がその接頭辞をインスタンスname()およびlocal-name() htmlと名前空間がないので同じ方法で動作しますが、そうでないと思われますが、おそらくバグです。

テスト:

    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


ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ