📄 xmd.lib.php
字号:
// - parsing 388 KB -> 0.94 sec // - caching 298 KB <- 1.63 sec: 11387 elements, 5137 string nodes // - uncache 298 KB -> 0.42 sec // - $this->children[$n][] in a loop is quicker than a temporary array // $children[] and copying $this->children[$n] = $children after the loop // - incremental operator ++$numptr is not quicker than ($numptr += 1) // - numbers & textstring: more compact with base64_encode(gzcompress()) function xmd_cache() // store all data in numbers+names+textstring { $this->numbers = array(); $this->textstring = ''; $this->_strings = 0; // add all element- and attributenames to names - see below for ($n = 0; $n <= $this->_last; $n++) { $this->numbers[] = count($this->children[$n]); foreach ($this->children[$n] as $ch) { if (is_string($ch)) { $this->numbers[] = 0; $this->_strings += 1; $this->numbers[] = strlen($ch); $this->textstring .= $ch; } else { $this->numbers[] = ($ch-$n); // more compact than $ch } } $this->numbers[] = count($this->attributes[$n]); foreach ($this->attributes[$n] as $name => $value) { $this->numbers[] = $this->_lookup($name); $this->numbers[] = $this->atns[$n][$name]; $this->numbers[] = strlen($value); $this->textstring .= $value; } $this->numbers[] = $this->_lookup($this->name[$n]); $this->numbers[] = $this->ns[$n]; $this->numbers[] = $n - $this->parent[$n]; // more compact } } function xmddoc($strings, $charset = 'ISO-8859-1', $textstring = '') { $this->parent = array(); $this->name = array(); $this->ns = array(); $this->attributes = array(); $this->atns = array(); $this->children = array(); $this->error = ''; $this->_nesting = array(); $this->_ns = array(); $this->_last = -1; $this->_nsp = array(); foreach (explode(',', 'eb,tn,eg,ut,as,ne,jt,ne,ah,en,er') as $pfx) $this->_nsp[$pfx] = ''; if (is_array($charset)) // new xmddoc($names, $numbers, $textstring) { $this->names = $strings; $this->numbers = $charset; $this->textstring = $textstring; $this->_uncache(); return; } $this->names = array(); $this->_lookup(''); // empty ns is number 0 $xml_parser = xml_parser_create_ns($charset, ':'); xml_set_object($xml_parser,$this); // instead of ...,&$this // See PHP manual: Passing by Reference vs. xml_set_object xml_set_element_handler($xml_parser, '_startElement', '_endElement'); xml_set_character_data_handler($xml_parser, '_cData'); xml_set_start_namespace_decl_handler($xml_parser, '_startNs'); // xml_set_end_namespace_decl_handler($xml_parser, '_endNs'); // xml_set_default_handler ($xml_parser, ''); xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, FALSE); if (!is_array($strings)) $strings = array($strings); if (count($strings) && (substr($strings[0], 0, 5) != '<?xml') && !xml_parse($xml_parser, '<?xml version="1.0" encoding="' . $charset . '"?>', FALSE)) { $this->error = 'Encoding ' . $charset . ': ' . xml_error_string(xml_get_error_code($xml_parser)); $strings = array(); } foreach ($strings as $s) { if (substr($s, -1) != "\n") $s .= "\n"; if (!xml_parse($xml_parser, $s, FALSE)) { $errCode = xml_get_error_code($xml_parser); $this->error = 'Line '. xml_get_current_line_number($xml_parser) . ' (c' . xml_get_current_column_number($xml_parser) . // ', b' . xml_get_current_byte_index($xml_parser) . '): error ' . $errCode . '= ' . xml_error_string($errCode); break; // the error string is English... } } xml_parse($xml_parser, '', TRUE); xml_parser_free($xml_parser); } // internal methods function _sibnum($parent, $name = '', $pmn = 'N') // sibling or number { if ($parent <= 0) return -1; $found = FALSE; $prev = -1; $next = -1; $num = 0; foreach ($this->children[$this->parent[$parent]] as $child) { if (is_string($child)) continue; $name_ok = $name ? ($this->name[$child] == $name) : TRUE; if ($found && $name_ok) { $next = $child; break; } elseif ($parent === $child) { $num ++; $found = TRUE; } elseif ($name_ok) { $num ++; $prev = $child; } } return ($pmn == '-') ? $prev : (($pmn == '+') ? $next : $num); } function _uncache() // restore all data from numbers+names+textstring { $n = -1; $numptr = -1; $txtptr = 0; $count = count($this->numbers); $A0 = array(); // believe it or not, this makes the loops quicker! while (++$numptr < $count) { $n++; if (($countdown = $this->numbers[$numptr]) == 0) { $this->children[$n] = $A0; } else while (--$countdown >= 0) { if (($chc = $this->numbers[++$numptr]) == 0) { $this->children[$n][] = substr($this->textstring, $txtptr, ($len = $this->numbers[++$numptr])); $txtptr += $len; } else { $this->children[$n][] = $n + $chc; } } if (($countdown = $this->numbers[++$numptr]) == 0) { $this->attributes[$n] = $this->atns[$n] = $A0; } else while (--$countdown >= 0) { $name = $this->names[$this->numbers[++$numptr]]; $this->atns[$n][$name] = $this->numbers[++$numptr]; $this->attributes[$n][$name] = substr($this->textstring, $txtptr, ($len = $this->numbers[++$numptr])); $txtptr += $len; } $this->name[$n] = $this->names[$this->numbers[++$numptr]]; $this->ns[$n] = $this->numbers[++$numptr]; $this->parent[$n] = $n - $this->numbers[++$numptr]; } $this->_last = $n; } function _startElement($parser, $name, $attribs) { $level = count($this->_nesting); $parent = ($level == 0) ? -1 : $this->_nesting[$level-1]; $child = $this->xmd_add_element($name, $parent, array_merge($attribs, $this->_ns)); $this->_nesting[] = $child; $this->_ns = array(); $this->_concat = FALSE; // see _cData } function _endElement($parser, $name) { array_pop($this->_nesting); $this->_concat = FALSE; } function _cData($parser, $data) { if (!ltrim($data)) return; // empty line, or whitespace preceding <tag> $level = count($this->_nesting); $parent = ($level == 0) ? -1 : $this->_nesting[$level-1]; if ($parent >= 0) { $nc = count($this->children[$parent]); $pcs = ($nc > 0 && is_string($this->children[$parent][$nc - 1])); if ($pcs && strlen($data) == 1) $this->_concat = TRUE; // expat parser puts &xx; in a separate cData, try to re-assemble if ($pcs && $data{0} > '~') $this->_concat = TRUE; // PHP5 expat breaks before 8-bit characters if ($this->_concat) { $this->children[$parent][$nc - 1] .= $data; $this->_concat = (strlen($data) == 1); } else $this->children[$parent][] = $pcs ? "\n" . $data : $data; } } function _startNs($parser, $pfx, $uri) // called before _startElement { $this->_ns['xmlns' . ($pfx ? ':'.$pfx : '')] = $uri; $this->_nsp[$pfx] = $uri; } function _nsPfx($ppar, $uri) // find namespace prefix { while ($ppar >= 0) { foreach ($this->attributes[$ppar] as $name => $value) if (substr($name, 0, 5) == 'xmlns' && $value == $uri) { $pfxc = substr($name, 6) . substr($name, 5, 1); break 2; } $ppar = $this->parent[$ppar]; } if ($ppar >= 0) return $pfxc; if ($uri == '') return ''; if ($uri == 'http://www.w3.org/XML/1998/namespace') return 'xml:'; foreach($this->_nsp as $pfx => $used) if (!$used) break; $this->_nsp[$pfx] = $uri; $xmlnspfx = 'xmlns:' . $pfx; $this->attributes[0][$xmlnspfx] = $uri; $this->atns[0][$xmlnspfx] = 0; return $pfx . ':'; } function _lookup($name) // for namespaces + see cache { $where = array_search($name, $this->names); if ($where === FALSE || $where === NULL) { $where = count($this->names); $this->names[] = $name; } return $where; }}/*<!-- This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -->*/?>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -