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