XPathSelector.cs :  » GUI » SharpVectorGraphics » SharpVectors » Dom » Css » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » GUI » SharpVectorGraphics 
SharpVectorGraphics » SharpVectors » Dom » Css » XPathSelector.cs
using System;
using System.Xml;
using System.Xml.XPath;
using System.Text.RegularExpressions;
using System.Text;
using System.Collections;

#if TEST 
using NUnit.Framework;
#endif

namespace SharpVectors.Dom.Css{
  #region Public enums
  internal enum XPathSelectorStatus
  {
    Start, Parsed, Compiled, Error
  }
  #endregion
  public class XPathSelector
  {
    #region Static members
    internal static Regex reSelector = new Regex(CssStyleRule.sSelector);
    #endregion

    #region Constructors
    public XPathSelector(string selector) : this(selector, new Hashtable())
    {
    }
    
    public XPathSelector(string selector, Hashtable namespaceTable)
    {
      CssSelector = selector.Trim();
      NsTable = namespaceTable;
    }
    #endregion

    #region Private fields
    private int _specificity = 0;
    private Hashtable NsTable;
    private string sXpath;
    private XPathExpression xpath = null;
    #endregion

    #region Internal properties
    /// <summary>
    /// Only used for testing!
    /// </summary>
    public string XPath
    {
      get
      {
        if(Status == XPathSelectorStatus.Start)
        {
          GetXPath(null);
        }
                return sXpath;
      }
    }

    public int Specificity
    {
      get
      {
        if(Status == XPathSelectorStatus.Start)
        {
          GetXPath(null);
        }
        if(Status != XPathSelectorStatus.Error) return _specificity;
        else return 0;
      }
    }

    internal XPathSelectorStatus Status = XPathSelectorStatus.Start;
    internal string CssSelector;
    #endregion

    #region Private methods
    private void AddSpecificity(int a, int b, int c)
    {
      _specificity += a*100 + b*10 + c;
    }

    private string NsToXPath(Match match)
    {
      string r = String.Empty;
      Group g = match.Groups["ns"];

      if(g != null && g.Success)
      {
        string prefix = g.Value.TrimEnd(new char[]{'|'});

        if(prefix.Length == 0)
        {
          // a element in no namespace
          r += "[namespace-uri()='']";
        }
        else if(prefix == "*")
        {
          // do nothing, any or no namespace is okey
        }
        else if(NsTable.ContainsKey(prefix))
        {
          r += "[namespace-uri()='" + NsTable[prefix] + "']";
        }
        else
        {
          //undeclared namespace => invalid CSS selector
          r += "[false]";
        }
      }
      else if(NsTable.ContainsKey(String.Empty))
      {
        //if no default namespace has been specified, this is equivalent to *|E. Otherwise it is equivalent to ns|E where ns is the default namespace.

        r += "[namespace-uri()='" + NsTable[String.Empty] + "']";
      }
      return r;
    }

    private string TypeToXPath(Match match)
    {
      string r = String.Empty;
      Group g = match.Groups["type"];
      string s = g.Value;
      if(!g.Success || s=="*") r = String.Empty;
      else
      {
        r = "[local-name()='" + s + "']";
        AddSpecificity(0, 0, 1);
      }

      return r;
    }

    private string ClassToXPath(Match match)
    {
      string r = String.Empty;
      Group g = match.Groups["class"];

      foreach(Capture c in g.Captures)
      {
        r += "[contains(concat(' ',@class,' '),' " + c.Value.Substring(1) + " ')]";
        AddSpecificity(0, 1, 0);
      }
      return r;
    }

    private string IdToXPath(Match match)
    {
      string r = String.Empty;
      Group g = match.Groups["id"];
      if(g.Success)
      {
        // r = "[id('" + g.Value.Substring(1) + "')]";
        r = "[@id='" + g.Value.Substring(1) + "']";
        AddSpecificity(1, 0, 0);
      }
      return r;
    }


    private string GetAttributeMatch(string attSelector)
    {
      string fullAttName = attSelector.Trim();
      int pipePos = fullAttName.IndexOf("|");
      string attMatch = String.Empty;

      if(pipePos == -1 || pipePos == 0)
      {
        // att or |att => should be in the undeclared namespace
        string attName = fullAttName.Substring(pipePos+1);
        attMatch = "@" + attName;
      }
      else if(fullAttName.StartsWith("*|"))
      {
        // *|att => in any namespace (undeclared or declared)
        attMatch = "@*[local-name()='" + fullAttName.Substring(2) + "']";
      }
      else
      {
        // ns|att => must macht a declared namespace
        string ns = fullAttName.Substring(0, pipePos);
        string attName = fullAttName.Substring(pipePos+1);
        if(NsTable.ContainsKey(ns))
        {
          attMatch = "@" + ns + ":" + attName;
        }
        else
        {
          // undeclared namespace => selector should fail
          attMatch = "false";
        }
      }
      return attMatch;
    }
    private string PredicatesToXPath(Match match)
    {
      string r = String.Empty;
      Group g = match.Groups["attributecheck"];
      
      foreach(Capture c in g.Captures)
      {
        r += "[" + GetAttributeMatch(c.Value) + "]";
        AddSpecificity(0, 1, 0);
      }

      g = match.Groups["attributevaluecheck"];
      Regex reAttributeValueCheck = new Regex("^" + CssStyleRule.attributeValueCheck + "?$");
  

      foreach(Capture c in g.Captures)
      {
        Match valueCheckMatch = reAttributeValueCheck.Match(c.Value);
        
        string attName = valueCheckMatch.Groups["attname"].Value;
        string attMatch = GetAttributeMatch(attName);
        string eq = valueCheckMatch.Groups["eqtype"].Value;  // ~,^,$,*,|,nothing
        string attValue = valueCheckMatch.Groups["attvalue"].Value;

        switch(eq)
        {
          case "":
            // [foo="bar"] => [@foo='bar']
            r += "[" + attMatch + "='" + attValue + "']";
            break;
          case "~":
            // [foo~="bar"] 
            // an E element whose "foo" attribute value is a list of space-separated values, one of which is exactly equal to "bar"
            r += "[contains(concat(' '," + attMatch + ",' '),' " + attValue + " ')]";
            break;
          case "^":
            // [foo^="bar"]  
            // an E element whose "foo" attribute value begins exactly with the string "bar"
            r += "[starts-with(" + attMatch + ",'" + attValue + "')]";
            break;
          case "$":
            // [foo$="bar"]  
            // an E element whose "foo" attribute value ends exactly with the string "bar"
            int a = attValue.Length - 1;

            r += "[substring(" + attMatch + ",string-length(" + attMatch + ")-" + a + ")='" + attValue + "']";
            break;
          case "*":
            // [foo*="bar"]  
            // an E element whose "foo" attribute value contains the substring "bar"
            r += "[contains(" + attMatch + ",'" + attValue + "')]";
            break;
          case "|":
            // [hreflang|="en"]  
            // an E element whose "hreflang" attribute has a hyphen-separated list of values beginning (from the left) with "en"
            r += "[" + attMatch + "='" + attValue + "' or starts-with(" + attMatch + ",'" + attValue + "-')]";
            break;
        }
        AddSpecificity(0, 1, 0);
      }

      return r;
    }

    private string PseudoClassesToXPath(Match match, XPathNavigator nav)
    {
      int specificityA = 0;
      int specificityB = 1;
      int specificityC = 0;
      string r = String.Empty;
      Group g = match.Groups["pseudoclass"];

      foreach(Capture c in g.Captures)
      {
        Regex reLang = new Regex(@"^lang\(([A-Za-z\-]+)\)$");
        Regex reContains = new Regex("^contains\\((\"|\')?(?<stringvalue>.*?)(\"|\')?\\)$");

        string s = @"^(?<type>(nth-child)|(nth-last-child)|(nth-of-type)|(nth-last-of-type))\(\s*";
        s += @"(?<exp>(odd)|(even)|(((?<a>[\+-]?\d*)n)?(?<b>[\+-]?\d+)?))";
        s += @"\s*\)$";
        Regex reNth = new Regex(s);

        string p = c.Value.Substring(1);

        if(p == "root")
        {
          r += "[not(parent::*)]";
        }
        else if(p.StartsWith("not"))
        {
          string expr = p.Substring(4, p.Length-5);
          XPathSelector sel = new XPathSelector(expr, NsTable);

          string xpath = sel.XPath;
          if(xpath != null && xpath.Length>3)
          {
            // remove *[ and ending ]
            xpath = xpath.Substring(2, xpath.Length-3);

            r += "[not(" + xpath + ")]";

            int specificity = sel.Specificity;

            // specificity = 123
            specificityA = (int)Math.Floor((double) specificity / 100);
            specificity -= specificityA*100;
            // specificity = 23
            specificityB = (int)Math.Floor((double) (specificity) / 10);

            specificity -= specificityB * 10;
            // specificity = 3
            specificityC = specificity;
          }
        }
        else if(p == "first-child")
        {
          r += "[count(preceding-sibling::*)=0]";
        }
        else if(p == "last-child")
        {
          r += "[count(following-sibling::*)=0]";
        }
        else if(p == "only-child")
        {
          r += "[count(../*)=1]";
        }
        else if(p == "only-of-type")
        {
          r += "[false]";
        }
        else if(p == "empty")
        {
          r += "[not(child::*) and not(text())]";
        }
        else if(p == "target")
        {
          r += "[false]";
        }
        else if(p == "first-of-type")
        {
          r += "[false]";
          //r += "[.=(../*[local-name='roffe'][position()=1])]";
        }
        else if(reLang.IsMatch(p))
        {
          r += "[lang('" + reLang.Match(p).Groups[1].Value + "')]";
        }
        else if(reContains.IsMatch(p))
        {
          r += "[contains(string(.),'" + reContains.Match(p).Groups["stringvalue"].Value + "')]";
        }
        else if(reNth.IsMatch(p))
        {
          Match m = reNth.Match(p);
          string type = m.Groups["type"].Value;
          string exp = m.Groups["exp"].Value;
          int a = 0;
          int b = 0;
          if(exp == "odd")
          {
            a = 2;
            b = 1;
          }
          else if(exp == "even")
          {
            a = 2;
            b = 0;
          }
          else
          {
            string v = m.Groups["a"].Value;

            if(v.Length == 0) a = 1;
            else if(v.Equals("-")) a = -1;
            else a = Int32.Parse(v);

            if(m.Groups["b"].Success) b = Int32.Parse(m.Groups["b"].Value);
          }


          if(type.Equals("nth-child") || type.Equals("nth-last-child"))
          {
            string axis;
            if(type.Equals("nth-child")) axis = "preceding-sibling";
            else axis = "following-sibling";

            if(a == 0)
            {
              r += "[count(" + axis + "::*)+1=" + b + "]";
            }
            else
            {
              r += "[((count(" + axis + "::*)+1-" + b + ") mod " + a + "=0)and((count(" + axis + "::*)+1-" + b + ") div " + a + ">=0)]";
            }
          }
        }
        AddSpecificity(specificityA, specificityB, specificityC);
      }
      return r;
    }

    private void SeperatorToXPath(Match match, StringBuilder xpath, string cur)
    {
      Group g = match.Groups["seperator"];
      if(g.Success)
      {
        string s = g.Value.Trim();
        if(s.Length == 0) cur += "//*";
        else if(s == ">") cur += "/*";
        else if(s == "+" || s == "~")
        {
          xpath.Append("[preceding-sibling::*");
          if(s == "+")
          {
            xpath.Append("[position()=1]");
          }
          xpath.Append(cur);
          xpath.Append("]");
          cur = String.Empty;
        }
      }
      xpath.Append(cur);
    }


    #endregion

    #region Internal methods
    internal void GetXPath(XPathNavigator nav)
    {
      this._specificity = 0;
      StringBuilder xpath = new StringBuilder("*");
      
      Match match = reSelector.Match(CssSelector);
      while(match.Success)
      {
        if(match.Success && match.Value.Length > 0)
        {
          string x = String.Empty;
          x += NsToXPath(match);
          x += TypeToXPath(match);
          x += ClassToXPath(match);
          x += IdToXPath(match);
          x += PredicatesToXPath(match);
          x += PseudoClassesToXPath(match, nav);
          SeperatorToXPath(match, xpath, x);
          

        }
        match = match.NextMatch();
      }
      if(nav != null) Status = XPathSelectorStatus.Parsed;
      sXpath = xpath.ToString();
    }

    private XmlNamespaceManager GetNSManager()
    {
      XmlNamespaceManager nsman = new XmlNamespaceManager(new NameTable());
      IDictionaryEnumerator dicEnum = NsTable.GetEnumerator();
      while(dicEnum.MoveNext())
      {
        nsman.AddNamespace((string)dicEnum.Key, (string)dicEnum.Value);
      }
      return nsman;

    }

    internal void Compile(XPathNavigator nav)
    {
      if(Status == XPathSelectorStatus.Start)
      {
        GetXPath(nav);
      }
      if(Status == XPathSelectorStatus.Parsed)
      {
        xpath = nav.Compile(sXpath);
        xpath.SetContext(GetNSManager());
        
        Status = XPathSelectorStatus.Compiled;
      }
    }

    public bool Matches(XPathNavigator nav)
    {
      if(Status != XPathSelectorStatus.Compiled)
      {
        Compile(nav);
      }
      if(Status == XPathSelectorStatus.Compiled)
      {
        try
        {
          return nav.Matches(xpath);
        }
        catch
        {
          return false;
        }
      }
      else
      {
        return false;
      }
    }

    #endregion

    #region Unit tests
    #if TEST
    [TestFixture]
    public class XPathSelectorTests
    {
      CssXmlDocument doc = new CssXmlDocument();
      XPathNavigator a;
      XPathNavigator b;
      XPathNavigator c;
      XPathNavigator d;
      XPathNavigator e;
      XPathNavigator f;
      XPathNavigator g;
      Hashtable nsTable = new Hashtable();

      #region Testdata
            string testXml = 
        "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + 
        "<!DOCTYPE a [" + 
        "  <!ELEMENT a (#PCDATA | b | e | f | ns:g)*>" + 
        "  <!ATTLIST a" + 
        "  xmlns:ns CDATA #REQUIRED" + 
        ">" + 
        "  <!ELEMENT b (#PCDATA | c)*>" + 
        "  <!ATTLIST b" + 
        "  id CDATA #REQUIRED" + 
        "    att CDATA #REQUIRED" + 
        "    class CDATA #REQUIRED" + 
        "    ns:nsatt CDATA #REQUIRED" + 
        ">" + 
        "  <!ELEMENT c (#PCDATA | d)*>" + 
        "  <!ATTLIST c" + 
        "  id ID #REQUIRED" + 
        "    xml:lang CDATA #REQUIRED" + 
        "    hreflang CDATA #REQUIRED" + 
        ">" + 
        "  <!ELEMENT d (#PCDATA)>" + 
        "  <!ELEMENT e EMPTY>" + 
        "  <!ELEMENT f EMPTY>" + 
        "  <!ELEMENT ns:g EMPTY>" + 
        "]>" + 
        "<a xmlns:ns='http://www.sharpvectors.org'>asdsa" + 
        "  <b id='mrB' att='attvalue' class='class1 class2 class3' ns:nsatt='foo'>" + 
        "    <c id='mrC' xml:lang='se-SV' hreflang='sv-FI'>kjjkkjjk" + 
        "      <d>some text</d>" + 
        "    </c>sdfsdf" + 
        "  </b>" + 
        "  <e/>" + 
        "  <e/>" + 
        "  <e/>" + 
        "  <f/>" + 
        "  <ns:g/>" + 
        "</a>";

      #endregion
    

      #region Setup
      [SetUp]
      public void Init()
      {
        doc.LoadXml(testXml);
      
        if(!nsTable.ContainsKey("ns")) nsTable.Add("ns", "http://www.sharpvectors.org");

        a = doc.SelectSingleNode("//a").CreateNavigator();
        b = doc.SelectSingleNode("//b").CreateNavigator();
        c = doc.SelectSingleNode("//c").CreateNavigator();
        d = doc.SelectSingleNode("//d").CreateNavigator();
        e = doc.SelectSingleNode("//e").CreateNavigator();
        f = doc.SelectSingleNode("//f").CreateNavigator();
        g = doc.SelectSingleNode("//*[local-name()='g']").CreateNavigator();
      }
      #endregion

      [Test]
      public void TestSpecificity()
      {
        Assert.AreEqual(0, new XPathSelector("*").Specificity, "*");
        Assert.AreEqual(1, new XPathSelector("LI").Specificity, "LI");
        Assert.AreEqual(1, new XPathSelector("ns|LI", nsTable).Specificity, "ns|LI");
        Assert.AreEqual(2, new XPathSelector("UL LI").Specificity, "UL LI");
        Assert.AreEqual(3, new XPathSelector("UL OL+LI").Specificity, "UL OL+LI");
        Assert.AreEqual(11, new XPathSelector("H1 + *[REL=up]").Specificity, "H1 + *[REL=up]");
        Assert.AreEqual(13, new XPathSelector("UL OL LI.red").Specificity, "UL OL LI.red");
        Assert.AreEqual(21, new XPathSelector("LI.red.level").Specificity, "LI.red.level");
        Assert.AreEqual(100 , new XPathSelector("#x34y").Specificity, "#x34y");
        Assert.AreEqual(101, new XPathSelector("#s12:not(FOO)").Specificity, "#s12:not(FOO)");
      }


    #region Type matching
      [Test]
      public void TestUniversalMatching()
      {
        Assert.IsTrue(new XPathSelector("*").Matches(a));
        Assert.IsTrue(new XPathSelector("*").Matches(b));
      }

      [Test]
      public void TestTypeMatching()
      {
        Assert.IsTrue(new XPathSelector("a").Matches(a));
        Assert.IsTrue(new XPathSelector("b").Matches(b));

        Assert.IsTrue(!(new XPathSelector("a").Matches(b)));
        Assert.IsTrue(!(new XPathSelector("A").Matches(a)));
      }
    #endregion

    #region Relation matching
      [Test]
      public void TestDescendantMatching()
      {
        Assert.IsTrue(new XPathSelector("a b").Matches(b), "a b");
        Assert.IsTrue(new XPathSelector("a     c").Matches(c), "a     c");
        Assert.IsTrue(new XPathSelector("b  d").Matches(d), "b  d");
        Assert.IsTrue(!(new XPathSelector("b e").Matches(e)), "b e");
        Assert.IsTrue(!(new XPathSelector("b a").Matches(a)), "b a");
      }

      [Test]
      public void TestChildMatching()
      {
        Assert.IsTrue(new XPathSelector("a>b").Matches(b), "a>b");
        Assert.IsTrue(!(new XPathSelector("a >c").Matches(c)), "a >c");
        Assert.IsTrue(!(new XPathSelector("a > d").Matches(d)), "a > d");
        Assert.IsTrue(new XPathSelector("b>      c").Matches(c), "b>      c");
      }

      [Test]
      public void TestDirectAdjacentMatching()
      {
        Assert.IsTrue(new XPathSelector("b +e").Matches(e), "b +e");
        Assert.IsTrue(new XPathSelector("e+f").Matches(f), "e+f");
        Assert.IsTrue(!(new XPathSelector("b+f").Matches(f)), "b+f");
      }

      [Test]
      public void TestIndirectAdjacentMatching()
      {
        Assert.IsTrue(new XPathSelector("b ~e").Matches(e), "b ~e");
        Assert.IsTrue(new XPathSelector("e~f").Matches(f), "e~f");
        Assert.IsTrue(new XPathSelector("b~f").Matches(f), "b~f");
        Assert.IsTrue(!(new XPathSelector("f~e").Matches(e)), "f~e");
      }
    #endregion

    #region Class, Id and namespace matching
      [Test]
      public void TestClassMatching()
      {
        Assert.IsTrue(new XPathSelector(".class1").Matches(b), ".class1");
        Assert.IsTrue(new XPathSelector(".class2").Matches(b), ".class2");
        Assert.IsTrue(new XPathSelector("b.class3").Matches(b), "b.class3");
        Assert.IsTrue(new XPathSelector(".class3.class2").Matches(b), ".class3.class2");
        Assert.IsTrue(new XPathSelector(".class1.class2.class3").Matches(b), ".class1.class2.class3");

        Assert.IsTrue(!(new XPathSelector(".class1").Matches(c)), ".class1");
        Assert.IsTrue(!(new XPathSelector(".dummy").Matches(b)), ".dummy");
      }

      [Test]
      public void TestIdMatching()
      {
        Assert.IsTrue(new XPathSelector("#mrC").Matches(c), "#mrC");
        Assert.IsTrue(new XPathSelector("c#mrC").Matches(c), "c#mrC");

      }

      [Test]
      [Ignore("DTD support disabled")]
      public void TestIdMatchingNoDtd()
      {
        // id on <b> is not defined in the DTD as ID
        Assert.IsTrue(!(new XPathSelector("#mrB").Matches(b)), "#mrB");
      }

      [Test]
      public void TestNsMatching()
      {
        Assert.IsTrue(new XPathSelector("ns|g", nsTable).Matches(g), "ns|g");
        Assert.IsTrue(new XPathSelector("*|g", nsTable).Matches(g), "*|g");
        Assert.IsTrue(new XPathSelector("|a", nsTable).Matches(a), "|a");
        Assert.IsTrue(new XPathSelector("*|a", nsTable).Matches(a), "*|a");

        Assert.IsTrue(!(new XPathSelector("dummy|g", nsTable).Matches(g)), "dummy|g");
        Assert.IsTrue(!(new XPathSelector("ns|a", nsTable).Matches(a)), "ns|a");
      }
    #endregion

    #region Attribute matching
      [Test]
      public void TestAttributeExistsMatching()
      {
        Assert.IsTrue(new XPathSelector("b[att]").Matches(b), "b[att]");
      
        Assert.IsTrue(new XPathSelector("b[ns|nsatt]", nsTable).Matches(b), "b[ns|nsatt]");
        Assert.IsTrue(new XPathSelector("b[*|nsatt]", nsTable).Matches(b), "b[*|nsatt]");
        Assert.IsTrue(new XPathSelector("b[*|att]", nsTable).Matches(b), "b[*|att]");
        Assert.IsTrue(new XPathSelector("b[|att]", nsTable).Matches(b), "b[|att]");

        Assert.IsTrue(!(new XPathSelector("b[|nsatt]", nsTable).Matches(b)), "b[|nsatt]");
        Assert.IsTrue(!(new XPathSelector("b[nsatt]", nsTable).Matches(b)), "b[nsatt]");

        Assert.IsTrue(new XPathSelector("b[ att][ class  ]").Matches(b), "b[ att][ class  ]");

        Assert.IsTrue(!(new XPathSelector("b[att][dummy]").Matches(b)), "b[att][dummy]");
        Assert.IsTrue(!(new XPathSelector("b[dummy]").Matches(b)), "b[dummy]");
      }

      [Test]
      public void TestAttributeValueMatching()
      {
        Assert.IsTrue(new XPathSelector("b[att=attvalue]").Matches(b), "b[att=attvalue]");
        Assert.IsTrue(new XPathSelector("b[att=  'attvalue' ]").Matches(b), "b[att=  'attvalue' ]");
        Assert.IsTrue(new XPathSelector("b[ att =\"attvalue\"]").Matches(b), "b[ att =\"attvalue\"]");

        Assert.IsTrue(new XPathSelector("b[ns|nsatt='foo']", nsTable).Matches(b), "b[ns|nsatt='foo']");
        Assert.IsTrue(new XPathSelector("b[*|nsatt=foo]", nsTable).Matches(b), "b[*|nsatt=foo]");
        Assert.IsTrue(new XPathSelector("b[*|att=attvalue]", nsTable).Matches(b), "b[*|att=attvalue]");
        Assert.IsTrue(new XPathSelector("b[|att=\"attvalue\"]", nsTable).Matches(b), "b[|att=\"attvalue\"]");

        Assert.IsTrue(!(new XPathSelector("b[|nsatt=foo]", nsTable).Matches(b)), "b[|nsatt=foo]");
        Assert.IsTrue(!(new XPathSelector("b[nsatt=foo]", nsTable).Matches(b)), "b[nsatt=foo]");


        Assert.IsTrue(!(new XPathSelector("b[att=dummy]").Matches(b)), "b[att=dummy]");
      }

      [Test]
      public void TestAttributeValueSpaceSeparatedMatching()
      {
        Assert.IsTrue(new XPathSelector("b[class~=class2]").Matches(b), "b[class~=class2]");
        Assert.IsTrue(new XPathSelector("b[class~=class3]").Matches(b), "b[class~=class3]");
        Assert.IsTrue(new XPathSelector("b[class~=class2][class~=class3]").Matches(b), "b[class~=class2][class~=class3]");

        Assert.IsTrue(!(new XPathSelector("b[class~=dummy]").Matches(b)), "b[class~=dummy]");
      }

      [Test]
      public void TestAttributeValueBeginMatching()
      {
        Assert.IsTrue(new XPathSelector("b[att^=attv]").Matches(b), "b[att^=attv]");
        Assert.IsTrue(new XPathSelector("b[att^=attvalue]").Matches(b), "b[att^=attvalue]");

        Assert.IsTrue(!(new XPathSelector("b[att^=dummy]").Matches(b)), "b[att^=dummy]");
        Assert.IsTrue(!(new XPathSelector("b[att^=ttv]").Matches(b)), "b[att^=ttv]");
      }

      [Test]
      public void TestAttributeValueEndMatching()
      {
        Assert.IsTrue(new XPathSelector("b[att$=lue]").Matches(b), "b[att$=lue]");
        Assert.IsTrue(new XPathSelector("b[att$=attvalue]").Matches(b), "b[att$=attvalue]");

        Assert.IsTrue(!(new XPathSelector("b[att$=dummy]").Matches(b)), "b[att$=dummy]");
        Assert.IsTrue(!(new XPathSelector("b[att$=ttv]").Matches(b)), "b[att$=ttv]");
      }

      [Test]
      public void TestAttributeValueSubStringMatching()
      {
        Assert.IsTrue(new XPathSelector("b[att*=lue]").Matches(b), "b[att*=lue]");
        Assert.IsTrue(new XPathSelector("b[att*=attvalue]").Matches(b), "b[att*=attvalue]");
        Assert.IsTrue(new XPathSelector("b[att*=attv]").Matches(b), "b[att*=attv]");

        Assert.IsTrue(!(new XPathSelector("b[att*=dummy]").Matches(b)), "b[att*=dummy]");
      }

      [Test]
      public void TestAttributeValueHyphenMatching()
      {
        Assert.IsTrue(new XPathSelector("[hreflang|=sv]").Matches(c), "[hreflang|=sv]");

        Assert.IsTrue(!(new XPathSelector("[hreflang|=sv]").Matches(b)), "[hreflang|=sv]");
      }
    #endregion

    #region Misc
      /* Not supported
      [Test]
      public void TestTargetMatching()
      {
        Console.WriteLine(doc.Url);

      }
      */
    
      [Test]
      public void TestLangMatching()
      {
        Assert.IsTrue(new XPathSelector("c:lang(se-SV)").Matches(c), "c:lang(se-SV)");
        Assert.IsTrue(new XPathSelector("c:lang(se)").Matches(c), "c:lang(se)");
        Assert.IsTrue(new XPathSelector("d:lang(se)").Matches(d), "d:lang(se)");

        Assert.IsTrue(!(new XPathSelector("c:lang(se-FI)").Matches(c)), "c:lang(se-FI)");
        Assert.IsTrue(!(new XPathSelector("c:lang(en)").Matches(c)), "c:lang(en)");
      }

      [Test]
      public void TestNotMatching()
      {
        Assert.IsTrue(new XPathSelector("c:not(:root)").Matches(c), "c:not(:root))");
        Assert.IsTrue(new XPathSelector("a:not(.kalle)").Matches(a), "a:not(.kalle))");
        Assert.IsTrue(new XPathSelector("*:not(b)").Matches(a), "*:not(b)");
        Assert.IsTrue(new XPathSelector("*:not(b)").Matches(g), "*:not(b)");

        Assert.IsTrue(!(new XPathSelector("*:not(b)").Matches(b)), "*:not(b)");
        Assert.IsTrue(!(new XPathSelector("a:not(:root)").Matches(a)), "a:not(:root))");
      }

      [Test]
      public void TestRootMatching()
      {
        Assert.IsTrue(new XPathSelector("a:root").Matches(a), "a:root");
        Assert.IsTrue(!(new XPathSelector("b:root").Matches(b)), "b:root");
      }

      [Test]
      public void TestContainsMatching()
      {
        Assert.IsTrue(new XPathSelector("d:contains(some)").Matches(d), "d:contains(some)");
        Assert.IsTrue(new XPathSelector("d:contains('me te')").Matches(d), "d:contains('me te')");
        Assert.IsTrue(new XPathSelector("d:contains(\"me text\")").Matches(d), "d:contains(\"me text\")");

        Assert.IsTrue(!(new XPathSelector("d:contains(dummy)").Matches(d)), "d:contains(dummy)");
      }

      [Test]
      public void TestOnlyChildMatching()
      {
        Assert.IsTrue(new XPathSelector("c:only-child").Matches(c), "c:only-child");
        Assert.IsTrue(new XPathSelector("d:only-child").Matches(d), "d:only-child");

        Assert.IsTrue(!(new XPathSelector("b:only-child").Matches(b)), "b:only-child");
        Assert.IsTrue(!(new XPathSelector("e:only-child").Matches(e)), "e:only-child");
      }

      [Test]
      public void TestEmptyMatching()
      {
        Assert.IsTrue(new XPathSelector("e:empty").Matches(e), "e:empty");

        Assert.IsTrue(!(new XPathSelector("b:empty").Matches(b)), "b:empty");
        Assert.IsTrue(!(new XPathSelector("d:empty").Matches(d)), "d:empty");
      }
      #endregion

      #region Position matching
      [Test]
      public void TestFirstChildMatching()
      {
        Assert.IsTrue(new XPathSelector("b:first-child").Matches(b), "b:first-child");
        Assert.IsTrue(new XPathSelector("d:first-child").Matches(d), "d:first-child");

        Assert.IsTrue(!(new XPathSelector("e:first-child").Matches(e)), "e:first-child");
      }

      [Test]
      public void TestLastChildMatching()
      {
        Assert.IsTrue(new XPathSelector("c:last-child").Matches(c), "c:last-child");
        Assert.IsTrue(new XPathSelector("d:first-child").Matches(d), "d:first-child");

        Assert.IsTrue(!(new XPathSelector("b:last-child").Matches(b)), "b:last-child");
      }

      [Test]
      public void TestNthChildMatching()
      {
        Assert.IsTrue(new XPathSelector("*:nth-child(2)").Matches(e), "1: *:nth-child(2)");

        Assert.IsTrue(new XPathSelector("e:nth-child(2n)").Matches(e), "e:nth-child(2n)");
        Assert.IsTrue(new XPathSelector("e:nth-child(n)").Matches(e), "e:nth-child(n)");
        Assert.IsTrue(new XPathSelector("e:nth-child(4n-2)").Matches(e), "e:nth-child(4n- 2)");
        Assert.IsTrue(new XPathSelector("g:nth-child(2n)").Matches(g), "g:nth-child(2n)");

        Assert.IsTrue(new XPathSelector("b:nth-child(0n  + 1)").Matches(b), "b:nth-child( 0n  + 1)");
        Assert.IsTrue(!(new XPathSelector("e:nth-child( 0n+1)").Matches(e)), "e:nth-child( 0n+1)");

        Assert.IsTrue(new XPathSelector("*:nth-child(-n+2)").Matches(b), "*:nth-child(-n+2)");
        Assert.IsTrue(new XPathSelector("*:nth-child(-n+2)").Matches(e), "*:nth-child(-n+2)");
        Assert.IsTrue(!(new XPathSelector("*:nth-child(-n+2)").Matches(f)), "*:nth-child(-n+2)");
        Assert.IsTrue(!(new XPathSelector("*:nth-child(-n+2)").Matches(g)), "*:nth-child(-n+2)");

        // test of odd and even
        Assert.IsTrue(new XPathSelector("e:nth-child(even)").Matches(e), "e:nth-child(even)");
        Assert.IsTrue(new XPathSelector("b:nth-child(odd)").Matches(b), "b:nth-child(odd)");
        Assert.IsTrue(new XPathSelector("f:nth-child(odd)").Matches(f), "f:nth-child(odd)");
        Assert.IsTrue(!(new XPathSelector("e:nth-child(odd)").Matches(e)), "e:nth-child(odd)");
        Assert.IsTrue(!(new XPathSelector("b:nth-child(even)").Matches(b)), "b:nth-child(even)");

        // tests for false positives
        Assert.IsTrue(!(new XPathSelector("b:nth-child(2n)").Matches(b)), "b:nth-child(2n)");
        Assert.IsTrue(!(new XPathSelector("f:nth-child(2n)").Matches(b)), "f:nth-child(2n)");
      }

      public void TestNthLastChildMatching()
      {
        Assert.IsTrue(new XPathSelector("*:nth-last-child(5)").Matches(e), "1: *:nth-last-child(5)");

        Assert.IsTrue(new XPathSelector("*:nth-last-child(-n+2)").Matches(g), "2: *:nth-last-child(-n+2)");
        Assert.IsTrue(new XPathSelector("*:nth-last-child(-n+2)").Matches(f), "3: *:nth-last-child(-n+2)");
        Assert.IsTrue(!(new XPathSelector("*:nth-last-child(-n+2)").Matches(e)), "4: *:nth-last-child(-n+2)");
        Assert.IsTrue(!(new XPathSelector("*:nth-last-child(-n+2)").Matches(b)), "5: *:nth-last-child(-n+2)");

        Assert.IsTrue(new XPathSelector("*:nth-last-child(odd)").Matches(g), "*:nth-last-child( odd)");
        Assert.IsTrue(new XPathSelector("*:nth-last-child(odd)").Matches(e), "*:nth-last-child(odd)");
        Assert.IsTrue(!(new XPathSelector("*:nth-last-child(odd)").Matches(f)), "*:nth-last-child(odd )");
        Assert.IsTrue(!(new XPathSelector("*:nth-last-child(odd)").Matches(b)), "*:nth-last-child(odd)");

        Assert.IsTrue(new XPathSelector("*:nth-last-child(even)").Matches(f), "*:nth-last-child(even)");
        Assert.IsTrue(new XPathSelector("*:nth-last-child(even)").Matches(b), "*:nth-last-child( even)");
        Assert.IsTrue(!(new XPathSelector("*:nth-last-child(even)").Matches(g)), "*:nth-last-child(even)");
        Assert.IsTrue(!(new XPathSelector("*:nth-last-child(even)").Matches(e)), "*:nth-last-child(even )");
      }
      #endregion

      private void PrintXPath(string sel)
      {
        this.PrintXPath(sel, new Hashtable());
      }

      private void PrintXPath(string sel, Hashtable nsTable)
      {
        XPathSelector xsel = new XPathSelector(sel, nsTable);
        xsel.Matches(e);
        //      Console.WriteLine(xsel.XPath);
      }

    }
    #endif
    #endregion
  }
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.