• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

voku / simple_html_dom / 24632839975

19 Apr 2026 03:42PM UTC coverage: 77.11% (+6.3%) from 70.769%
24632839975

push

github

web-flow
Merge pull request #135 from voku/copilot/fix-html-parsing-newline-issue

Preserve node HTML formatting when serializing nested elements

4 of 24 new or added lines in 1 file covered. (16.67%)

51 existing lines in 6 files now uncovered.

1654 of 2145 relevant lines covered (77.11%)

262.05 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

72.0
/src/voku/helper/XmlDomParser.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace voku\helper;
6

7
/**
8
 * @property-read string $plaintext
9
 *                                 <p>Get dom node's plain text.</p>
10
 *
11
 * @method static XmlDomParser file_get_xml($xml, $libXMLExtraOptions = null)
12
 *                                 <p>Load XML from file.</p>
13
 * @method static XmlDomParser str_get_xml($xml, $libXMLExtraOptions = null)
14
 *                                 <p>Load XML from string.</p>
15
 */
16
class XmlDomParser extends AbstractDomParser
17
{
18
    /**
19
     * @var callable|null
20
     *
21
     * @phpstan-var null|callable(string $cssSelectorString, string $xPathString, \DOMXPath, \voku\helper\XmlDomParser): string
22
     */
23
    private $callbackXPathBeforeQuery;
24

25
    /**
26
     * @var callable|null
27
     *
28
     * @phpstan-var null|callable(string $xmlString, \voku\helper\XmlDomParser): string
29
     */
30
    private $callbackBeforeCreateDom;
31

32
    /**
33
     * @var bool
34
     */
35
    private $autoRemoveXPathNamespaces = false;
36

37
    /**
38
     * @var bool
39
     */
40
    private $autoRegisterXPathNamespaces = false;
41

42
    /**
43
     * @var bool
44
     */
45
    private $reportXmlErrorsAsException = false;
46

47
    /**
48
     * @var string[]
49
     *
50
     * @phpstan-var array<string, string>
51
     */
52
    private $xPathNamespaces = [];
53

54
    /**
55
     * @param \DOMNode|SimpleXmlDomInterface|string $element HTML code or SimpleXmlDomInterface, \DOMNode
56
     */
57
    public function __construct($element = null)
58
    {
59
        $this->document = new \DOMDocument('1.0', $this->getEncoding());
133✔
60

61
        // DOMDocument settings
62
        $this->document->preserveWhiteSpace = true;
133✔
63
        $this->document->formatOutput = true;
133✔
64

65
        if ($element instanceof SimpleXmlDomInterface) {
133✔
66
            $element = $element->getNode();
70✔
67
        }
68

69
        if ($element instanceof \DOMNode) {
133✔
70
            $domNode = $this->document->importNode($element, true);
70✔
71

72
            if ($domNode instanceof \DOMNode) {
63✔
73
                /** @noinspection UnusedFunctionResultInspection */
74
                $this->document->appendChild($domNode);
63✔
75
            }
76

77
            return;
63✔
78
        }
79

80
        if ($element !== null) {
126✔
81
            $this->loadXml($element);
×
82
        }
83
    }
84

85
    /**
86
     * @param string $name
87
     * @param array  $arguments
88
     *
89
     * @throws \BadMethodCallException
90
     * @throws \RuntimeException
91
     *
92
     * @return static
93
     */
94
    public static function __callStatic($name, $arguments)
95
    {
96
        $arguments0 = $arguments[0] ?? '';
42✔
97

98
        $arguments1 = $arguments[1] ?? null;
42✔
99

100
        if ($name === 'str_get_xml') {
42✔
101
            $parser = new static();
21✔
102

103
            return $parser->loadXml($arguments0, $arguments1);
21✔
104
        }
105

106
        if ($name === 'file_get_xml') {
21✔
107
            $parser = new static();
21✔
108

109
            return $parser->loadXmlFile($arguments0, $arguments1);
21✔
110
        }
111

112
        throw new \BadMethodCallException('Method does not exist');
×
113
    }
114

115
    /** @noinspection MagicMethodsValidityInspection */
116

117
    /**
118
     * @param string $name
119
     *
120
     * @return string|null
121
     */
122
    public function __get($name)
123
    {
124
        $name = \strtolower($name);
×
125

126
        if ($name === 'plaintext') {
×
127
            return $this->text();
×
128
        }
129

130
        return null;
×
131
    }
132

133
    /**
134
     * @return string
135
     */
136
    public function __toString()
137
    {
138
        return $this->xml(false, false, true, 0);
14✔
139
    }
140

141
    /**
142
     * Create DOMDocument from XML.
143
     *
144
     * @param string   $xml
145
     * @param int|null $libXMLExtraOptions
146
     * @param bool     $useDefaultLibXMLOptions
147
     *
148
     * @return \DOMDocument
149
     */
150
    protected function createDOMDocument(string $xml, $libXMLExtraOptions = null, $useDefaultLibXMLOptions = true): \DOMDocument
151
    {
152
        $this->resetDynamicDomHelpers();
126✔
153

154
        if ($this->callbackBeforeCreateDom) {
126✔
155
            $xml = \call_user_func($this->callbackBeforeCreateDom, $xml, $this);
7✔
156
        }
157

158
        // set error level
159
        $internalErrors = \libxml_use_internal_errors(true);
126✔
160
        if (\PHP_VERSION_ID < 80000) {
126✔
UNCOV
161
            $disableEntityLoader = \libxml_disable_entity_loader(true);
36✔
162
        }
163
        \libxml_clear_errors();
126✔
164

165
        $optionsXml = 0;
126✔
166
        if ($useDefaultLibXMLOptions) {
126✔
167
            $optionsXml = \LIBXML_DTDLOAD | \LIBXML_DTDATTR | \LIBXML_NONET;
119✔
168

169
            if (\defined('LIBXML_BIGLINES')) {
119✔
170
                $optionsXml |= \LIBXML_BIGLINES;
119✔
171
            }
172

173
            if (\defined('LIBXML_COMPACT')) {
119✔
174
                $optionsXml |= \LIBXML_COMPACT;
119✔
175
            }
176
        }
177

178
        if ($libXMLExtraOptions !== null) {
126✔
179
            $optionsXml |= $libXMLExtraOptions;
7✔
180
        }
181

182
        $this->xPathNamespaces = []; // reset
126✔
183
        $matches = [];
126✔
184
        \preg_match_all('#xmlns:(?<namespaceKey>.*)=(["\'])(?<namespaceValue>.*)\\2#Ui', $xml, $matches);
126✔
185
        foreach ($matches['namespaceKey'] ?? [] as $index => $key) {
126✔
186
            if ($key) {
42✔
187
                $this->xPathNamespaces[\trim($key, ':')] = $matches['namespaceValue'][$index];
42✔
188
            }
189
        }
190

191
        if ($this->autoRemoveXPathNamespaces) {
126✔
192
            $xml = $this->removeXPathNamespaces($xml);
21✔
193
        }
194

195
        $xml = self::replaceToPreserveHtmlEntities($xml);
126✔
196

197
        $documentFound = false;
126✔
198
        $sxe = \simplexml_load_string($xml, \SimpleXMLElement::class, $optionsXml);
126✔
199
        $xmlErrors = \libxml_get_errors();
126✔
200
        if ($sxe !== false && \count($xmlErrors) === 0) {
126✔
201
            $domElementTmp = \dom_import_simplexml($sxe);
112✔
202
            if ($domElementTmp->ownerDocument instanceof \DOMDocument) {
112✔
203
                $documentFound = true;
112✔
204
                $this->document = $domElementTmp->ownerDocument;
112✔
205
            }
206
        }
207

208
        if ($documentFound === false) {
126✔
209
            // UTF-8 hack: http://php.net/manual/en/domdocument.loadhtml.php#95251
210
            $xmlHackUsed = false;
14✔
211
            /** @noinspection StringFragmentMisplacedInspection */
212
            if (\stripos('<?xml', $xml) !== 0) {
14✔
213
                $xmlHackUsed = true;
14✔
214
                $xml = '<?xml encoding="' . $this->getEncoding() . '" ?>' . $xml;
14✔
215
            }
216

217
            $documentFound = $this->document->loadXML($xml, $optionsXml);
14✔
218

219
            // remove the "xml-encoding" hack
220
            if ($xmlHackUsed) {
14✔
221
                foreach ($this->document->childNodes as $child) {
14✔
222
                    if ($child->nodeType === \XML_PI_NODE) {
×
223
                        /** @noinspection UnusedFunctionResultInspection */
224
                        $this->document->removeChild($child);
×
225

226
                        break;
×
227
                    }
228
                }
229
            }
230
        }
231

232
        if (
233
            $documentFound === false
126✔
234
            &&
235
            \count($xmlErrors) > 0
126✔
236
        ) {
237
            $errorStr = 'XML-Errors: ' . \print_r($xmlErrors, true) . ' in ' . \print_r($xml, true);
14✔
238

239
            if (!$this->reportXmlErrorsAsException) {
14✔
240
                \trigger_error($errorStr, \E_USER_WARNING);
7✔
241
            } else {
242
                throw new \InvalidArgumentException($errorStr);
7✔
243
            }
244
        }
245

246
        // set encoding
247
        $this->document->encoding = $this->getEncoding();
119✔
248

249
        // restore lib-xml settings
250
        \libxml_clear_errors();
119✔
251
        \libxml_use_internal_errors($internalErrors);
119✔
252
        if (\PHP_VERSION_ID < 80000 && isset($disableEntityLoader)) {
119✔
UNCOV
253
            \libxml_disable_entity_loader($disableEntityLoader);
34✔
254
        }
255

256
        return $this->document;
119✔
257
    }
258

259
    /**
260
     * Find list of nodes with a CSS or xPath selector.
261
     *
262
     * @param string   $selector
263
     * @param int|null $idx
264
     *
265
     * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface<SimpleXmlDomInterface>
266
     */
267
    public function find(string $selector, $idx = null)
268
    {
269
        $xPathQuery = SelectorConverter::toXPath($selector, true, false);
91✔
270

271
        $xPath = new \DOMXPath($this->document);
91✔
272

273
        if ($this->autoRegisterXPathNamespaces) {
91✔
274
            foreach ($this->xPathNamespaces as $key => $value) {
×
275
                $xPath->registerNamespace($key, $value);
×
276
            }
277
        }
278

279
        if ($this->callbackXPathBeforeQuery) {
91✔
280
            $xPathQuery = \call_user_func($this->callbackXPathBeforeQuery, $selector, $xPathQuery, $xPath, $this);
7✔
281
        }
282

283
        $nodesList = $xPath->query($xPathQuery);
91✔
284

285
        $elements = new SimpleXmlDomNode();
91✔
286

287
        if ($nodesList) {
91✔
288
            foreach ($nodesList as $node) {
91✔
289
                $elements[] = new SimpleXmlDom($node);
91✔
290
            }
291
        }
292

293
        // return all elements
294
        if ($idx === null) {
91✔
295
            if (\count($elements) === 0) {
63✔
296
                return new SimpleXmlDomNodeBlank();
28✔
297
            }
298

299
            return $elements;
63✔
300
        }
301

302
        // handle negative values
303
        if ($idx < 0) {
56✔
304
            $idx = \count($elements) + $idx;
×
305
        }
306

307
        // return one element
308
        return $elements[$idx] ?? new SimpleXmlDomBlank();
56✔
309
    }
310

311
    /**
312
     * Find nodes with a CSS or xPath selector.
313
     *
314
     * @param string $selector
315
     *
316
     * @return SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface<SimpleXmlDomInterface>
317
     */
318
    public function findMulti(string $selector): SimpleXmlDomNodeInterface
319
    {
320
        return $this->find($selector, null);
21✔
321
    }
322

323
    /**
324
     * Find nodes with a CSS or xPath selector or false, if no element is found.
325
     *
326
     * @param string $selector
327
     *
328
     * @return false|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface<SimpleXmlDomInterface>
329
     */
330
    public function findMultiOrFalse(string $selector)
331
    {
332
        $return = $this->find($selector, null);
21✔
333

334
        if ($return instanceof SimpleXmlDomNodeBlank) {
21✔
335
            return false;
7✔
336
        }
337

338
        return $return;
14✔
339
    }
340

341
    /**
342
     * Find nodes with a CSS or xPath selector or null, if no element is found.
343
     *
344
     * @param string $selector
345
     *
346
     * @return null|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface<SimpleXmlDomInterface>
347
     */
348
    public function findMultiOrNull(string $selector)
349
    {
350
        $return = $this->find($selector, null);
14✔
351

352
        if ($return instanceof SimpleXmlDomNodeBlank) {
14✔
353
            return null;
7✔
354
        }
355

356
        return $return;
14✔
357
    }
358

359
    /**
360
     * Find one node with a CSS or xPath selector.
361
     *
362
     * @param string $selector
363
     *
364
     * @return SimpleXmlDomInterface
365
     */
366
    public function findOne(string $selector): SimpleXmlDomInterface
367
    {
368
        return $this->find($selector, 0);
49✔
369
    }
370

371
    /**
372
     * Find one node with a CSS or xPath selector or false, if no element is found.
373
     *
374
     * @param string $selector
375
     *
376
     * @return false|SimpleXmlDomInterface
377
     */
378
    public function findOneOrFalse(string $selector)
379
    {
380
        $return = $this->find($selector, 0);
7✔
381

382
        if ($return instanceof SimpleXmlDomBlank) {
7✔
383
            return false;
7✔
384
        }
385

386
        return $return;
×
387
    }
388

389
    /**
390
     * Find one node with a CSS or xPath selector or null, if no element is found.
391
     *
392
     * @param string $selector
393
     *
394
     * @return null|SimpleXmlDomInterface
395
     */
396
    public function findOneOrNull(string $selector)
397
    {
398
        $return = $this->find($selector, 0);
14✔
399

400
        if ($return instanceof SimpleXmlDomBlank) {
14✔
401
            return null;
14✔
402
        }
403

404
        return $return;
14✔
405
    }
406

407
    /**
408
     * @param string $content
409
     * @param bool   $multiDecodeNewHtmlEntity
410
     * @param bool   $putBrokenReplacedBack
411
     *
412
     * @return string
413
     */
414
    public function fixHtmlOutput(
415
        string $content,
416
        bool $multiDecodeNewHtmlEntity = false,
417
        bool $putBrokenReplacedBack = true
418
    ): string {
419
        $content = $this->decodeHtmlEntity($content, $multiDecodeNewHtmlEntity);
70✔
420

421
        return self::putReplacedBackToPreserveHtmlEntities($content, $putBrokenReplacedBack);
70✔
422
    }
423

424
    /**
425
     * Return elements by ".class".
426
     *
427
     * @param string $class
428
     *
429
     * @return SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface<SimpleXmlDomInterface>
430
     */
431
    public function getElementByClass(string $class): SimpleXmlDomNodeInterface
432
    {
433
        return $this->findMulti(".{$class}");
×
434
    }
435

436
    /**
437
     * Return element by #id.
438
     *
439
     * @param string $id
440
     *
441
     * @return SimpleXmlDomInterface
442
     */
443
    public function getElementById(string $id): SimpleXmlDomInterface
444
    {
445
        return $this->findOne("#{$id}");
×
446
    }
447

448
    /**
449
     * Return element by tag name.
450
     *
451
     * @param string $name
452
     *
453
     * @return SimpleXmlDomInterface
454
     */
455
    public function getElementByTagName(string $name): SimpleXmlDomInterface
456
    {
457
        $node = $this->document->getElementsByTagName($name)->item(0);
×
458

459
        if ($node === null) {
×
460
            return new SimpleXmlDomBlank();
×
461
        }
462

463
        return new SimpleXmlDom($node);
×
464
    }
465

466
    /**
467
     * Returns elements by "#id".
468
     *
469
     * @param string   $id
470
     * @param int|null $idx
471
     *
472
     * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface<SimpleXmlDomInterface>
473
     */
474
    public function getElementsById(string $id, $idx = null)
475
    {
476
        return $this->find("#{$id}", $idx);
×
477
    }
478

479
    /**
480
     * Returns elements by tag name.
481
     *
482
     * @param string   $name
483
     * @param int|null $idx
484
     *
485
     * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface<SimpleXmlDomInterface>
486
     */
487
    public function getElementsByTagName(string $name, $idx = null)
488
    {
489
        $nodesList = $this->document->getElementsByTagName($name);
×
490

491
        $elements = new SimpleXmlDomNode();
×
492

493
        foreach ($nodesList as $node) {
×
494
            $elements[] = new SimpleXmlDom($node);
×
495
        }
496

497
        // return all elements
498
        if ($idx === null) {
×
499
            if (\count($elements) === 0) {
×
500
                return new SimpleXmlDomNodeBlank();
×
501
            }
502

503
            return $elements;
×
504
        }
505

506
        // handle negative values
507
        if ($idx < 0) {
×
508
            $idx = \count($elements) + $idx;
×
509
        }
510

511
        // return one element
512
        return $elements[$idx] ?? new SimpleXmlDomNodeBlank();
×
513
    }
514

515
    /**
516
     * Get dom node's outer html.
517
     *
518
     * @param bool $multiDecodeNewHtmlEntity
519
     * @param bool $putBrokenReplacedBack
520
     *
521
     * @return string
522
     */
523
    public function html(bool $multiDecodeNewHtmlEntity = false, bool $putBrokenReplacedBack = true): string
524
    {
525
        if (static::$callback !== null) {
×
526
            \call_user_func(static::$callback, [$this]);
×
527
        }
528

529
        $content = $this->document->saveHTML();
×
530

531
        if ($content === false) {
×
532
            return '';
×
533
        }
534

535
        return $this->fixHtmlOutput($content, $multiDecodeNewHtmlEntity, $putBrokenReplacedBack);
×
536
    }
537

538
    /**
539
     * Load HTML from string.
540
     *
541
     * @param string   $html
542
     * @param int|null $libXMLExtraOptions
543
     *
544
     * @return $this
545
     */
546
    public function loadHtml(string $html, $libXMLExtraOptions = null): DomParserInterface
547
    {
548
        $this->document = $this->createDOMDocument($html, $libXMLExtraOptions);
7✔
549

550
        return $this;
7✔
551
    }
552

553
    /**
554
     * Load HTML from file.
555
     *
556
     * @param string   $filePath
557
     * @param int|null $libXMLExtraOptions
558
     *
559
     * @throws \RuntimeException
560
     *
561
     * @return $this
562
     */
563
    public function loadHtmlFile(string $filePath, $libXMLExtraOptions = null): DomParserInterface
564
    {
565
        if (
566
            !\preg_match("/^https?:\/\//i", $filePath)
×
567
            &&
568
            !\file_exists($filePath)
×
569
        ) {
570
            throw new \RuntimeException("File {$filePath} not found");
×
571
        }
572

573
        try {
574
            if (\class_exists('\voku\helper\UTF8')) {
×
575
                $html = \voku\helper\UTF8::file_get_contents($filePath);
×
576
            } else {
577
                $html = \file_get_contents($filePath);
×
578
            }
579
        } catch (\Exception $e) {
×
580
            throw new \RuntimeException("Could not load file {$filePath}");
×
581
        }
582

583
        if ($html === false) {
×
584
            throw new \RuntimeException("Could not load file {$filePath}");
×
585
        }
586

587
        return $this->loadHtml($html, $libXMLExtraOptions);
×
588
    }
589

590
    /**
591
     * @param string $selector
592
     * @param int    $idx
593
     *
594
     * @return SimpleXmlDomInterface|SimpleXmlDomInterface[]|SimpleXmlDomNodeInterface<SimpleXmlDomInterface>
595
     */
596
    public function __invoke($selector, $idx = null)
597
    {
598
        return $this->find($selector, $idx);
×
599
    }
600

601
    /**
602
     * @param string $xml
603
     *
604
     * @return string
605
     */
606
    private function removeXPathNamespaces(string $xml): string
607
    {
608
        foreach ($this->xPathNamespaces as $key => $value) {
21✔
609
            $xml = \str_replace($key . ':', '', $xml);
14✔
610
        }
611

612
        return (string) \preg_replace('#xmlns:?.*=(["\'])(?:.*)\\1#Ui', '', $xml);
21✔
613
    }
614

615
    /**
616
     * Load XML from string.
617
     *
618
     * @param string   $xml
619
     * @param int|null $libXMLExtraOptions
620
     * @param bool     $useDefaultLibXMLOptions
621
     *
622
     * @return $this
623
     */
624
    public function loadXml(string $xml, $libXMLExtraOptions = null, $useDefaultLibXMLOptions = true): self
625
    {
626
        $this->document = $this->createDOMDocument($xml, $libXMLExtraOptions, $useDefaultLibXMLOptions);
119✔
627

628
        return $this;
112✔
629
    }
630

631
    /**
632
     * Load XML from file.
633
     *
634
     * @param string   $filePath
635
     * @param int|null $libXMLExtraOptions
636
     * @param bool     $useDefaultLibXMLOptions
637
     *
638
     * @throws \RuntimeException
639
     *
640
     * @return $this
641
     */
642
    public function loadXmlFile(string $filePath, $libXMLExtraOptions = null, $useDefaultLibXMLOptions = true): self
643
    {
644
        if (
645
            !\preg_match("/^https?:\/\//i", $filePath)
21✔
646
            &&
647
            !\file_exists($filePath)
21✔
648
        ) {
649
            throw new \RuntimeException("File {$filePath} not found");
×
650
        }
651

652
        try {
653
            if (\class_exists('\voku\helper\UTF8')) {
21✔
654
                $xml = \voku\helper\UTF8::file_get_contents($filePath);
×
655
            } else {
656
                $xml = \file_get_contents($filePath);
21✔
657
            }
658
        } catch (\Exception $e) {
×
659
            throw new \RuntimeException("Could not load file {$filePath}");
×
660
        }
661

662
        if ($xml === false) {
21✔
663
            throw new \RuntimeException("Could not load file {$filePath}");
×
664
        }
665

666
        return $this->loadXml($xml, $libXMLExtraOptions, $useDefaultLibXMLOptions);
21✔
667
    }
668

669
    /**
670
     * @param callable      $callback
671
     * @param \DOMNode|null $domNode
672
     *
673
     * @return void
674
     */
675
    public function replaceTextWithCallback($callback, ?\DOMNode $domNode = null)
676
    {
677
        if ($domNode === null) {
7✔
678
            $domNode = $this->document;
7✔
679
        }
680

681
        if ($domNode->hasChildNodes()) {
7✔
682
            $children = [];
7✔
683

684
            // since looping through a DOM being modified is a bad idea we prepare an array:
685
            foreach ($domNode->childNodes as $child) {
7✔
686
                $children[] = $child;
7✔
687
            }
688

689
            foreach ($children as $child) {
7✔
690
                if ($child->nodeType === \XML_TEXT_NODE) {
7✔
691
                    /** @noinspection PhpSillyAssignmentInspection */
692
                    /** @var \DOMText $child */
693
                    $child = $child;
7✔
694

695
                    $oldText = self::putReplacedBackToPreserveHtmlEntities($child->wholeText);
7✔
696
                    $newText = $callback($oldText);
7✔
697
                    if ($domNode->ownerDocument) {
7✔
698
                        $newTextNode = $domNode->ownerDocument->createTextNode(self::replaceToPreserveHtmlEntities($newText));
7✔
699
                        $domNode->replaceChild($newTextNode, $child);
7✔
700
                    }
701
                } else {
702
                    $this->replaceTextWithCallback($callback, $child);
7✔
703
                }
704
            }
705
        }
706
    }
707

708
    /**
709
     * @param bool $autoRemoveXPathNamespaces
710
     *
711
     * @return $this
712
     */
713
    public function autoRemoveXPathNamespaces(bool $autoRemoveXPathNamespaces = true): self
714
    {
715
        $this->autoRemoveXPathNamespaces = $autoRemoveXPathNamespaces;
21✔
716

717
        return $this;
21✔
718
    }
719

720
    /**
721
     * @param bool $autoRegisterXPathNamespaces
722
     *
723
     * @return $this
724
     */
725
    public function autoRegisterXPathNamespaces(bool $autoRegisterXPathNamespaces = true): self
726
    {
727
        $this->autoRegisterXPathNamespaces = $autoRegisterXPathNamespaces;
×
728

729
        return $this;
×
730
    }
731

732
    /**
733
     * @param callable $callbackXPathBeforeQuery
734
     *
735
     * @phpstan-param callable(string $cssSelectorString, string $xPathString, \DOMXPath, \voku\helper\XmlDomParser): string $callbackXPathBeforeQuery
736
     *
737
     * @return $this
738
     */
739
    public function setCallbackXPathBeforeQuery(callable $callbackXPathBeforeQuery): self
740
    {
741
        $this->callbackXPathBeforeQuery = $callbackXPathBeforeQuery;
7✔
742

743
        return $this;
7✔
744
    }
745

746
    /**
747
     * @param callable $callbackBeforeCreateDom
748
     *
749
     * @phpstan-param callable(string $xmlString, \voku\helper\XmlDomParser): string $callbackBeforeCreateDom
750
     *
751
     * @return $this
752
     */
753
    public function setCallbackBeforeCreateDom(callable $callbackBeforeCreateDom): self
754
    {
755
        $this->callbackBeforeCreateDom = $callbackBeforeCreateDom;
7✔
756

757
        return $this;
7✔
758
    }
759

760
    /**
761
     * @param bool $reportXmlErrorsAsException
762
     *
763
     * @return $this
764
     */
765
    public function reportXmlErrorsAsException(bool $reportXmlErrorsAsException = true): self
766
    {
767
        $this->reportXmlErrorsAsException = $reportXmlErrorsAsException;
21✔
768

769
        return $this;
21✔
770
    }
771
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc