summaryrefslogtreecommitdiff
path: root/lib/querypath/src/QueryPath/CSS/Selector.php
blob: 4b538bd8e9d5ab43b7bddfdec229b14406a3c3fe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
<?php
/** @file
 * A selector.
 */

namespace QueryPath\CSS;

/**
 * A CSS Selector.
 *
 * A CSS selector is made up of one or more Simple Selectors
 * (SimpleSelector).
 *
 * @attention
 * The Selector data structure is a LIFO (Last in, First out). This is
 * because CSS selectors are best processed "bottom up". Thus, when
 * iterating over 'a>b>c', the iterator will produce:
 * - c
 * - b
 * - a
 * It is assumed, therefore, that any suitable querying engine will
 * traverse from the bottom (`c`) back up.
 *
 * @b Usage
 *
 * This class is an event handler. It can be plugged into an Parser and 
 * receive the events the Parser generates.
 *
 * This class is also an iterator. Once the parser has completed, the
 * captured selectors can be iterated over.
 *
 * @code
 * <?php
 * $selectorList = new \QueryPath\CSS\Selector();
 * $parser = new \QueryPath\CSS\Parser($selector, $selectorList);
 *
 * $parser->parse();
 *
 * foreach ($selectorList as $simpleSelector) {
 *   // Do something with the SimpleSelector.
 *   print_r($simpleSelector);
 * }
 * ?>
 * @endode
 *
 *
 * @since QueryPath 3.0.0
 */
class Selector implements EventHandler, \IteratorAggregate, \Countable {
  protected $selectors = array();
  protected $currSelector;
  protected $selectorGroups = array();
  protected $groupIndex = 0;

  public function __construct() {
    $this->currSelector = new SimpleSelector();

    $this->selectors[$this->groupIndex][] = $this->currSelector;
  }

  public function getIterator() {
    return new \ArrayIterator($this->selectors);
  }

  /**
   * Get the array of SimpleSelector objects.
   *
   * Normally, one iterates over a Selector. However, if it is
   * necessary to get the selector array and manipulate it, this
   * method can be used.
   */
  public function toArray() {
    return $this->selectors;
  }

  public function count() {
    return count($this->selectors);
  }

  public function elementID($id) {
    $this->currSelector->id = $id;
  }
  public function element($name) {
    $this->currSelector->element = $name;
  }
  public function elementNS($name, $namespace = NULL) {
    $this->currSelector->ns = $namespace;
    $this->currSelector->element = $name;
  }
  public function anyElement() {
    $this->currSelector->element = '*';
  }
  public function anyElementInNS($ns) {
    $this->currSelector->ns = $ns;
    $this->currSelector->element = '*';
  }
  public function elementClass($name) {
    $this->currSelector->classes[] = $name;
  }
  public function attribute($name, $value = NULL, $operation = EventHandler::isExactly) {
    $this->currSelector->attributes[] = array(
      'name'  => $name,
      'value' => $value,
      'op'    => $operation,
    );
  }
  public function attributeNS($name, $ns, $value = NULL, $operation = EventHandler::isExactly) {
    $this->currSelector->attributes[] = array(
      'name'  => $name,
      'value' => $value,
      'op'    => $operation,
      'ns'    => $ns,
    );
  }
  public function pseudoClass($name, $value = NULL) {
    $this->currSelector->pseudoClasses[] = array('name' => $name, 'value' => $value);
  }
  public function pseudoElement($name) {
    $this->currSelector->pseudoElements[] = $name;
  }
  public function combinator($combinatorName) {
    $this->currSelector->combinator = $combinatorName;
    $this->currSelector = new SimpleSelector();
    array_unshift($this->selectors[$this->groupIndex], $this->currSelector);
    //$this->selectors[]= $this->currSelector;
  }
  public function directDescendant() {
    $this->combinator(SimpleSelector::directDescendant);
  }
  public function adjacent() {
    $this->combinator(SimpleSelector::adjacent);
  }
  public function anotherSelector() {
    $this->groupIndex++;
    $this->currSelector = new SimpleSelector();
    $this->selectors[$this->groupIndex] = array($this->currSelector);
  }
  public function sibling() {
    $this->combinator(SimpleSelector::sibling);
  }
  public function anyDescendant() {
    $this->combinator(SimpleSelector::anyDescendant);
  }
}