2012-02-05 16 views
6

Khi tôi sử dụngHtmlAgilityPack XPath trường hợp bỏ qua

SelectSingleNode("//meta[@name='keywords']") 

nó không hoạt động, nhưng khi tôi sử dụng trường hợp tương tự mà được sử dụng trong tài liệu gốc nó hoạt động tốt:

SelectSingleNode("//meta[@name='Keywords']") 

Vì vậy, câu hỏi là làm thế nào tôi có thể đặt trường hợp bỏ qua?

+0

XPath là cố ý trường hợp nhạy cảm? – CarneyCode

+0

@Carnotaurus Có. – Tomalak

Trả lời

4

Nếu bạn cần giải pháp toàn diện hơn, bạn có thể viết chức năng mở rộng cho bộ xử lý XPath sẽ thực hiện so sánh phân biệt chữ hoa chữ thường. Đó là một chút mã, nhưng bạn chỉ viết nó một lần.

Sau khi thực hiện phần mở rộng bạn có thể viết câu hỏi của bạn như sau

"//meta[@name[Extensions:CaseInsensitiveComparison('Keywords')]]" 

đâu Extensions:CaseInsensitiveComparison là chức năng mở rộng thực hiện trong mẫu dưới đây.

LƯU Ý: điều này không được kiểm tra tốt Tôi vừa ném nó cùng nhau để phản hồi này để xử lý lỗi, v.v. không tồn tại!

Sau đây là mã cho bối cảnh XSLT tùy chỉnh mà cung cấp một hoặc mở rộng nhiều chức năng

using System; 
using System.Xml.XPath; 
using System.Xml.Xsl; 
using System.Xml; 
using HtmlAgilityPack; 

public class XsltCustomContext : XsltContext 
{ 
    public const string NamespaceUri = "http://XsltCustomContext"; 

    public XsltCustomContext() 
    { 
    } 

    public XsltCustomContext(NameTable nt) 
    : base(nt) 
    {  
    } 

    public override IXsltContextFunction ResolveFunction(string prefix, string name, XPathResultType[] ArgTypes) 
    { 
    // Check that the function prefix is for the correct namespace 
    if (this.LookupNamespace(prefix) == NamespaceUri) 
    { 
     // Lookup the function and return the appropriate IXsltContextFunction implementation 
     switch (name) 
     { 
     case "CaseInsensitiveComparison": 
      return CaseInsensitiveComparison.Instance; 
     } 
    } 

    return null; 
    } 

    public override IXsltContextVariable ResolveVariable(string prefix, string name) 
    { 
    return null; 
    } 

    public override int CompareDocument(string baseUri, string nextbaseUri) 
    { 
    return 0; 
    } 

    public override bool PreserveWhitespace(XPathNavigator node) 
    { 
    return false; 
    } 

    public override bool Whitespace 
    { 
    get { return true; } 
    } 

    // Class implementing the XSLT Function for Case Insensitive Comparison 
    class CaseInsensitiveComparison : IXsltContextFunction 
    { 
    private static XPathResultType[] _argTypes = new XPathResultType[] { XPathResultType.String }; 
    private static CaseInsensitiveComparison _instance = new CaseInsensitiveComparison(); 

    public static CaseInsensitiveComparison Instance 
    { 
     get { return _instance; } 
    }  

    #region IXsltContextFunction Members 

    public XPathResultType[] ArgTypes 
    { 
     get { return _argTypes; } 
    } 

    public int Maxargs 
    { 
     get { return 1; } 
    } 

    public int Minargs 
    { 
     get { return 1; } 
    } 

    public XPathResultType ReturnType 
    { 
     get { return XPathResultType.Boolean; } 
    } 

    public object Invoke(XsltContext xsltContext, object[] args, XPathNavigator navigator) 
    {     
     // Perform the function of comparing the current element to the string argument 
     // NOTE: You should add some error checking here. 
     string text = args[0] as string; 
     return string.Equals(navigator.Value, text, StringComparison.InvariantCultureIgnoreCase);   
    } 
    #endregion 
    } 
} 

Sau đó bạn có thể sử dụng chức năng mở rộng trên trong các truy vấn XPath của bạn, đây là một ví dụ cho trường hợp của chúng tôi

class Program 
{ 
    static string html = "<html><meta name=\"keywords\" content=\"HTML, CSS, XML\" /></html>"; 

    static void Main(string[] args) 
    { 
    HtmlDocument doc = new HtmlDocument(); 
    doc.LoadHtml(html); 

    XPathNavigator nav = doc.CreateNavigator(); 

    // Create the custom context and add the namespace to the context 
    XsltCustomContext ctx = new XsltCustomContext(new NameTable()); 
    ctx.AddNamespace("Extensions", XsltCustomContext.NamespaceUri); 

    // Build the XPath query using the new function 
    XPathExpression xpath = 
     XPathExpression.Compile("//meta[@name[Extensions:CaseInsensitiveComparison('Keywords')]]"); 

    // Set the context for the XPath expression to the custom context containing the 
    // extensions 
    xpath.SetContext(ctx); 

    var element = nav.SelectSingleNode(xpath); 

    // Now we have the element 
    } 
} 
+0

điều này có thể được áp dụng cho tên nút không? –

8

Nếu giá trị thực tế là trường hợp không xác định, tôi nghĩ bạn phải sử dụng dịch. Tôi tin rằng đó là:

SelectSingleNode("//meta[translate(@name,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='keywords']") 

Đây là hack, nhưng nó là lựa chọn duy nhất trong XPath 1.0 (trừ trường hợp ngược lại).

2

Đây là cách tôi làm điều đó:

HtmlNodeCollection MetaDescription = document.DocumentNode.SelectNodes("//meta[@name='description' or @name='Description' or @name='DESCRIPTION']"); 

string metaDescription = MetaDescription != null ? HttpUtility.HtmlDecode(MetaDescription.FirstOrDefault().Attributes["content"].Value) : string.Empty; 
+0

Cách tiếp cận của bạn không phổ biến như của Chris Taylor. Câu trả lời của Chris chú ý đến sự kết hợp giữa trường hợp của char. – kseen

+1

@ kseen Tôi biết nhưng thực sự, liệu có thể từ một người nào đó để đặt một cái gì đó như "KeYwOrDs"? Đây là ba cách phổ biến, và nếu ai đó viết meta name như thế tôi nghi ngờ bạn sẽ có thể phân tích cú pháp bất kỳ thứ gì từ tài liệu HTML đó. Đây là giải pháp ngoài hộp yêu cầu hai dòng mã và hoạt động tốt cho hầu hết các trường hợp, nhưng tất cả đều phụ thuộc vào yêu cầu của bạn. – formatc

+0

Tôi cố gắng giữ nguyên quy tắc "không bao giờ tin tưởng người dùng nhập" và tôi cũng khuyên bạn thân thiện. – kseen

1

Hoặc sử dụng thứ e mới LINQ cú pháp mà nên hỗ trợ trường hợp phù hợp nhạy cảm:

 node = doc.DocumentNode.Descendants("meta") 
      .Where(meta => meta.Attributes["name"] != null) 
      .Where(meta => string.Equals(meta.Attributes["name"].Value, "keywords", StringComparison.OrdinalIgnoreCase)) 
      .Single(); 

Nhưng bạn phải làm một kiểm tra null xấu xí cho các thuộc tính để ngăn chặn một NullReferenceException ...

Các vấn đề liên quan