2015-04-22 110 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中的错误?任何提及支持这一点? –