2015-04-22 148 views
1

我得到了HTML我需要解析,並且我使用C#和Html Agility Pack Library來完成節點的選擇。我的HTML看起來像之一:使用XPath通配符選擇屬性

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

或:

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

其中data-translate-attr-****是我需要找到

我可以使用像這樣的屬性的新格局:

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

但不幸的是,那隻會尋找價值INSIDE attri弼。 如何使用通配符查找屬性本身?

更新: @Mathias穆勒

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

這似乎是一個HTML敏捷性包的問題不是一個XPath問題的更多,我用鍍鉻來測試我的XPath表達式並且以下所有工作都適用於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 
       } 
      } 
     } 
    } 
} 

回答

1

使用XPath功能或starts-with()。您需要一個XPath表達式像

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

或許

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

實際上檢索屬性節點。以上,@*是您要查找的屬性通配符。

+0

感謝您的回答,我已經更新的問題,比較什麼,我要你提出什麼。我犯了一些愚蠢的錯誤? – Nnoel

+0

@Nnoel這是不可能的,除了實際輸入文檔中有名稱空間的屬性。否則,'// @ data-translate'返回節點是不可能的,而'// @ * [包含(name(),'data-translate')]'不會。你迄今爲止還沒有提供的重要信息?爲了打破這個問題,你做了什麼簡化? –

+0

標記您的答案是正確的,因爲您的XPath在使用Chrome進行測試時是正確的。 – Nnoel

1

,而不是使用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 
+0

感謝您的回答,我測試了'local-name()',並且它在本例中和'name()'一樣工作。 – Nnoel

+0

@Nnoel在'HtmlAgilityPack'中只有'local-name()'可以工作,'name()'應該以相同的方式工作,但是有一個錯誤。 –

+0

您如何知道這是AgilityPack中的錯誤?任何提及支持這一點? –