2012-02-05 13 views
6

を無視します大文字小文字を無視するように設定するはHtmlAgilityPack XPathの場合は、私はそれが動作しませんが、私は元の文書で使用したのと同じケースを使用する場合、それは良い作品</p> <pre><code>SelectSingleNode("//meta[@name='keywords']") </code></pre> <p>を使用する場合

+0

XPathを防止するために、属性の醜いヌルチェックを行うにはされていが、大文字と小文字を区別:大文字小文字を区別しないマッチングを支援すべきである電子の新しいLINQの構文? – CarneyCode

+0

@Carnotaurusはい。 – Tomalak

答えて

4

より包括的な解決策が必要な場合は、大文字と小文字を区別しない比較を実行するXPathプロセッサの拡張機能を記述できます。これはかなりのコードですが、一度だけ書くことはできます。 Extensions:CaseInsensitiveComparisonは、以下のサンプルで実装の拡張機能である

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

を次のように

拡張を実装した後、あなたのクエリを書くことができます。

注:これはうまくテストされていません。エラー処理などが存在しないように、この応答用にまとめました!

次は、1つのまたは複数の拡張機能を提供するカスタムXSLTコンテキスト用のコード

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 
    } 
} 

あなたは、あなたのXPathクエリでは、上記の拡張機能を使用することができ、ここで我々の場合

ための一例です
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

これをノード名に適用できますか? –

8

実際の値が不明な場合は、translateを使用する必要があると思います。

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

これはハックですが、これはXPath 1.0では唯一のオプションです(大文字とは逆です)。

2

これは私がそれを行う方法です。

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

あなたのアプローチは、Chris Taylor'sのように普遍的ではありません。クリスの答えは、チャーのケースの任意の組み合わせに注目してください。 – kseen

+1

@kseen私は知っているが、本当に、誰かから "KeYwOrDs"のようなものを置くことは可能でしょうか?これは3つの一般的な方法です。誰かがそのようなメタ名を書くと、そのHTML文書から何かを解析できるかどうか疑いがあります。これは、2行のコードを必要とし、ほとんどの場合はうまく動作する、すぐに使える解決策ですが、すべてあなたの要件に依存します。 – formatc

+0

私はルールを「ユーザーの入力を信頼しないでください」というルールを維持しようとしています。 – kseen

1

また目を使います

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

しかし、あなたが意図的NullReferenceException ...