comparison sites/all/libraries/ARC2/arc/parsers/ARC2_RDFXMLParser.php @ 4:ce11bbd8f642

added modules
author danieleb <danielebarchiesi@me.com>
date Thu, 19 Sep 2013 10:38:44 +0100
parents
children
comparison
equal deleted inserted replaced
3:b28be78d8160 4:ce11bbd8f642
1 <?php
2 /**
3 * ARC2 RDF/XML Parser
4 *
5 * @author Benjamin Nowack <bnowack@semsol.com>
6 * @license http://arc.semsol.org/license
7 * @homepage <http://arc.semsol.org/>
8 * @package ARC2
9 */
10
11 ARC2::inc('RDFParser');
12
13 class ARC2_RDFXMLParser extends ARC2_RDFParser {
14
15 function __construct($a, &$caller) {
16 parent::__construct($a, $caller);
17 }
18
19 function __init() {/* reader */
20 parent::__init();
21 $this->encoding = $this->v('encoding', false, $this->a);
22 $this->state = 0;
23 $this->x_lang = '';
24 $this->x_base = $this->base;
25 $this->xml = 'http://www.w3.org/XML/1998/namespace';
26 $this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
27 $this->nsp = array($this->xml => 'xml', $this->rdf => 'rdf');
28 $this->s_stack = array();
29 $this->s_count = 0;
30 $this->target_encoding = '';
31 }
32
33 /* */
34
35 function parse($path, $data = '', $iso_fallback = false) {
36 /* reader */
37 if (!$this->v('reader')) {
38 ARC2::inc('Reader');
39 $this->reader = new ARC2_Reader($this->a, $this);
40 }
41 $this->reader->setAcceptHeader('Accept: application/rdf+xml; q=0.9, */*; q=0.1');
42 $this->reader->activate($path, $data);
43 $this->x_base = isset($this->a['base']) && $this->a['base'] ? $this->a['base'] : $this->reader->base;
44 /* xml parser */
45 $this->initXMLParser();
46 /* parse */
47 $first = true;
48 while ($d = $this->reader->readStream()) {
49 if (!$this->keep_time_limit) @set_time_limit($this->v('time_limit', 60, $this->a));
50 if ($iso_fallback && $first) {
51 $d = '<?xml version="1.0" encoding="ISO-8859-1"?>' . "\n" . preg_replace('/^\<\?xml [^\>]+\?\>\s*/s', '', $d);
52 $first = false;
53 }
54 if (!xml_parse($this->xml_parser, $d, false)) {
55 $error_str = xml_error_string(xml_get_error_code($this->xml_parser));
56 $line = xml_get_current_line_number($this->xml_parser);
57 $this->tmp_error = 'XML error: "' . $error_str . '" at line ' . $line . ' (parsing as ' . $this->getEncoding() . ')';
58 if (!$iso_fallback && preg_match("/Invalid character/i", $error_str)) {
59 xml_parser_free($this->xml_parser);
60 unset($this->xml_parser);
61 $this->reader->closeStream();
62 $this->__init();
63 $this->encoding = 'ISO-8859-1';
64 unset($this->xml_parser);
65 unset($this->reader);
66 return $this->parse($path, $data, true);
67 }
68 else {
69 return $this->addError($this->tmp_error);
70 }
71 }
72 }
73 $this->target_encoding = xml_parser_get_option($this->xml_parser, XML_OPTION_TARGET_ENCODING);
74 xml_parser_free($this->xml_parser);
75 $this->reader->closeStream();
76 unset($this->reader);
77 return $this->done();
78 }
79
80 /* */
81
82 function initXMLParser() {
83 if (!isset($this->xml_parser)) {
84 $enc = preg_match('/^(utf\-8|iso\-8859\-1|us\-ascii)$/i', $this->getEncoding(), $m) ? $m[1] : 'UTF-8';
85 $parser = xml_parser_create_ns($enc, '');
86 xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
87 xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
88 xml_set_element_handler($parser, 'open', 'close');
89 xml_set_character_data_handler($parser, 'cdata');
90 xml_set_start_namespace_decl_handler($parser, 'nsDecl');
91 xml_set_object($parser, $this);
92 $this->xml_parser = $parser;
93 }
94 }
95
96 /* */
97
98 function getEncoding($src = 'config') {
99 if ($src == 'parser') {
100 return $this->target_encoding;
101 }
102 elseif (($src == 'config') && $this->encoding) {
103 return $this->encoding;
104 }
105 return $this->reader->getEncoding();
106 }
107
108 /* */
109
110 function getTriples() {
111 return $this->v('triples', array());
112 }
113
114 function countTriples() {
115 return $this->t_count;
116 }
117
118 /* */
119
120 function pushS(&$s) {
121 $s['pos'] = $this->s_count;
122 $this->s_stack[$this->s_count] = $s;
123 $this->s_count++;
124 }
125
126 function popS(){/* php 4.0.x-safe */
127 $r = array();
128 $this->s_count--;
129 for ($i = 0, $i_max = $this->s_count; $i < $i_max; $i++) {
130 $r[$i] = $this->s_stack[$i];
131 }
132 $this->s_stack = $r;
133 }
134
135 function updateS($s) {
136 $this->s_stack[$s['pos']] = $s;
137 }
138
139 function getParentS() {
140 return ($this->s_count && isset($this->s_stack[$this->s_count - 1])) ? $this->s_stack[$this->s_count - 1] : false;
141 }
142
143 function getParentXBase() {
144 if ($p = $this->getParentS()) {
145 return isset($p['p_x_base']) && $p['p_x_base'] ? $p['p_x_base'] : (isset($p['x_base']) ? $p['x_base'] : '');
146 }
147 return $this->x_base;
148 }
149
150 function getParentXLang() {
151 if ($p = $this->getParentS()) {
152 return isset($p['p_x_lang']) && $p['p_x_lang'] ? $p['p_x_lang'] : (isset($p['x_lang']) ? $p['x_lang'] : '');
153 }
154 return $this->x_lang;
155 }
156
157 /* */
158
159 function addT($s, $p, $o, $s_type, $o_type, $o_dt = '', $o_lang = '') {
160 //echo "-----\nadding $s / $p / $o\n-----\n";
161 $t = array('s' => $s, 'p' => $p, 'o' => $o, 's_type' => $s_type, 'o_type' => $o_type, 'o_datatype' => $o_dt, 'o_lang' => $o_lang);
162 if ($this->skip_dupes) {
163 $h = md5(serialize($t));
164 if (!isset($this->added_triples[$h])) {
165 $this->triples[$this->t_count] = $t;
166 $this->t_count++;
167 $this->added_triples[$h] = true;
168 }
169 }
170 else {
171 $this->triples[$this->t_count] = $t;
172 $this->t_count++;
173 }
174 }
175
176 function reify($t, $s, $p, $o, $s_type, $o_type, $o_dt = '', $o_lang = '') {
177 $this->addT($t, $this->rdf.'type', $this->rdf.'Statement', 'uri', 'uri');
178 $this->addT($t, $this->rdf.'subject', $s, 'uri', $s_type);
179 $this->addT($t, $this->rdf.'predicate', $p, 'uri', 'uri');
180 $this->addT($t, $this->rdf.'object', $o, 'uri', $o_type, $o_dt, $o_lang);
181 }
182
183 /* */
184
185 function open($p, $t, $a) {
186 //echo "state is $this->state\n";
187 //echo "opening $t\n";
188 switch($this->state) {
189 case 0: return $this->h0Open($t, $a);
190 case 1: return $this->h1Open($t, $a);
191 case 2: return $this->h2Open($t, $a);
192 case 4: return $this->h4Open($t, $a);
193 case 5: return $this->h5Open($t, $a);
194 case 6: return $this->h6Open($t, $a);
195 default: $this->addError('open() called at state ' . $this->state . ' in '.$t);
196 }
197 }
198
199 function close($p, $t) {
200 //echo "state is $this->state\n";
201 //echo "closing $t\n";
202 switch($this->state){
203 case 1: return $this->h1Close($t);
204 case 2: return $this->h2Close($t);
205 case 3: return $this->h3Close($t);
206 case 4: return $this->h4Close($t);
207 case 5: return $this->h5Close($t);
208 case 6: return $this->h6Close($t);
209 default: $this->addError('close() called at state ' . $this->state . ' in '.$t);
210 }
211 }
212
213 function cdata($p, $d) {
214 //echo "state is $this->state\n";
215 //echo "cdata\n";
216 switch($this->state){
217 case 4: return $this->h4Cdata($d);
218 case 6: return $this->h6Cdata($d);
219 default: return false;
220 }
221 }
222
223 function nsDecl($p, $prf, $uri) {
224 $this->nsp[$uri] = isset($this->nsp[$uri]) ? $this->nsp[$uri] : $prf;
225 }
226
227 /* */
228
229 function h0Open($t, $a) {
230 $this->x_lang = $this->v($this->xml.'lang', $this->x_lang, $a);
231 $this->x_base = $this->calcURI($this->v($this->xml.'base', $this->x_base, $a));
232 $this->state = 1;
233 if ($t !== $this->rdf.'RDF') {
234 $this->h1Open($t, $a);
235 }
236 }
237
238 /* */
239
240 function h1Open($t, $a) {
241 $s = array(
242 'x_base' => isset($a[$this->xml.'base']) ? $this->calcURI($a[$this->xml.'base']) : $this->getParentXBase(),
243 'x_lang' => isset($a[$this->xml.'lang']) ? $a[$this->xml.'lang'] : $this->getParentXLang(),
244 'li_count' => 0,
245 );
246 /* ID */
247 if (isset($a[$this->rdf.'ID'])) {
248 $s['type'] = 'uri';
249 $s['value'] = $this->calcURI('#'.$a[$this->rdf.'ID'], $s['x_base']);
250 }
251 /* about */
252 elseif (isset($a[$this->rdf.'about'])) {
253 $s['type'] = 'uri';
254 $s['value'] = $this->calcURI($a[$this->rdf.'about'], $s['x_base']);
255 }
256 /* bnode */
257 else {
258 $s['type'] = 'bnode';
259 if (isset($a[$this->rdf.'nodeID'])) {
260 $s['value'] = '_:'.$a[$this->rdf.'nodeID'];
261 }
262 else {
263 $s['value'] = $this->createBnodeID();
264 }
265 }
266 /* sub-node */
267 if ($this->state === 4) {
268 $sup_s = $this->getParentS();
269 /* new collection */
270 if (isset($sup_s['o_is_coll']) && $sup_s['o_is_coll']) {
271 $coll = array('value' => $this->createBnodeID(), 'type' => 'bnode', 'is_coll' => true, 'x_base' => $s['x_base'], 'x_lang' => $s['x_lang']);
272 $this->addT($sup_s['value'], $sup_s['p'], $coll['value'], $sup_s['type'], $coll['type']);
273 $this->addT($coll['value'], $this->rdf . 'first', $s['value'], $coll['type'], $s['type']);
274 $this->pushS($coll);
275 }
276 /* new entry in existing coll */
277 elseif (isset($sup_s['is_coll']) && $sup_s['is_coll']) {
278 $coll = array('value' => $this->createBnodeID(), 'type' => 'bnode', 'is_coll' => true, 'x_base' => $s['x_base'], 'x_lang' => $s['x_lang']);
279 $this->addT($sup_s['value'], $this->rdf . 'rest', $coll['value'], $sup_s['type'], $coll['type']);
280 $this->addT($coll['value'], $this->rdf . 'first', $s['value'], $coll['type'], $s['type']);
281 $this->pushS($coll);
282 }
283 /* normal sub-node */
284 elseif(isset($sup_s['p']) && $sup_s['p']) {
285 $this->addT($sup_s['value'], $sup_s['p'], $s['value'], $sup_s['type'], $s['type']);
286 }
287 }
288 /* typed node */
289 if ($t !== $this->rdf.'Description') {
290 $this->addT($s['value'], $this->rdf.'type', $t, $s['type'], 'uri');
291 }
292 /* (additional) typing attr */
293 if (isset($a[$this->rdf.'type'])) {
294 $this->addT($s['value'], $this->rdf.'type', $a[$this->rdf.'type'], $s['type'], 'uri');
295 }
296 /* Seq|Bag|Alt */
297 if (in_array($t, array($this->rdf.'Seq', $this->rdf.'Bag', $this->rdf.'Alt'))) {
298 $s['is_con'] = true;
299 }
300 /* any other attrs (skip rdf and xml, except rdf:_, rdf:value, rdf:Seq) */
301 foreach($a as $k => $v) {
302 if (((strpos($k, $this->xml) === false) && (strpos($k, $this->rdf) === false)) || preg_match('/(\_[0-9]+|value|Seq|Bag|Alt|Statement|Property|List)$/', $k)) {
303 if (strpos($k, ':')) {
304 $this->addT($s['value'], $k, $v, $s['type'], 'literal', '', $s['x_lang']);
305 }
306 }
307 }
308 $this->pushS($s);
309 $this->state = 2;
310 }
311
312 /* */
313
314 function h2Open($t, $a) {
315 $s = $this->getParentS();
316 foreach (array('p_x_base', 'p_x_lang', 'p_id', 'o_is_coll') as $k) {
317 unset($s[$k]);
318 }
319 /* base */
320 if (isset($a[$this->xml.'base'])) {
321 $s['p_x_base'] = $this->calcURI($a[$this->xml.'base'], $s['x_base']);
322 }
323 $b = isset($s['p_x_base']) && $s['p_x_base'] ? $s['p_x_base'] : $s['x_base'];
324 /* lang */
325 if (isset($a[$this->xml.'lang'])) {
326 $s['p_x_lang'] = $a[$this->xml.'lang'];
327 }
328 $l = isset($s['p_x_lang']) && $s['p_x_lang'] ? $s['p_x_lang'] : $s['x_lang'];
329 /* adjust li */
330 if ($t === $this->rdf.'li') {
331 $s['li_count']++;
332 $t = $this->rdf.'_'.$s['li_count'];
333 }
334 /* set p */
335 $s['p'] = $t;
336 /* reification */
337 if (isset($a[$this->rdf.'ID'])) {
338 $s['p_id'] = $a[$this->rdf.'ID'];
339 }
340 $o = array('value' => '', 'type' => '', 'x_base' => $b, 'x_lang' => $l);
341 /* resource/rdf:resource */
342 if (isset($a['resource'])) {
343 $a[$this->rdf . 'resource'] = $a['resource'];
344 unset($a['resource']);
345 }
346 if (isset($a[$this->rdf.'resource'])) {
347 $o['value'] = $this->calcURI($a[$this->rdf.'resource'], $b);
348 $o['type'] = 'uri';
349 $this->addT($s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
350 /* type */
351 if (isset($a[$this->rdf.'type'])) {
352 $this->addT($o['value'], $this->rdf.'type', $a[$this->rdf.'type'], 'uri', 'uri');
353 }
354 /* reification */
355 if (isset($s['p_id'])) {
356 $this->reify($this->calcURI('#'.$s['p_id'], $b), $s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
357 unset($s['p_id']);
358 }
359 $this->state = 3;
360 }
361 /* named bnode */
362 elseif (isset($a[$this->rdf.'nodeID'])) {
363 $o['value'] = '_:' . $a[$this->rdf.'nodeID'];
364 $o['type'] = 'bnode';
365 $this->addT($s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
366 $this->state = 3;
367 /* reification */
368 if (isset($s['p_id'])) {
369 $this->reify($this->calcURI('#'.$s['p_id'], $b), $s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
370 }
371 }
372 /* parseType */
373 elseif (isset($a[$this->rdf.'parseType'])) {
374 if ($a[$this->rdf.'parseType'] === 'Literal') {
375 $s['o_xml_level'] = 0;
376 $s['o_xml_data'] = '';
377 $s['p_xml_literal_level'] = 0;
378 $s['ns'] = array();
379 $this->state = 6;
380 }
381 elseif ($a[$this->rdf.'parseType'] === 'Resource') {
382 $o['value'] = $this->createBnodeID();
383 $o['type'] = 'bnode';
384 $o['has_closing_tag'] = 0;
385 $this->addT($s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
386 $this->pushS($o);
387 /* reification */
388 if (isset($s['p_id'])) {
389 $this->reify($this->calcURI('#'.$s['p_id'], $b), $s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
390 unset($s['p_id']);
391 }
392 $this->state = 2;
393 }
394 elseif ($a[$this->rdf.'parseType'] === 'Collection') {
395 $s['o_is_coll'] = true;
396 $this->state = 4;
397 }
398 }
399 /* sub-node or literal */
400 else {
401 $s['o_cdata'] = '';
402 if (isset($a[$this->rdf.'datatype'])) {
403 $s['o_datatype'] = $a[$this->rdf.'datatype'];
404 }
405 $this->state = 4;
406 }
407 /* any other attrs (skip rdf and xml) */
408 foreach($a as $k => $v) {
409 if (((strpos($k, $this->xml) === false) && (strpos($k, $this->rdf) === false)) || preg_match('/(\_[0-9]+|value)$/', $k)) {
410 if (strpos($k, ':')) {
411 if (!$o['value']) {
412 $o['value'] = $this->createBnodeID();
413 $o['type'] = 'bnode';
414 $this->addT($s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
415 }
416 /* reification */
417 if (isset($s['p_id'])) {
418 $this->reify($this->calcURI('#'.$s['p_id'], $b), $s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
419 unset($s['p_id']);
420 }
421 $this->addT($o['value'], $k, $v, $o['type'], 'literal');
422 $this->state = 3;
423 }
424 }
425 }
426 $this->updateS($s);
427 }
428
429 /* */
430
431 function h4Open($t, $a) {
432 return $this->h1Open($t, $a);
433 }
434
435 /* */
436
437 function h5Open($t, $a) {
438 $this->state = 4;
439 return $this->h4Open($t, $a);
440 }
441
442 /* */
443
444 function h6Open($t, $a) {
445 $s = $this->getParentS();
446 $data = isset($s['o_xml_data']) ? $s['o_xml_data'] : '';
447 $ns = isset($s['ns']) ? $s['ns'] : array();
448 $parts = $this->splitURI($t);
449 if ((count($parts) === 1) || empty($parts[1])) {
450 $data .= '<'.$t;
451 }
452 else {
453 $ns_uri = $parts[0];
454 $name = $parts[1];
455 if (!isset($this->nsp[$ns_uri])) {
456 foreach ($this->nsp as $tmp1 => $tmp2) {
457 if (strpos($t, $tmp1) === 0) {
458 $ns_uri = $tmp1;
459 $name = substr($t, strlen($tmp1));
460 break;
461 }
462 }
463 }
464 $nsp = $this->nsp[$ns_uri];
465 $data .= $nsp ? '<' . $nsp . ':' . $name : '<' . $name;
466 /* ns */
467 if (!isset($ns[$nsp.'='.$ns_uri]) || !$ns[$nsp.'='.$ns_uri]) {
468 $data .= $nsp ? ' xmlns:'.$nsp.'="'.$ns_uri.'"' : ' xmlns="'.$ns_uri.'"';
469 $ns[$nsp.'='.$ns_uri] = true;
470 $s['ns'] = $ns;
471 }
472 }
473 foreach ($a as $k => $v) {
474 $parts = $this->splitURI($k);
475 if (count($parts) === 1) {
476 $data .= ' '.$k.'="'.$v.'"';
477 }
478 else {
479 $ns_uri = $parts[0];
480 $name = $parts[1];
481 $nsp = $this->v($ns_uri, '', $this->nsp);
482 $data .= $nsp ? ' '.$nsp.':'.$name.'="'.$v.'"' : ' '.$name.'="'.$v.'"' ;
483 }
484 }
485 $data .= '>';
486 $s['o_xml_data'] = $data;
487 $s['o_xml_level'] = isset($s['o_xml_level']) ? $s['o_xml_level'] + 1 : 1;
488 if ($t == $s['p']) {/* xml container prop */
489 $s['p_xml_literal_level'] = isset($s['p_xml_literal_level']) ? $s['p_xml_literal_level'] + 1 : 1;
490 }
491 $this->updateS($s);
492 }
493
494 /* */
495
496 function h1Close($t) {/* end of doc */
497 $this->state = 0;
498 }
499
500 /* */
501
502 function h2Close($t) {/* expecting a prop, getting a close */
503 if ($s = $this->getParentS()) {
504 $has_closing_tag = (isset($s['has_closing_tag']) && !$s['has_closing_tag']) ? 0 : 1;
505 $this->popS();
506 $this->state = 5;
507 if ($s = $this->getParentS()) {/* new s */
508 if (!isset($s['p']) || !$s['p']) {/* p close after collection|parseType=Resource|node close after p close */
509 $this->state = $this->s_count ? 4 : 1;
510 if (!$has_closing_tag) {
511 $this->state = 2;
512 }
513 }
514 elseif (!$has_closing_tag) {
515 $this->state = 2;
516 }
517 }
518 }
519 }
520
521 /* */
522
523 function h3Close($t) {/* p close */
524 $this->state = 2;
525 }
526
527 /* */
528
529 function h4Close($t) {/* empty p | pClose after cdata | pClose after collection */
530 if ($s = $this->getParentS()) {
531 $b = isset($s['p_x_base']) && $s['p_x_base'] ? $s['p_x_base'] : (isset($s['x_base']) ? $s['x_base'] : '');
532 if (isset($s['is_coll']) && $s['is_coll']) {
533 $this->addT($s['value'], $this->rdf . 'rest', $this->rdf . 'nil', $s['type'], 'uri');
534 /* back to collection start */
535 while ((!isset($s['p']) || ($s['p'] != $t))) {
536 $sub_s = $s;
537 $this->popS();
538 $s = $this->getParentS();
539 }
540 /* reification */
541 if (isset($s['p_id']) && $s['p_id']) {
542 $this->reify($this->calcURI('#'.$s['p_id'], $b), $s['value'], $s['p'], $sub_s['value'], $s['type'], $sub_s['type']);
543 }
544 unset($s['p']);
545 $this->updateS($s);
546 }
547 else {
548 $dt = isset($s['o_datatype']) ? $s['o_datatype'] : '';
549 $l = isset($s['p_x_lang']) && $s['p_x_lang'] ? $s['p_x_lang'] : (isset($s['x_lang']) ? $s['x_lang'] : '');
550 $o = array('type' => 'literal', 'value' => $s['o_cdata']);
551 $this->addT($s['value'], $s['p'], $o['value'], $s['type'], $o['type'], $dt, $l);
552 /* reification */
553 if (isset($s['p_id']) && $s['p_id']) {
554 $this->reify($this->calcURI('#'.$s['p_id'], $b), $s['value'], $s['p'], $o['value'], $s['type'], $o['type'], $dt, $l);
555 }
556 unset($s['o_cdata']);
557 unset($s['o_datatype']);
558 unset($s['p']);
559 $this->updateS($s);
560 }
561 $this->state = 2;
562 }
563 }
564
565 /* */
566
567 function h5Close($t) {/* p close */
568 if ($s = $this->getParentS()) {
569 unset($s['p']);
570 $this->updateS($s);
571 $this->state = 2;
572 }
573 }
574
575 /* */
576
577 function h6Close($t) {
578 if ($s = $this->getParentS()) {
579 $l = isset($s['p_x_lang']) && $s['p_x_lang'] ? $s['p_x_lang'] : (isset($s['x_lang']) ? $s['x_lang'] : '');
580 $data = $s['o_xml_data'];
581 $level = $s['o_xml_level'];
582 if ($level === 0) {/* pClose */
583 $this->addT($s['value'], $s['p'], trim($data, ' '), $s['type'], 'literal', $this->rdf.'XMLLiteral', $l);
584 unset($s['o_xml_data']);
585 $this->state = 2;
586 }
587 else {
588 $parts = $this->splitURI($t);
589 if ((count($parts) === 1) || empty($parts[1])) {
590 $data .= '</'.$t.'>';
591 }
592 else {
593 $ns_uri = $parts[0];
594 $name = $parts[1];
595 if (!isset($this->nsp[$ns_uri])) {
596 foreach ($this->nsp as $tmp1 => $tmp2) {
597 if (strpos($t, $tmp1) === 0) {
598 $ns_uri = $tmp1;
599 $name = substr($t, strlen($tmp1));
600 break;
601 }
602 }
603 }
604 $nsp = $this->nsp[$ns_uri];
605 $data .= $nsp ? '</'.$nsp.':'.$name.'>' : '</'.$name.'>';
606 }
607 $s['o_xml_data'] = $data;
608 $s['o_xml_level'] = $level - 1;
609 if ($t == $s['p']) {/* xml container prop */
610 $s['p_xml_literal_level']--;
611 }
612 }
613 $this->updateS($s);
614 }
615 }
616
617 /* */
618
619 function h4Cdata($d) {
620 if ($s = $this->getParentS()) {
621 $s['o_cdata'] = isset($s['o_cdata']) ? $s['o_cdata'] . $d : $d;
622 $this->updateS($s);
623 }
624 }
625
626 /* */
627
628 function h6Cdata($d) {
629 if ($s = $this->getParentS()) {
630 if (isset($s['o_xml_data']) || preg_match("/[\n\r]/", $d) || trim($d)) {
631 $d = htmlspecialchars($d, ENT_NOQUOTES);
632 $s['o_xml_data'] = isset($s['o_xml_data']) ? $s['o_xml_data'] . $d : $d;
633 }
634 $this->updateS($s);
635 }
636 }
637
638 /* */
639
640 }