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

이 HTML 민첩성 팩 문제가 XPath 문제보다 더 많은 것으로 보입니다. 크롬을 사용하여 XPath 표현식을 테스트했으며 다음은 Chrome에서 작동하지만 HTML 민첩성 팩에서는 작동하지 않았습니다.

//@*[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() 은 해당 접두어가있는 경우 네 번째 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


Related

아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.