Использование 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')]

но, к сожалению, это приведет к поиску значения INSIDE только для атрибута. Как искать атрибут сам с помощью шаблона?

Обновление: @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

Похоже, что проблема с пакетом обновления Html Agility Pack больше, чем проблема XPath, я использовал хром для тестирования своих выражений XPath, и все из следующих выполнялось в хроме, но не в 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
                }
            }
        }
    }
}

Принятый ответ

Используйте функции XPath contains() или starts-with() . Вам нужно выражение 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() case 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
Является ли этот КБ законным? Да, узнайте, почему
Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow
Является ли этот КБ законным? Да, узнайте, почему