2018-09-06 22:51:08 -04:00
|
|
|
<?php
|
2021-03-21 17:38:05 -04:00
|
|
|
/** @license MIT
|
|
|
|
* Copyright 2017 , Dustin Wilson, J. King et al.
|
|
|
|
* See LICENSE and AUTHORS files for details */
|
|
|
|
|
2018-09-06 22:51:08 -04:00
|
|
|
declare(strict_types=1);
|
2021-03-21 17:38:05 -04:00
|
|
|
namespace MensBeam\HTML;
|
2018-09-06 22:51:08 -04:00
|
|
|
|
|
|
|
class Document extends \DOMDocument {
|
2021-03-19 15:01:49 -04:00
|
|
|
use EscapeString, Moonwalk, Serialize, Walk;
|
2018-09-06 22:51:08 -04:00
|
|
|
|
2021-02-17 21:45:14 -05:00
|
|
|
// Quirks mode constants
|
|
|
|
public const NO_QUIRKS_MODE = 0;
|
|
|
|
public const QUIRKS_MODE = 1;
|
|
|
|
public const LIMITED_QUIRKS_MODE = 2;
|
|
|
|
|
|
|
|
public $quirksMode = self::NO_QUIRKS_MODE;
|
2021-03-07 12:20:46 -05:00
|
|
|
public $mangledElements = false;
|
|
|
|
public $mangledAttributes = false;
|
2021-03-16 11:27:53 -04:00
|
|
|
public $documentEncoding = null;
|
2021-02-17 21:45:14 -05:00
|
|
|
|
2021-02-23 17:30:45 -05:00
|
|
|
// An array of all template elements created in the document
|
|
|
|
// This exists because values of properties on derived DOM classes
|
|
|
|
// are lost unless at least one PHP reference is kept for the
|
|
|
|
// element somewhere in userspace. This is that somewhere.
|
|
|
|
protected $templateElements = [];
|
|
|
|
|
2018-09-06 22:51:08 -04:00
|
|
|
public function __construct() {
|
|
|
|
parent::__construct();
|
|
|
|
|
2021-03-21 17:38:05 -04:00
|
|
|
$this->registerNodeClass('DOMComment', '\MensBeam\HTML\Comment');
|
|
|
|
$this->registerNodeClass('DOMDocumentFragment', '\MensBeam\HTML\DocumentFragment');
|
|
|
|
$this->registerNodeClass('DOMElement', '\MensBeam\HTML\Element');
|
|
|
|
$this->registerNodeClass('DOMProcessingInstruction', '\MensBeam\HTML\ProcessingInstruction');
|
|
|
|
$this->registerNodeClass('DOMText', '\MensBeam\HTML\Text');
|
2018-09-06 22:51:08 -04:00
|
|
|
}
|
|
|
|
|
2021-03-19 15:01:49 -04:00
|
|
|
public function createAttribute($name) {
|
|
|
|
try {
|
|
|
|
return parent::createAttribute($name);
|
|
|
|
} catch (\DOMException $e) {
|
|
|
|
// The element name is invalid for XML
|
|
|
|
// Replace any offending characters with "UHHHHHH" where H are the
|
|
|
|
// uppercase hexadecimal digits of the character's code point
|
|
|
|
$this->mangledAttributes = true;
|
|
|
|
$name = $this->coerceName($name);
|
|
|
|
return parent::createAttribute($name);
|
2021-03-09 11:59:31 -05:00
|
|
|
}
|
2018-09-10 17:56:38 -04:00
|
|
|
}
|
|
|
|
|
2021-03-19 15:01:49 -04:00
|
|
|
public function createAttributeNS($namespaceURI, $qualifiedName) {
|
|
|
|
try {
|
|
|
|
return parent::createAttributeNS($namespaceURI, $qualifiedName);
|
|
|
|
} catch (\DOMException $e) {
|
|
|
|
// The element name is invalid for XML
|
|
|
|
// Replace any offending characters with "UHHHHHH" where H are the
|
|
|
|
// uppercase hexadecimal digits of the character's code point
|
|
|
|
$this->mangledAttributes = true;
|
|
|
|
$qualifiedName = $this->coerceName($qualifiedName);
|
|
|
|
return parent::createAttributeNS($namespaceURI, $qualifiedName);
|
|
|
|
}
|
2018-09-10 17:56:38 -04:00
|
|
|
}
|
|
|
|
|
2021-02-23 17:30:45 -05:00
|
|
|
public function createElement($name, $value = "") {
|
2021-03-07 12:20:46 -05:00
|
|
|
try {
|
2021-03-22 13:07:44 -04:00
|
|
|
if ($name !== 'template') {
|
|
|
|
$e = parent::createElement($name, $value);
|
|
|
|
} else {
|
2021-03-23 17:59:26 -04:00
|
|
|
$e = new TemplateElement($this, $name, $value);
|
2021-03-07 12:20:46 -05:00
|
|
|
$this->templateElements[] = $e;
|
|
|
|
$e->content = $this->createDocumentFragment();
|
|
|
|
}
|
2021-03-22 13:07:44 -04:00
|
|
|
|
2021-03-07 12:20:46 -05:00
|
|
|
return $e;
|
2021-03-07 16:50:27 -05:00
|
|
|
} catch (\DOMException $e) {
|
2021-03-07 12:20:46 -05:00
|
|
|
// The element name is invalid for XML
|
|
|
|
// Replace any offending characters with "UHHHHHH" where H is the
|
|
|
|
// uppercase hexadecimal digits of the character's code point
|
|
|
|
$this->mangledElements = true;
|
2021-03-07 16:50:27 -05:00
|
|
|
$name = $this->coerceName($name);
|
|
|
|
return parent::createElement($name, $value);
|
2021-02-23 17:30:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-06 21:41:12 -05:00
|
|
|
public function createElementNS($namespaceURI, $qualifiedName, $value = "") {
|
2021-03-07 12:20:46 -05:00
|
|
|
try {
|
2021-03-23 17:59:26 -04:00
|
|
|
if ($qualifiedName !== 'template' || $namespaceURI !== null) {
|
2021-03-22 13:07:44 -04:00
|
|
|
$e = parent::createElementNS($namespaceURI, $qualifiedName, $value);
|
|
|
|
} else {
|
2021-03-23 17:59:26 -04:00
|
|
|
$e = new TemplateElement($this, $qualifiedName, $value);
|
2021-03-07 12:20:46 -05:00
|
|
|
$this->templateElements[] = $e;
|
|
|
|
$e->content = $this->createDocumentFragment();
|
|
|
|
}
|
2021-03-22 13:07:44 -04:00
|
|
|
|
2021-03-07 12:20:46 -05:00
|
|
|
return $e;
|
2021-03-07 16:50:27 -05:00
|
|
|
} catch (\DOMException $e) {
|
2021-03-07 12:20:46 -05:00
|
|
|
// The element name is invalid for XML
|
2021-03-07 16:50:27 -05:00
|
|
|
// Replace any offending characters with "UHHHHHH" where H are the
|
2021-03-07 12:20:46 -05:00
|
|
|
// uppercase hexadecimal digits of the character's code point
|
|
|
|
$this->mangledElements = true;
|
2021-03-07 16:50:27 -05:00
|
|
|
$qualifiedName = $this->coerceName($qualifiedName);
|
|
|
|
return parent::createElementNS($namespaceURI, $qualifiedName, $value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-19 15:01:49 -04:00
|
|
|
public function load($source, $options = null, ?string $encodingOrContentType = null): bool {
|
|
|
|
$data = Parser::fetchFile($source, $encodingOrContentType);
|
|
|
|
if (!$data) {
|
|
|
|
return false;
|
2021-03-07 16:50:27 -05:00
|
|
|
}
|
2021-03-19 15:01:49 -04:00
|
|
|
[$data, $encodingOrContentType] = $data;
|
|
|
|
Parser::parse($data, $this, $encodingOrContentType, null, (string) $source);
|
|
|
|
return true;
|
2021-03-07 16:50:27 -05:00
|
|
|
}
|
|
|
|
|
2021-03-19 15:01:49 -04:00
|
|
|
public function loadHTML($source, $options = null, ?string $encodingOrContentType = null): bool {
|
|
|
|
assert(is_string($source), new DOMException(DOMException::STRING_EXPECTED, 'source', gettype($source)));
|
|
|
|
Parser::parse($source, $this, $encodingOrContentType);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function save($filename, $options = 0): string {
|
|
|
|
return file_put_contents($filename, $this->serialize());
|
|
|
|
}
|
|
|
|
|
|
|
|
public function saveHTML(\DOMNode $node = null): string {
|
|
|
|
if ($node === null) {
|
|
|
|
$node = $this;
|
|
|
|
} elseif ($node->ownerDocument !== $this) {
|
|
|
|
throw new DOMException(DOMException::WRONG_DOCUMENT);
|
2021-03-06 21:41:12 -05:00
|
|
|
}
|
2021-03-19 15:01:49 -04:00
|
|
|
|
|
|
|
return $node->serialize();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function saveHTMLFile($filename): int {
|
|
|
|
return $this->save($filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function saveXML(?\DOMNode $node = null, $options = null) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function validate(): bool {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function xinclude($options = null): bool {
|
|
|
|
return false;
|
2021-03-06 21:41:12 -05:00
|
|
|
}
|
|
|
|
|
2018-09-12 09:47:52 -04:00
|
|
|
public function __toString() {
|
|
|
|
return $this->serialize();
|
|
|
|
}
|
2018-09-06 22:51:08 -04:00
|
|
|
}
|