HtmlAgilityPack XPath 대소 문자 무시

.net-2.0 c# case-sensitive html-agility-pack xpath

문제

내가 사용할 때

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

그것은 작동하지 않습니다,하지만 내가 원래의 문서에서 사용되는 것과 동일한 케이스를 사용할 때 그것은 잘 작동합니다 :

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

문제는 어떻게 무시할 수 있습니까?

수락 된 답변

보다 포괄적 인 솔루션이 필요한 경우 대소 문자를 구분하지 않는 비교를 수행하는 XPath 프로세서 용 확장 함수를 작성할 수 있습니다. 꽤 많은 코드이지만 한 번만 쓰십시오.

확장 기능을 구현 한 후에는 다음과 같이 쿼리를 작성할 수 있습니다.

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

여기서 Extensions:CaseInsensitiveComparison 은 아래 샘플에서 구현 된 확장 함수입니다.

참고 : 이 잘 테스트되지 않은 나는 단지이 응답을 위해 함께 던져 오류 처리 등 존재하지 않습니다!

다음은 하나 이상의 확장 기능을 제공하는 사용자 정의 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
  }
}

인기 답변

실제 값이 알 수없는 경우 번역을 사용해야합니다. 나는 그것이라고 믿는다 :

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

이것은 해킹이지만 XPath 1.0에서는 유일한 옵션입니다 (대문자의 경우는 제외).



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