自动注入资源到指定的位置
- 在渲染好html后,输出html字符之前调用此方法
`$html = $manager->injectAssets($html);`
@param string $html html document string
@return mixed|string [type]
495517
public function injectAssets($html)
    {
        $html = trim($html);

        if (!($assets = $this->assets)) {
            return $html;
        }

        if (!empty($assets[self::POS_BODY])) {

            $assetBody = $this->bodyNode . implode('', $assets[self::POS_BODY]);
            $bodyNode = str_replace('/', '\/', $this->bodyNode);
            $html = preg_replace("/$bodyNode/i", $assetBody, $html, 1, $count);

            // 没找到节点，注入失败时，直接加入开始位置
            if ($count === 0) {
                $html = $assetBody . $html;
            }
        }

        if (!empty($assets[self::POS_HEAD])) {
            $assetHead = implode('', $assets[self::POS_HEAD]) . $this->headNode;
            $headNode = str_replace('/', '\/', $this->headNode);
            $html = preg_replace("/$headNode/i", $assetHead, $html, 1, $count);

            if ($count === 0) {
                $html = $assetHead . $html;
            }
        }

        if (!empty($assets[self::POS_END])) {

            $assetEnd = implode('', $assets[self::POS_END]) . $this->endNode;
            $endNode = str_replace('/', '\/', $this->endNode);
            $html = preg_replace("/$endNode/i", $assetEnd, $html, 1, $count);

            // 没找到节点，注入失败时，直接加入末尾位置
            if ($count === 0) {
                $html .= $assetEnd;
            }
        }

        unset($bodyNode, $headNode, $endNode, $assetHead, $assetBody, $assetEnd, $count);

        return $html;
    }
1083850
protected function cleaningHtml($html)
    {
        $xml = false;
        $childrens = null;

        try {
            $xml = @simplexml_load_string($html);
        } catch (\Exception $e) {
            // ignore
        }

        if ($xml !== false) {
            if (!$this->hasHead && $xml->getName() === 'head') {
                $childrens = $xml->xpath('//head/child::*');
            }
            if (!$this->hasBody && $xml->getName() === 'body') {
                $childrens = $xml->xpath('//body/child::*');
            }

            if ($childrens !== null) {
                $temp = '';
                foreach ($childrens as $children) {
                    $temp .= $children->saveXML();
                }
                $html = html_entity_decode($temp);
            }
        }

        if ($this->hasHtml) {
            $html = $this->htmlMatches['before'].$html.$this->htmlMatches['after'];
        }
        if ($this->hasDoctype) {
            $html = $this->doctypeMatches['content'].$html;
        }

        return $html;
    }
1222630
final public function importHTML($html)
	{
		$tmp_doc = new \DOMDocument('1.0', 'UTF-8');
		$tmp_doc->loadHTML($html);
		$nodes = array();
		foreach ($tmp_doc->documentElement->childNodes as $node) {
			array_push($nodes, $node);
			$this->appendChild($this->ownerDocument->importNode($node, true));
		}
		return $nodes;
	}
312047
private function createDOMDocumentFromHTML($html = null) {

        if ($html != null) {
            libxml_use_internal_errors(true);
            $dom = new DOMDocument;
            $dom->loadHTML($html);
            libxml_clear_errors();
            libxml_use_internal_errors(false);
            return $dom;
        }
    }
490279
protected function parseHtml($html)
    {
        $data = [
            'image' => '',
            'title' => '',
            'description' => '',
            'pictures' => [],
        ];

        libxml_use_internal_errors(true);
        $doc = new \DOMDocument();
        $doc->loadHTML($html);

        /** @var \DOMElement $meta */
        foreach ($doc->getElementsByTagName('meta') as $meta) {
            if ($meta->getAttribute('itemprop') === 'image') {
                $data['image'] = $meta->getAttribute('content');
            } elseif ($meta->getAttribute('property') === 'og:image') {
                $data['image'] = $meta->getAttribute('content');
            } elseif ($meta->getAttribute('property') === 'twitter:image') {
                $data['image'] = $meta->getAttribute('value');
            }

            if ($meta->getAttribute('itemprop') === 'name') {
                $data['title'] = $meta->getAttribute('content');
            } elseif ($meta->getAttribute('property') === 'og:title') {
                $data['title'] = $meta->getAttribute('content');
            } elseif ($meta->getAttribute('property') === 'twitter:title') {
                $data['title'] = $meta->getAttribute('value');
            }

            if ($meta->getAttribute('itemprop') === 'description') {
                $data['title'] = $meta->getAttribute('content');
            }
            if ($meta->getAttribute('property') === 'og:description') {
                $data['description'] = $meta->getAttribute('content');
            }
        }

        if (empty($data['title'])) {
            /** @var \DOMElement $title */
            foreach ($doc->getElementsByTagName('title') as $title) {
                $data['title'] = $title->nodeValue;
            }
        }

        if (empty($data['description'])) {
            foreach ($doc->getElementsByTagName('meta') as $meta) {
                if ($meta->getAttribute('name') === 'description') {
                    $data['description'] = $meta->getAttribute('content');
                }
            }
        }

        foreach ($doc->getElementsByTagName('img') as $img) {
            $data['pictures'][] = $img->getAttribute('src');
        }

        return $data;
    }
621444
private function parseAttribute(string $html) : string
    {
        $remainingHtml = ltrim($html);

        try {
            // Will match the first entire name/value attribute pair.
            preg_match(
                "/((([a-z0-9\-_]+:)?[a-z0-9\-_]+)(\s*=\s*)?)/i",
                $remainingHtml,
                $attributeMatches
            );

            $attributeName = $attributeMatches[2];
            $remainingHtml = mb_substr(mb_strstr($remainingHtml, $attributeName), mb_strlen($attributeName));
            if ($this->isAttributeValueless($remainingHtml)) {
                $this->attributes[trim($attributeName)] = true;

                return $remainingHtml;
            }

            return $this->parseAttributeValue($html, $remainingHtml, $attributeName);
        } catch (ParseException $e) {
            if ($this->getThrowOnError()) {
                throw $e;
            }
        }

        return '';
    }
730593
protected function restore($html)
    {
        foreach ($this->data as $index => $item)
        {
            $key = (string) '$' . $index . '$';

            $html = str_replace($key, $item, $html);
        }

        return (string) $html;
    }
1005335
private function eliminateUselessTags(string $html): string
    {
        // eliminate useless symbols
        $html = preg_replace('/[\342\200\230-\342\200\235]|[\342\206\220-\342\206\223]|[\342\226\240-\342\226\275]|[\342\227\206-\342\227\257]|\342\230\205|\342\230\206/u', '', $html);

        // eliminate useless html tags
        $html = preg_replace('/<(script|style|select|noscript)[^>]*>.*?<\/\1\s*>/isu', '', $html);
        $html = preg_replace('/<!--.*?-->/su', '', $html);
        $html = preg_replace('/<![A-Za-z].*?>/u', '', $html);
        $html = preg_replace('/<div\s[^>]*class\s*=\s*[\'"]?alpslab-slide["\']?[^>]*>.*?<\/div\s*>/su', '', $html);
        $html = preg_replace('/<div\s[^>]*(id|class)\s*=\s*[\'"]?\S*more\S*["\']?[^>]*>/iu', '', $html);

        return $html;
    }
353967
public function setHtml(string $html=null, bool $append=true) :self {
		// append by default or replace html
		$this->content = $append ? $this->content . $html : $html;
		// return self
		return($this);
	}
415327
protected function tidy( $html ) {

		// Make XHTML 1.1 strict using htmlLawed

		$html = \Pressbooks\Interactive\Content::init()->replaceInteractiveTags( $html );

		$config = [
			'valid_xhtml' => 1,
			'unique_ids' => 'fixme-',
			'hook' => '\Pressbooks\Sanitize\html5_to_xhtml11',
			'tidy' => -1,
		];

		return \Pressbooks\HtmLawed::filter( $html, $config );
	}
1318471
private static function convertHtmlToDom($html)
    {
        $dom = new DOMDocument;

        \libxml_use_internal_errors(true);
        $dom->loadHTML($html);

        \libxml_clear_errors();

        return $dom;
    }
935583
public function convert($html) {
    if (preg_match('/^\s*$/u', $html)) {
      return '';
    }
    $html = '<html><head><meta http-equiv="content-type" content="text/html; charset=UTF-8"></head>' . $html . '</body></html>';
    $this->dom = new \DOMDocument();
    if (!$this->dom->loadHTML($html)) {
      return NULL;
    }
    $xp = new \DOMXPath($this->dom);
    return implode(self::BLOCK_DELIMITER, $this->getBlocks(
      $xp->query('/html/body')->item(0)->childNodes
    ));
  }
375578
protected function _convertUrls($html) {
		$fullBaseUrl = Configure::read('App.fullBaseUrl');
		if (!empty($fullBaseUrl)) {
			$html = preg_replace('~(?:src|action|href)=[\'"]\K/(?!/)[^\'"]*~', "$fullBaseUrl$0", $html);
		}

		return $html;
	}
123451
private function prepareHtmlForDomConversion($html)
    {
        $htmlWithSelfClosingSlashes = $this->ensurePhpUnrecognizedSelfClosingTagsAreXml($html);
        $htmlWithDocumentType = $this->ensureDocumentType($htmlWithSelfClosingSlashes);

        return $this->addContentTypeMetaTag($htmlWithDocumentType);
    }
590952
public function loadHTML($html)
    {
        if ($html instanceof Renderable) {
            $html = $html->render();
        }
        $this->html = $html;
        $this->file = null;
        return $this;
    }
937271
private function ensureDocumentType($html)
    {
        $hasDocumentType = \stripos($html, '<!DOCTYPE') !== false;
        if ($hasDocumentType) {
            return $html;
        }

        return static::DEFAULT_DOCUMENT_TYPE . $html;
    }
947559
public function linkUrlsInTrustedHtml($html)
	{
		$reMarkup = '{</?([a-z]+)([^"\'>]|"[^"]*"|\'[^\']*\')*>|&#?[a-zA-Z0-9]+;|$}';

		$insideAnchorTag = false;
		$position = 0;
		$result = '';

		// Iterate over every piece of markup in the HTML.
		while (true)
		{
			$match = array();
			preg_match($reMarkup, $html, $match, PREG_OFFSET_CAPTURE, $position);

			list($markup, $markupPosition) = $match[0];

			// Process text leading up to the markup.
			$text = substr($html, $position, $markupPosition - $position);

			// Link URLs unless we're inside an anchor tag.
			if ( ! $insideAnchorTag )
			{
				$text = $this->linkUrlsAndEscapeHtml($text);
			}

			$result .= $text;

			// End of HTML?
			if ( $markup === '' )
			{
				break;
			}

			// Check if markup is an anchor tag ('<a>', '</a>').
			if ( $markup[0] !== '&' && $match[1][0] === 'a' )
			{
				$insideAnchorTag = ($markup[1] !== '/');
			}

			// Pass markup through unchanged.
			$result .= $markup;

			// Continue after the markup.
			$position = $markupPosition + strlen($markup);
		}

		return $result;
	}