1: <?php
2: 3: 4: 5: 6: 7: 8: 9:
10:
11: namespace Kotchasan;
12:
13: 14: 15: 16: 17: 18: 19:
20: class DOMParser
21: {
22: 23: 24: 25: 26:
27: protected $doms = array();
28:
29: 30: 31: 32: 33: 34:
35: public function __construct($html, $charset = 'utf-8')
36: {
37: $patt = array(
38: '/^(.*)<body[^>]{0,}>(.*)<\/body>(.*)$/is' => '\\2',
39: '#<(style|script)(.*?)>(.*?)</\\1>#is' => '',
40: '@<!--.*-->@is' => '',
41: '/<(\!|link|meta)[^>]+\>/i' => '',
42: '@>[\s\t]{0,}[\r\n]+[\s\t]{0,}<@' => '><',
43: '@[\s\t\r\n]{0,}<(\/?(br|hr|figure|figcaption|p|div|footer|article|section|blockquote|code|aside|navy|table|tr|td|th|thead|tbody|tfoot|caption|ul|ol|li|dl|dt|dd|h[1-6])[^>]{0,})>[\s\t\r\n]{0,}@i' => '<\\1>',
44: '@[\s\t]{0,}[\r\n]+[\s\t]{0,}@' => ' ',
45: );
46: $html = preg_replace(array_keys($patt), array_values($patt), $html);
47: if (strtolower($charset) != 'utf-8') {
48: $html = iconv('utf-8', $charset, $html);
49: }
50: $node = null;
51: foreach (preg_split('/<(.*)>/U', $html, -1, PREG_SPLIT_DELIM_CAPTURE) as $i => $e) {
52: if ($e != '') {
53: if ($i % 2 == 0) {
54:
55: if ($e != '') {
56: if ($node) {
57: $node->childNodes[] = new DOMNode('', $node, array(), $e);
58: } else {
59: $this->doms[] = new DOMNode('', $node, array(), $e);
60: }
61: }
62: } elseif ($e[0] == '/') {
63:
64: $node = $node->parentNode;
65: } elseif (preg_match('/^([a-zA-Z0-9]+)([\s]{0,}(.*))?$/', $e, $a2)) {
66:
67: $tag = strtoupper($a2[1]);
68:
69: $attributes = array();
70: if (!empty($a2[3]) && preg_match_all('/(\\w+)\s*=\\s*("[^"]*"|\'[^\']*\'|[^"\'\\s>]*)/', $a2[3], $matches, PREG_SET_ORDER)) {
71: foreach ($matches as $match) {
72: if (($match[2][0] == '"' || $match[2][0] == "'") && $match[2][0] == $match[2][strlen($match[2]) - 1]) {
73: $match[2] = substr($match[2], 1, -1);
74: }
75: $attributes[strtoupper($match[1])] = $match[2];
76: }
77: }
78: if ($tag == 'BR' || $tag == 'IMG' || $tag == 'INPUT' || $tag == 'HR') {
79: if ($node) {
80: $node->childNodes[] = new DOMNode($tag, $node, $attributes);
81: } else {
82: $this->doms[] = new DOMNode($tag, $node, $attributes);
83: }
84: } else {
85: $temp = $node;
86: $node = new DOMNode($tag, $temp, $attributes);
87: if ($temp) {
88: $temp->childNodes[] = $node;
89: } else {
90: $this->doms[] = $node;
91: }
92: }
93: }
94: }
95: }
96:
97: $currentNode = null;
98: foreach ($this->doms as $node) {
99: $node->previousSibling = $currentNode;
100: $this->populate($node);
101: if ($node->previousSibling) {
102: $node->previousSibling->nextSibling = $node;
103: }
104: $currentNode = $node;
105: }
106: }
107:
108: 109: 110: 111: 112: 113: 114:
115: public static function load($url)
116: {
117: $obj = new static(file_get_contents($url));
118:
119: return $obj;
120: }
121:
122: 123: 124: 125: 126:
127: public function nodes()
128: {
129: return $this->doms;
130: }
131:
132: 133: 134: 135: 136:
137: public function toHTML()
138: {
139: $html = '';
140: foreach ($this->doms as $node) {
141: $html .= $this->drawNode($node);
142: }
143:
144: return $html;
145: }
146:
147: 148: 149: 150: 151:
152: private function drawNode($node)
153: {
154: $html = '';
155: if ($node->nodeName == '') {
156: $html .= $node->nodeValue;
157: } else {
158: $prop = array();
159: foreach ($node->attributes as $k => $v) {
160: $prop[] = $k.'="'.$v.'"';
161: }
162: if ($node->nodeName == 'BR' || $node->nodeName == 'IMG') {
163: $html .= '<'.$node->nodeName.' '.implode(' ', $prop).'>';
164: } else {
165: $prop = empty($prop) ? '' : ' '.implode(' ', $prop);
166: $html .= '<'.$node->nodeName.$prop.'>';
167: if (empty($node->childNodes)) {
168: $html .= $node->nodeValue;
169: } else {
170: foreach ($node->childNodes as $child) {
171: $html .= $this->drawNode($child);
172: }
173: }
174: if ($node->previousSibling) {
175: $html .= '('.$node->previousSibling->nodeName.')';
176: }
177: $html .= '</'.$node->nodeName.'>';
178: }
179: }
180:
181: return $html;
182: }
183:
184: 185: 186: 187: 188:
189: private function populate($node)
190: {
191: $currentNode = null;
192: foreach ($node->childNodes as $item) {
193: $item->previousSibling = $currentNode;
194: foreach ($item->childNodes as $child) {
195: $this->populate($child);
196: if ($node->previousSibling) {
197: $node->previousSibling->nextSibling = $node;
198: }
199: }
200: $currentNode = $item;
201: }
202: }
203: }
204: