Advertisement
Guest User

Untitled

a guest
Apr 10th, 2012
127
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.67 KB | None | 0 0
  1. bool GUI::XHTMLDisplayer::doesSelectorMatch(const std::string& selector, XMLDocument::NodeID node) {
  2.     // first case: if there is a comma in the selector, splitting it and calling doesSelectorMatch with each part
  3.     // TODO:
  4.  
  5.     // second case: if the selector ends with ::something (eg. after, before, etc.), ie. pseudo elements
  6.     // TODO:
  7.  
  8.     // third case: if the selector ends with :something (eg. last-child, empty, etc.), ie. structural pseudo-classes
  9.     //      calling doesSelectorMatch with the first part of the selector, then checking the thing on the right
  10.     {   static std::regex regex("^(.*):([^:]+)$");
  11.         std::smatch matchResults;
  12.         if (std::regex_match(selector, matchResults, regex)) {
  13.             if (!doesSelectorMatch(matchResults[1].str(), node))
  14.                 return false;
  15.  
  16.             // now testing the structural pseudo-class
  17.             const auto secondPart = matchResults[2].str();
  18.             if (secondPart == "root") {
  19.                 return _xhtmlDocument.getParent(node) == _xhtmlDocument.getDocumentElement();
  20.             } else if (secondPart == "first-child") {
  21.                 auto children = _xhtmlDocument.getChildren(_xhtmlDocument.getParent(node));
  22.                 for (auto i = children.begin(); i != children.end(); ++i)
  23.                     if (_xhtmlDocument.getNodeType(*i) == XMLDocument::NODETYPE_ELEMENT && *i != node)
  24.                         return false;
  25.                 return true;
  26.             }
  27.  
  28.             // unknown structural pseudo-class
  29.             return false;
  30.         }
  31.     }
  32.  
  33.     // fourth case: a class, like: E.warning
  34.     // TODO:
  35.  
  36.     // fifth case: an ID, like: E#myid
  37.     // TODO:
  38.  
  39.     // sixth case: an attribute selector, like E[attr] or E[attr="test"]
  40.     // TODO:
  41.  
  42.     // seventh case: the selector is "A B" or "A ~ B" or "A + B" or "A > B"
  43.     {   static std::regex regex("^(.*)\\s*(~|\\+|\\>| )?\\s*[[:alnum:]-_\\.]+$");
  44.         std::smatch matchResults;
  45.         if (std::regex_match(selector, matchResults, regex)) {
  46.             if (!doesSelectorMatch(matchResults[3].str(), node))
  47.                 return false;
  48.            
  49.             const auto firstPart = matchResults[1].str();
  50.             const auto combinator = matchResults[2].matched ? matchResults[2].str().at(0) : ' ';
  51.  
  52.             // now dispatching depending on the combinator
  53.             if (combinator == '>') {
  54.                 // the '>' combinator means the first part must be the parent of the second part
  55.                 return doesSelectorMatch(firstPart, _xhtmlDocument.getParent(node));
  56.  
  57.             } else if (combinator == '+') {
  58.                 // the '+' combinator means the first part must be THE previous element sibling of the second part
  59.                 for (auto i = _xhtmlDocument.getPreviousSibling(node); ; i = _xhtmlDocument.getPreviousSibling(i)) {
  60.                     if (_xhtmlDocument.getNodeType(i) == XMLDocument::NODETYPE_ELEMENT)
  61.                         return doesSelectorMatch(firstPart, i);
  62.                     if (!_xhtmlDocument.hasPreviousSibling(i))
  63.                         break;
  64.                 }
  65.                 return false;
  66.  
  67.             } else if (combinator == '~') {
  68.                 // the '~' combinator means the first part must be one of the previous siblings of the second part
  69.                 for (auto i = _xhtmlDocument.getPreviousSibling(node); ; i = _xhtmlDocument.getPreviousSibling(i)) {
  70.                     if (_xhtmlDocument.getNodeType(i) == XMLDocument::NODETYPE_ELEMENT && doesSelectorMatch(firstPart, i))
  71.                         return true;
  72.                     if (!_xhtmlDocument.hasPreviousSibling(i))
  73.                         break;
  74.                 }
  75.                 return false;
  76.  
  77.             } else if (combinator == ' ') {
  78.                 // the ' ' combinator means the first part must be an ancestor of the second part
  79.                 for (auto i = _xhtmlDocument.getParent(node); i != _xhtmlDocument.getDocumentElement(); i = _xhtmlDocument.getParent(i)) {
  80.                     if (doesSelectorMatch(firstPart, i))
  81.                         return true;
  82.                 }
  83.                 return false;
  84.  
  85.             } else {
  86.                 // unknown combinator
  87.                 return false;
  88.             }
  89.         }
  90.     }
  91.  
  92.     // eight case: the selector is just a node name or a star
  93.     {   static std::regex regex("^\\s*(\\*|[[:alnum:]-_\\.]+)\\s*$");
  94.         std::smatch matchResults;
  95.         if (std::regex_match(selector, matchResults, regex)) {
  96.             const auto name = matchResults[1].str();
  97.             return name == _xhtmlDocument.getNodeName(node) || name == "*";
  98.         }
  99.     }
  100.  
  101.     // if everything failed, returning false
  102.     return false;
  103. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement