1<?php 2 3/** 4 * webtrees: online genealogy 5 * Copyright (C) 2019 webtrees development team 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17declare(strict_types=1); 18 19namespace Fisharebest\Webtrees\Report; 20 21use DomainException; 22use Exception; 23 24/** 25 * Class ReportParserBase 26 */ 27class ReportParserBase 28{ 29 /** @var resource The XML parser */ 30 protected $xml_parser; 31 32 /** @var string Text contents of tags */ 33 protected $text = ''; 34 35 /** 36 * Create a parser for a report 37 * 38 * @param string $report The XML filename 39 * 40 * @throws Exception 41 */ 42 public function __construct(string $report) 43 { 44 $this->xml_parser = xml_parser_create(); 45 46 xml_parser_set_option($this->xml_parser, XML_OPTION_CASE_FOLDING, false); 47 48 xml_set_element_handler( 49 $this->xml_parser, 50 function ($parser, string $name, array $attrs): void { 51 $this->startElement($parser, $name, $attrs); 52 }, 53 function ($parser, string $name): void { 54 $this->endElement($parser, $name); 55 } 56 ); 57 58 xml_set_character_data_handler( 59 $this->xml_parser, 60 function ($parser, string $data): void { 61 $this->characterData($parser, $data); 62 } 63 ); 64 65 $fp = fopen($report, 'rb'); 66 67 if ($fp === false) { 68 throw new Exception('Cannot open ' . $report); 69 } 70 71 while ($data = fread($fp, 4096)) { 72 if (!xml_parse($this->xml_parser, $data, feof($fp))) { 73 throw new DomainException(sprintf( 74 'XML error: %s at line %d', 75 xml_error_string(xml_get_error_code($this->xml_parser)), 76 xml_get_current_line_number($this->xml_parser) 77 )); 78 } 79 } 80 81 fclose($fp); 82 83 xml_parser_free($this->xml_parser); 84 } 85 86 /** 87 * XML handler for an opening (or self-closing) tag. 88 * 89 * @param resource $parser The resource handler for the xml parser 90 * @param string $name The name of the xml element parsed 91 * @param string[] $attrs An array of key value pairs for the attributes 92 * 93 * @return void 94 */ 95 protected function startElement($parser, string $name, array $attrs): void 96 { 97 $method = $name . 'StartHandler'; 98 99 if (method_exists($this, $method)) { 100 $this->$method($attrs); 101 } 102 } 103 104 /** 105 * XML handler for a closing tag. 106 * 107 * @param resource $parser the resource handler for the xml parser 108 * @param string $name the name of the xml element parsed 109 * 110 * @return void 111 */ 112 protected function endElement($parser, string $name): void 113 { 114 $method = $name . 'EndHandler'; 115 116 if (method_exists($this, $method)) { 117 $this->$method(); 118 } 119 } 120 121 /** 122 * XML handler for character data. 123 * 124 * @param resource $parser The resource handler for the xml parser 125 * @param string $data The name of the xml element parsed 126 * 127 * @return void 128 */ 129 protected function characterData($parser, $data): void 130 { 131 $this->text .= $data; 132 } 133} 134