php / php/php-src

Dom\HTMLDocument: Impossible to add text node on document level

オープン
#23,562 コメント 4 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

Feature Status: Needs Triage
主要言語
C
スター
40.4k
フォーク
8.2k
平均マージ
2日 13時間
マージ済み PR(30日)
96

説明

Description

The following code...

$doc = \Dom\HTMLDocument::createFromString('Hello <b>world</b>!',LIBXML_HTML_NOIMPLIED);
$greeting = $doc->firstChild;
echo get_class($greeting)."<br />";
$new_greeting = $doc->createTextNode('Welcome');
$greeting->replaceWith($new_greeting);
echo htmlentities($doc->saveHtml());

results in this error:

DOMException: Cannot insert text as a child of a document in Dom\CharacterData->replaceWith()

This is different behavior from the old DOM classes which allowed this. I understand, this spec-compliance is supposed to be a feature. If I understand correctly, the new Lexbor-based parser offers validity checks for some methods and not for others:

https://lexbor.com/modules/dom/

E.g. lxb_dom_node_insert_before_spec vs lxb_dom_node_insert_before etc.

I'm unaware of the current PHP implementation but I assume it is using the _spec versions throughout without any option to turn it off.

I think this is problematic. The NOIMPLIED option is very useful indeed if you want to handle document fragments etc. without unnecessary wrapper tags.

The above code leads to the peculiar situation that you can indeed create a Document with textNodes on the document level, but if you just want to replace that textNode with a different textNode it won't work. This complicates things a lot unnecessarily. Other methods like insertAdjacentHTML, appendChild etc are equally stubborn.

There are different solutions for this: IMHO the easiest one would be to use the non-spec versions of these functions if NOIMPLIED was specified. NOIMPLIED explicitly allows a non-spec document to be imported. Any manipulation should also be allowed then.

Another alternative would be to create a new general flag LIBXML_HTML_RELAX_SPEC.

A third alternative would be to specifically add option flags to the individual methods to allow this for a single call.

I'm unsure what's really the best solution but at the moment, porting over existing code is unnecessarily difficult due to this restriction and I really think this feature would make a lot of sense anyway. Thanks for considering.

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

まず、Dom\HTMLDocument::createFromString、LIBXML_HTML_NOIMPLIED、CharacterData::replaceWith() を使って PHP スニペットを再現します。replaceWith()、insertAdjacentHTML()、appendChild() がドキュメントレベルのテキストノードをどのように扱うかを追跡し、次に issue で言及されている仕様準拠および仕様非準拠の Lexbor エントリーポイントを比較します。NOIMPLIED ドキュメントに対する一貫した動作について明確な判断に到達し、それを実装または文書化し、示されているケースのテストを追加できれば完了です。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
c, php
領域
api, backend
issue の種類
機能追加
難易度
4/5
見積もり時間
3〜5日
活発さ
活発
明瞭さ
おおむね明確
初心者へのやさしさ
48/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。