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 */ 17 18declare(strict_types=1); 19 20namespace Fisharebest\Webtrees\Report; 21 22use DomainException; 23use Exception; 24 25/** 26 * Class ReportParserBase 27 */ 28class ReportParserBase 29{ 30 /** @var resource The XML parser */ 31 protected $xml_parser; 32 33 /** @var string Text contents of tags */ 34 protected $text = ''; 35 36 /** 37 * Create a parser for a report 38 * 39 * @param string $report The XML filename 40 * 41 * @throws Exception 42 */ 43 public function __construct(string $report) 44 { 45 $this->xml_parser = xml_parser_create(); 46 47 xml_parser_set_option($this->xml_parser, XML_OPTION_CASE_FOLDING, false); 48 49 xml_set_element_handler( 50 $this->xml_parser, 51 function ($parser, string $name, array $attrs): void { 52 $this->startElement($parser, $name, $attrs); 53 }, 54 function ($parser, string $name): void { 55 $this->endElement($parser, $name); 56 } 57 ); 58 59 xml_set_character_data_handler( 60 $this->xml_parser, 61 function ($parser, string $data): void { 62 $this->characterData($parser, $data); 63 } 64 ); 65 66 $fp = fopen($report, 'rb'); 67 68 if ($fp === false) { 69 throw new Exception('Cannot open ' . $report); 70 } 71 72 while ($data = fread($fp, 4096)) { 73 if (!xml_parse($this->xml_parser, $data, feof($fp))) { 74 throw new DomainException(sprintf( 75 'XML error: %s at line %d', 76 xml_error_string(xml_get_error_code($this->xml_parser)), 77 xml_get_current_line_number($this->xml_parser) 78 )); 79 } 80 } 81 82 fclose($fp); 83 84 xml_parser_free($this->xml_parser); 85 } 86 87 /** 88 * XML handler for an opening (or self-closing) tag. 89 * 90 * @param resource $parser The resource handler for the xml parser 91 * @param string $name The name of the xml element parsed 92 * @param string[] $attrs An array of key value pairs for the attributes 93 * 94 * @return void 95 */ 96 protected function startElement($parser, string $name, array $attrs): void 97 { 98 $method = $name . 'StartHandler'; 99 100 if (method_exists($this, $method)) { 101 $this->$method($attrs); 102 } 103 } 104 105 /** 106 * XML handler for a closing tag. 107 * 108 * @param resource $parser the resource handler for the xml parser 109 * @param string $name the name of the xml element parsed 110 * 111 * @return void 112 */ 113 protected function endElement($parser, string $name): void 114 { 115 $method = $name . 'EndHandler'; 116 117 if (method_exists($this, $method)) { 118 $this->$method(); 119 } 120 } 121 122 /** 123 * XML handler for character data. 124 * 125 * @param resource $parser The resource handler for the xml parser 126 * @param string $data The name of the xml element parsed 127 * 128 * @return void 129 */ 130 protected function characterData($parser, $data): void 131 { 132 $this->text .= $data; 133 } 134} 135