2012-12-07 2 views
51

저는 html 민첩성 팩에서 찌르다가이 문제를 해결하는 데 올바른 방법을 찾는 데 어려움을 겪고 있습니다. 예를 들어Html 민첩성 팩은 클래스별로 모든 요소를 ​​가져옵니다.

:

var findclasses = _doc.DocumentNode.Descendants("div").Where(d => d.Attributes.Contains("class")); 

그러나, 분명히 된 div 그래서 난이 시도 당신은 ... 많은에

var allLinksWithDivAndClass = _doc.DocumentNode.SelectNodes("//*[@class=\"float\"]"); 

더 많은 클래스를 추가 할 수 있습니다하지만 그 사건을 처리하지 않습니다 어디 여러 클래스를 추가하면 "float"은 다음 중 하나와 같습니다.

class="className float anotherclassName" 

이 모든 것을 처리 할 수있는 방법이 있습니까? 기본적으로 클래스가있는 모든 노드를 선택하고 float가 포함됩니다.

대답은에 대한 자세한 설명과 함께 내 블로그에 문서화되어있다 ** :

var findclasses = _doc.DocumentNode 
    .Descendants("div") 
    .Where(d => 
     d.Attributes.Contains("class") 
     && 
     d.Attributes["class"].Value.Contains("float") 
    ); 

내가 확장 방법 HasClass을 만드는 것이 좋습니다 수 있으며 사용 : Html Agility Pack Get All Elements by Class

답변

79

는 그냥 조건에 더 많은 절을 추가 like :

IEnumerable<HtmlNode> hasFloatClass = _doc.DocumentNode 
    .Descendants("div") 
    .Where(div => div.HasClass("float")); 

public static Boolean HasClass(this HtmlNode element, String className) 
{ 
    if(element == null) throw new ArgumentNullException(nameof(element)); 
    if(String.IsNullOrWhitespace(className)) throw new ArgumentNullException(nameof(className)); 
    if(element.NodeType != HtmlNodeType.Element) return false; 

    HtmlAttribute classAttrib = element.Attributes["class"]; 
    if(classAttrib == null) return false; 

    Boolean hasClass = CheapClassListContains(classAttrib.Value, className, StringComparison.Ordinal); 
    return hasClass; 
} 

/// <summary>Performs optionally-whitespace-padded string search without new string allocations.</summary> 
/// <remarks>A regex might also work, but constructing a new regex every time this method is called would be expensive.</remarks> 
private static Boolean CheapClassListContains(String haystack, String needle, StringComparison comparison) 
{ 
    if(String.Equals(haystack, needle, comparison)) return true; 
    Int32 idx = 0; 
    while(idx + needle.Length <= haystack.Length) 
    { 
     idx = haystack.IndexOf(needle, idx, comparison); 
     if(idx == -1) return false; 

     Int32 end = idx + needle.Length; 

     // Needle must be enclosed in whitespace or be at the start/end of string 
     Boolean validStart = idx == 0    || Char.IsWhiteSpace(haystack[idx - 1]); 
     Boolean validEnd = end == haystack.Length || Char.IsWhiteSpace(haystack[end]); 
     if(validStart && validEnd) return true; 

     idx++; 
    } 
    return false; 
} 

HtmlAgilityPack은 DOM 인터페이스 (예 :)의 구현을 제공하기위한 것입니다., getElementById 등)하지만 지금은 조금 뒤쳐져 있으며 classList과 같은 새 DOM 기능이 없기 때문에이 작업을 간단하게 할 수 있습니다.

... 새 변경 사항이 포함 된 패치 요청을 제출할 수는 있지만 HtmlAgilityPack에는 공식 GitHub 레포가 없습니다.

+0

늘이 원인은 찾을 수 div를? 그 클래스를 Adam

+1

그런 다음 "div"술어를 제거하십시오. – Dai

+0

.Descendants ("")로 할 수 있습니까? – Adam

68

당신은 아래의이 XPath 쿼리 내에서 기능을 '포함'을 사용하여 문제를 해결할 수 있습니다

var allElementsWithClassFloat = 
    _doc.DocumentNode.SelectNodes("//*[contains(@class,'float')]") 

함수에서이 문제를 다시 다음과 유사한하려면 :

string classToFind = "float";  
var allElementsWithClassFloat = 
    _doc.DocumentNode.SelectNodes(string.Format("//*[contains(@class,'{0}')]", classToFind)); 
+0

'allElementsWithClassFloat' 객체 유형은 무엇입니까? –

+0

'allElementsWithClassFloat'은 HtmlNodeCollection – feztheforeigner

+0

입니다. string.Format 대신'$ "// * [contains (@class, '{classToFind}']" " – feztheforeigner

-7

다음 스크립트를 사용할 수 있습니다.

var findclasses = _doc.DocumentNode.Descendants("div").Where(d => 
    d.Attributes.Contains("class") && d.Attributes["class"].Value.Contains("float") 
); 
2

내 프로젝트에서이 확장 메소드를 많이 사용했습니다. 그것이 당신들 중 하나를 도울 수 있기를 바랍니다.

public static bool HasClass(this HtmlNode node, params string[] classValueArray) 
    { 
     var classValue = node.GetAttributeValue("class", ""); 
     var classValues = classValue.Split(' '); 
     return classValueArray.All(c => classValues.Contains(c)); 
    } 
+1

정말로 원하는 것이 'IgnoreCase 비교'일 때'ToLower()'를 사용하지 마십시오. 'StringComparison.CultureIgnoreCase'를 전달하면보다 명확하고 명확한 의도를 보여줍니다. –

+0

네 말이 맞아. 우리는 확실히 그것을 사용할 수 있습니다. –

0
public static List<HtmlNode> GetTagsWithClass(string html,List<string> @class) 
    { 
     // LoadHtml(html);   
     var result = htmlDocument.DocumentNode.Descendants() 
      .Where(x =>x.Attributes.Contains("class") && @class.Contains(x.Attributes["class"].Value)).ToList();   
     return result; 
    }  
관련 문제