Jsdom: innerTextの実装

作成日 2015年09月25日  ·  26コメント  ·  ソース: jsdom/jsdom

jsdomは、Webスクレイピングに最適なツールです。 ただし、 textContentは、html2text変換用の読み取り可能なテキストを取得するための非常に不便な方法です。

多くの場合、ごくわずかなinnerText有用性についてのすばらしい記事があります。

http://perfectionkills.com/the-poor-misunderstood-innerText/

著者は、非常に遅い回避策としてgetSelection().toString()を提案していますが、 getSelectionはまだjsdomに実装されていません。

jsdomにinnerTextを実装することを検討していただけますか? 著者はそれについて素晴らしい調査を行い、最後に簡単な仕様を追加しました。

feature layout

最も参考になるコメント

他の誰かがこの問題に遭遇した場合、私はそれをさらに一歩進め、 sanitize-htmlパッケージを使用して、基本的にブラウザーが実行していることを取得しました(JSDOMセットアップは不要であることがわかったため、インポートしなかったことに注意してください)これを私のJestセットアップファイルに入れるときですが、Jestを使用していない場合は、 @ benypowersが推奨するglobal.Element = (new JSDOM()).window.Elementセットアップを使用することをお勧めします):

Object.defineProperty(global.Element.prototype, 'innerText', {
  get() {
    return sanitizeHtml(this.textContent, {
      allowedTags: [], // remove all tags and return text content only
      allowedAttributes: {}, // remove all tags and return text content only
    });
  },
  configurable: true, // make it so that it doesn't blow chunks on re-running tests with things like --watch
});

全てのコメント26件

rangyこととどのような残念SelectioninnerText :ライブラリはjsdomと互換性がありませんhttps://github.com/timdown/rangy/issues/348

したがって、innerTextは標準ではなく、少なくとも1つの主要なエンジン(Firefox)に実装されていません。 標準がなければ、実装すべきではないと思います。

ここにドラフト仕様があるため、この全体に動きがあるようリファレンスも参照して

Firefoxが実装しました: https

承認するWHATWGsemms: https

仕様からすると、基本的なレイアウトのサポートなしではinnerText適切に実装できないようです。

ええ、これはとにかくjsdomで実際に実装可能になることはなく、多くのインフラストラクチャの作業がなければ...誰も彼らの希望を得ることができません:(。

レイアウトサポート要件について: https

WHATWGの採用により、実装する予定はありますか?

ええ...仕様にはjsdomにはない多くのものが必要ですが、CSSボックスの周り:(。何をすべきかわからない。

これをjsdomと一緒にプラグインするためのライブラリはありますか?

@domenicは、なぜこれがそのようなインフラストラクチャのオーバーホールであるかについての知識を落とす

よろしくお願いします🙏/ cc @vsemozhetbyt

主な問題は、 innerTextがガイダンスのためにレイアウトエンジンに依存しており、jsdomにはレイアウトエンジンがないという事実です。 https://html.spec.whatwg.org/multipage/dom.html#the-innertext-idl-attributeおよび
http://perfectionkills.com/the-poor-misunderstood-innerText/ 。 2番目のリンクから:

innerTextが、テキストがページにどのように表示されるかをほぼ正確に表していることに注目してください。 一方、textContentは奇妙なことをします—それはによって作成された改行を無視します
ブロックとしてスタイル設定された要素(この場合)の周囲ただし、マークアップで定義されているスペースは保持されます。

まだ範囲外で回避策はありませんか?

どうやら仕様は言う:

この要素がレンダリングされていない場合、またはユーザーエージェントが非CSSユーザーエージェントである場合、 [強調を追加]すると、この要素のtextContentIDL属性と同じ値が返されます。

回避策は、単にtextContent返すことだと思います。

私たちは十分なCSSを実装しているので、それは当てはまらないと思います。 レイアウトパーツは実装していません...

こんにちはみんな、これに関するニュースはありますか?

ヘッドレスクロームを使用するだけです:)

@corehが言及したその仕様からの@domenic
https://html.spec.whatwg.org/multipage/dom.html#the -innertext-idl-attribute

この要素がレンダリングされていない場合、またはユーザーエージェントが非CSSユーザーエージェントである場合は、この要素のtextContent IDL属性と同じ値を返します。

https://html.spec.whatwg.org/multipage/rendering.html#being -rendered

要素にCSSレイアウトボックス、SVGレイアウトボックス、または他のスタイル言語の同等のものが関連付けられている場合、その要素はレンダリングされます

jsdomがレイアウトパーツを実装していない場合、それは「レンダリングされていない」という意味ではありませんか?

このメッセージは、関数の実装を変更せずにテストに合格する方法が必要な、このgithubスレッドに到達した人を対象としています。

テストファイルの先頭のコピーパスタ:

// Expose JSDOM Element constructor
global.Element = (new JSDOM()).window.Element;
// 'Implement' innerText in JSDOM: https://github.com/jsdom/jsdom/issues/1245
Object.defineProperty(global.Element.prototype, 'innerText', {
  get() {
    return this.textContent;
  },
});

当然、上記の説明からの警告が適用されます。

他の誰かがこの問題に遭遇した場合、私はそれをさらに一歩進め、 sanitize-htmlパッケージを使用して、基本的にブラウザーが実行していることを取得しました(JSDOMセットアップは不要であることがわかったため、インポートしなかったことに注意してください)これを私のJestセットアップファイルに入れるときですが、Jestを使用していない場合は、 @ benypowersが推奨するglobal.Element = (new JSDOM()).window.Elementセットアップを使用することをお勧めします):

Object.defineProperty(global.Element.prototype, 'innerText', {
  get() {
    return sanitizeHtml(this.textContent, {
      allowedTags: [], // remove all tags and return text content only
      allowedAttributes: {}, // remove all tags and return text content only
    });
  },
  configurable: true, // make it so that it doesn't blow chunks on re-running tests with things like --watch
});

私も同様のニーズがありましたが、 textContentを使用するだけではなく、少し先に進みたいと思っていました。これも、特にcssによって隠された要素に関して、ブラウザーが実際に行うことを正確に表したものではありませんが、それは良いことです。私のユースケースには十分です:

function innerText(el)
  el = el.cloneNode(true) // can skip if mutability isn't a concern
  el.querySelectorAll('script,style').forEach(s => s.remove())
  return el.textContent
}

お気の毒に!

どうやら仕様は言う:

この要素がレンダリングされていない場合、またはユーザーエージェントが非CSSユーザーエージェントである場合、[強調を追加]すると、この要素のtextContentIDL属性と同じ値が返されます。

回避策は、単にtextContentを返すことだと思います。

私たちは十分なCSSを実装しているので、それは当てはまらないと思います。 レイアウトパーツは実装していません...

@domenicは、仕様のより自由な解釈を検討してください

textContentは、CSSルールの適用が高すぎる場合、フォールバックとして明示的に許可されます

また、innerTextはgetterおよびsetterとして指定されます

私がスペックエディターであることを考えると、「CSSルールの適用が高すぎる場合」はスペックが言っていることではないと確信を持って述べることができます。

..それは「ユーザーエージェントが非CSSユーザーエージェントである場合」の私の解釈でした

「CSSユーザーエージェント」と「非CSSユーザーエージェント」の違いは何ですか?

どうですか:
CSSユーザーエージェントは「CSSルールを適用」して結果を出力できます(グラフィックまたはテキスト)
非CSSユーザーエージェントは「CSSルールを適用する」にはあまりにも愚かです

私たちは十分なCSSを実装しているので、それは当てはまらないと思います。

どういう意味? window.getComputedStyle?

textContentへのフォールバックは、標準のインターフェースを実装しないよりも優れています

たぶん、 textContent値を使用して、テストの実行中にinnerText結果をjsdom置き換えることができます。 例えば:

describe('mytest', () => {
  beforeAll(() => {
    Object.defineProperty(HTMLElement.prototype, 'innerText', {
      get() {
        return this.textContent;
      }
    });
  });
  it('should ok', () => {
  // test assertions
  });
});
このページは役に立ちましたか?
0 / 5 - 0 評価