私は長年フロントエンド開発に携わってきましたが、ここ数年で傾向が見えてきました。それは、若い開発者がプロ​​グラミングの歴史的背景を理解せずに、新しいプログラミング パラダイムに取り組んでいることです。 もちろん、何かを知らないことは十分に理解できます。ウェブは非常に大きな場所であり、さまざまなスキルや専門分野が存在するため、私たちは自分が何を知らないのかを常に知っているわけではありません。この分野での学習は、一度起こって終わるものではなく、継続的な旅です。 好例: 私のチームの誰かが、ユーザーが UI の特定のタブから移動したかどうかを知ることができるかどうか尋ねました。 JavaScript の beforeunload イベントについて指摘しました。しかし、これまでにこれに取り組んだことのある人は、他のサイトで保存されていないデータに関するアラートが表示されたことがあり、これが可能であることを知っています。これは、アンロード前が典型的な使用例です。また、念のため、同僚に pageHide イベントと VisibilityChange イベントについても指摘しました。 どうやってそのことを知りましたか?それは別のプロジェクトで思いついたからであり、最初に JavaScript を学習したときにそれについて勉強したからではありません。 実際のところ、最新のフロントエンド フレームワークは、それ以前の巨大テクノロジー企業の肩の上に立っています。これらは開発プラクティスを抽象化し、多くの場合、開発者エクスペリエンスを向上させるため、これまで誰もがおそらく知っておくべき重要なフロントエンド概念を知ったり触れたりする必要性を減らしたり、さらには排除したりします。 CSS オブジェクト モデル (CSSOM) について考えてみましょう。 CSS と JavaScript を扱う人は誰でも CSSOM の実践経験を積んでいると思われるかもしれませんが、必ずしもそうとは限りません。 私が取り組んだ電子商取引サイトの React プロジェクトでは、現在選択されている決済プロバイダーのスタイルシートを読み込む必要がありました。問題は、スタイルシートが特定のページでのみ必要であるにもかかわらず、すべてのページに読み込まれてしまうことでした。これを実現する任務を負った開発者は、スタイルシートを動的にロードしたことがありませんでした。繰り返しになりますが、React が従来のアプローチを抽象化していることを考えると、これは完全に理解できます。 CSSOM は、日常の仕事ではおそらく必要ありません。ただし、たとえ 1 回限りであっても、ある時点でそれを操作する必要がある可能性があります。 これらの経験が私にこの記事を書くきっかけを与えてくれました。日常の業務では直接触れることのない、多くの既存の Web 機能やテクノロジーが世に出ています。おそらく、あなたは Web 開発にあまり慣れておらず、特定のフレームワークの抽象化にどっぷり浸かっていて、それを深く知る必要がない、あるいはまったく知らないため、単にそれらに気づいていないだけかもしれません。 私は特に XML について話しています。XML は HTML と全く変わらない古代の言語であることは多くの人が知っています。 私がこれを取り上げたのは、XSLT プログラミングとして知られる XML スタックの重要な部分をブラウザーから削除する必要があると示唆する最近の WHATWG の議論のためです。これはまさに、私たちが長年にわたって保有してきた古い既存のテクノロジーであり、私のチームが陥っていた CSSOM の状況と同じくらい実用的なものに使用できます。 これまでに XSLT を使用したことがありますか?この古いテクノロジーに大きく依存し、XML のコンテキストの外でその機能を活用して、今日の現実世界の問題に取り組むかどうかを見てみましょう。 XPath: 中央 API 単純な XML の観点以外でおそらく最も役立つ最も重要な XML テクノロジは XPath です。XPath は、1 つのルート要素を持つマークアップ ツリー内の任意のノードまたは属性を検索できるクエリ言語です。私は XSLT に個人的な愛情を持っていますが、それは XPath にも依存しているため、ランキングの重要性では個人的な愛情は脇に置く必要があります。 XSLT を削除するという議論では XPath については何も言及されていないので、まだ許可されていると思います。 XPath は、特に通常の XML の使用以外で使用するものを見つけようとする場合に、この一連のテクノロジーの中心的かつ最も重要な API であるため、これは良いことです。 CSS セレクターを使用してページ内のほとんどの要素を検索できますが、すべての要素を検索できるわけではないため、これは重要です。さらに、CSS セレクターを使用して、DOM 内の現在の位置に基づいて要素を検索することはできません。 XPathは可能です。 さて、これを読んでいる人の中には XPath を知っている人もいれば、知らない人もいるかもしれません。 XPath は非常に大きなテクノロジー分野であり、このような 1 つの記事ですべての基本を説明し、XPath を使った素晴らしい方法を紹介することはできません。実際にその記事を書いてみましたが、スマッシング マガジンの平均的な記事は 5,000 ワードを超えません。私はすでに以上でした基礎の半分しかないのに2,000語。 そこで、XPath を使って素晴らしいことを始めて、このことに興味を持った場合に基本に使用できるリンクをいくつか紹介します。 XPath と CSS の組み合わせ XPath は、要素をクエリするときに CSS セレクターではできない多くのことを実行できます。ただし、CSS セレクターは、XPath ではできないこと、つまりクラス名による要素のクエリも実行できます。

CSS XPath .myClass /*[contains(@class, "myClass")]

この例では、CSS は .myClass クラス名を含む要素をクエリします。一方、XPath の例では、文字列「myClass」を持つ属性クラスを含む要素をクエリします。つまり、.myClass クラス名を持つ要素や、.myClass2 などの文字列に「myClass」を持つ要素など、任意の属性に myClass を持つ要素が選択されます。その意味では、XPath はより広範です。 だから、いいえ。 CSS を捨てて XPath 経由ですべての要素を選択し始めるべきだと言っているわけではありません。それは重要ではありません。 重要なのは、XPath はブラウザ スタックの古いテクノロジであり、一見すると明白ではないように見えても、CSS ではできないことを実行でき、依然として非常に役立つ可能性があるということです。 2 つのテクノロジーを一緒に使用しましょう。それができるからだけではなく、その過程で XPath について学び、XPath をスタック内の別のツールにするためです。ずっと存在していたことを知らなかったかもしれません。 問題は、JavaScript の document.evaluate メソッドと、JavaScript 用の CSS API で使用するさまざまなクエリ セレクター メソッドに互換性がないことです。 始めるために互換性のあるクエリ API を作成しましたが、確かに、ここで行っていることとは異なるため、あまり深く考えていません。以下は、再利用可能なクエリ コンストラクターの非常に単純な実際の例です。 Bryan Rasmussen による Pen queryXPath [forked] を参照してください。 ドキュメント オブジェクトに 2 つのメソッド、queryCSSSelectors (本質的には querySelectorAll) と queryXPaths を追加しました。これらはどちらも queryResults オブジェクトを返します。

{ クエリの種類: ノード |文字列 |番号 |ブール値、 結果: any[] // html 要素、xml 要素、文字列、数値、ブール値、 queryCSSSelectors: (クエリ: 文字列、修正: ブール値) => queryResults、 queryXpaths: (クエリ: 文字列、修正: ブール値) => queryResults }

queryCSSSelectors 関数と queryXpaths 関数は、結果の配列がノード型である限り、結果の配列内の要素に対して指定されたクエリを実行します。それ以外の場合は、空の配列とノードのタイプを含む queryResult が返されます。 amend プロパティが true に設定されている場合、関数は独自の queryResults を変更します。 いかなる状況でも、これを運用環境で使用しないでください。このようにしているのは、純粋に 2 つのクエリ API を一緒に使用することによるさまざまな効果を示すためです。 クエリの例 さまざまな XPath クエリの例をいくつか示し、XPath クエリで実行できる強力な機能と、他のアプローチの代わりに XPath クエリを使用する方法を示したいと思います。 最初の例は //li/text() です。これはすべての li 要素をクエリし、そのテキスト ノードを返します。したがって、次の HTML をクエリするとします。

  • 1 つ
  • 2 つ
  • 3 つ

…これが返されます:

{"queryType":"xpathEvaluate","results":["one","two","three"],"resultType":"string"}

つまり、配列 ["one","two","three"] が得られます。 通常、li 要素をクエリしてそれを取得し、そのクエリの結果を配列に変換し、配列をマップして、各要素のテキスト ノードを返します。しかし、XPath を使用すると、これをより簡潔に行うことができます。 document.queryXPaths("//li/text()").results。

テキスト ノードを取得する方法は text() を使用することです。これは関数シグネチャのように見えますが、実際そのとおりです。要素のテキスト ノードを返します。この例では、マークアップに 3 つの li 要素があり、それぞれにテキスト (「one」、「two」、「three」) が含まれています。 text() クエリのもう 1 つの例を見てみましょう。これが私たちのマークアップであると仮定します。 サインイン

href 属性値を返すクエリを作成してみましょう。 document.queryXPaths("//a[text() = 'サインイン']/@href").results.

これは、最後の例と同様に、現在のドキュメントに対する XPath クエリですが、今回は「サインイン」というテキストを含むリンク (要素) の href 属性を返します。実際に戻ってきたのは結果は ["/login.html"] です。 XPath 関数の概要 XPath 関数は多数ありますが、おそらく馴染みのない関数です。以下のような、知っておく価値のあることがいくつかあると思います。

begins-withテキストが他の特定のテキスト例で始まる場合、href 属性が http: で始まる場合、starts-with(@href, 'http:') は true を返します。 containsテキストに他の特定のテキスト例が含まれている場合、テキスト ノードのどこかに「Smashing Magazine」という単語が含まれている場合、contains(text(), "Smashing Magazine") は true を返します。 countクエリに一致する件数を返します。たとえば、count(//*[starts-with(@href, 'http:']) は、http: で始まるテキストを含む href 属性を持つ要素を持つコンテキスト ノード内のリンクの数を返します。 substring は、文字列を引数として渡す点を除いて、JavaScript の部分文字列と同様に機能します。たとえば、substring("my text", 2, 4) は「y t」を返します。 substring-before別の文字列の前の文字列の部分を返します。たとえば、substing-before("my text", " ") は "my" を返します。同様に、substring-before("hi","bye") は空の文字列を返します。 substring-after別の文字列の後の文字列の部分を返します。たとえば、substing-after("my text", " ") は "text" を返します。同様に、substring-after("hi","bye") は空の文字列を返します。 Normalize-space先頭と末尾の空白を削除し、一連の空白文字を単一のスペースに置き換えることによって正規化された空白を含む引数文字列を返します。 not引数が false の場合はブール値 true、それ以外の場合は false を返します。 trueブール値の true を返します。 falseブール値の false を返します。 concat JavaScript concat と同じですが、文字列のメソッドとして実行しない点が異なります。代わりに、連結したいすべての文字列を入力します。 string-lengthこれは JavaScript の string-length と同じではなく、引数として指定された文字列の長さを返します。 translationThis は文字列を受け取り、2 番目の引数を 3 番目の引数に変更します。たとえば、translate("abcdef", "abc", "XYZ") は XYZdef を出力します。

これらの特定の XPath 関数とは別に、JavaScript の対応する関数 (または基本的にあらゆるプログラミング言語の対応する関数) とまったく同じように機能する関数が他にも多数あります。これらの関数もおそらく便利だと思われます (floor、ceiling、round、sum など)。 次のデモは、これらの各機能を示しています。 Bryan Rasmussen による「Pen XPath Numerical function [forked]」を参照してください。 ほとんどの文字列操作関数と同様、数値操作関数の多くは 1 つの入力を受け取ることに注意してください。もちろん、これは、最後の XPath の例のように、クエリに使用されることを想定しているためです。 //li[floor(text()) > 250]/@val

これらを使用すると、ほとんどの例と同様に、パスに一致する最初のノードで実行されることになります。 JavaScript にはすでに独自の型変換の問題があるため、おそらく避けるべき型変換関数もいくつかあります。ただし、他の数値と比較するために文字列を数値に変換したい場合があります。 何かのタイプを設定する関数は、ブール値、数値、文字列、およびノードです。これらは重要な XPath データ型です。 ご想像のとおり、これらの関数のほとんどは DOM ノードではないデータ型で使用できます。たとえば、すでに説明したように、substring-after は文字列を受け取りますが、href 属性からの文字列である可能性があります。単なる文字列にすることもできます。

const testSubstringAfter = document.queryXPaths("substring-after('hello world',' ')");

明らかに、この例では結果の配列が ["world"] として返されます。これを実際に示すために、DOM ノードではないものに対する関数を使用してデモ ページを作成しました。 Bryan Rasmussen による Pen queryXPath [forked] を参照してください。 翻訳関数の驚くべき側面に注意してください。それは、2 番目の引数 (つまり、翻訳する文字のリスト) に文字があり、翻訳先の一致する文字がない場合、その文字は出力から削除されるということです。 したがって、これは次のようになります。

translation('こんにちは、私の名前はイニゴ・モントーヤです、あなたは私の父を殺しました、死ぬ準備をしてください','abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,','*')

…結果はスペースを含む文字列になります。 [" * * ** "]

これは、文字「a」はアスタリスク (*) に変換されますが、ターゲット文字列を考慮すると、変換されない他の文字はすべて完全に削除されることを意味します。残っているのは空白だけです翻訳された「a」文字の間。 もう一度、このクエリ:

translation('こんにちは、私の名前はイニゴ・モントーヤです、あなたは私の父を殺しました、死ぬ準備をしてください','abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,','**************************************************')")

…問題はなく、次のような結果が出力されます。

「***** ** **** ** ***** ******* ******* ** ****** ******* ** ***」

XPath 変換関数が行うこととまったく同じことを JavaScript で行う簡単な方法はないと思われるかもしれませんが、多くの使用例では正規表現を使用した replaceAll で処理できます。 私が示したのと同じアプローチを使用することもできますが、文字列を翻訳したいだけの場合、それは次善の策です。次のデモは、XPath の翻訳関数をラップして JavaScript バージョンを提供します。 Bryan Rasmussen によるペン翻訳関数 [フォーク] を参照してください。 このようなものをどこで使用できますか? 3 桁のオフセットを持つ Caesar Cipher 暗号化 (たとえば、紀元前 48 年の最上位暗号化) を考えてみましょう。

translation("カエサルはルビコン川を渡るつもりだ!", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", "XYZABCDEFGHIJKLMNOPQRSTUVWxyzabcdefghijklmnopqrstuvw")

入力テキスト「シーザーはルビコン川を渡ることを計画しています!」結果は「Zxbpxo fp mixkkfkd ql zolpp qeb Oryfzlk!」になります。 さまざまな可能性の別の簡単な例を示すために、文字列入力を受け取り、translate 関数を使用して、ウムラウトを受け取るすべての文字を含むテキストを返すメタル関数を作成しました。 Bryan Rasmussen によるペン メタル関数 [フォーク] を参照してください。

const metal = (str) => { return translation(str, "AOUaou","ÄÖÜäöü"); }

また、「モトリー クルーのルール、ロック オン ガイ!」というテキストが与えられた場合、「モトリー クルーのルール、ロック オン ガイ!」が返されます。 明らかに、この関数をあらゆる種類のパロディで使用することができるでしょう。もしあなたがそうなら、この TVTropes の記事はたくさんのインスピレーションを与えてくれるはずです。 XPath での CSS の使用 CSS セレクターを XPath と併用する主な理由を思い出してください。CSS はクラスが何であるかをほぼ理解していますが、XPath でできるのはクラス属性の文字列比較です。ほとんどの場合、これでうまくいきます。 しかし、たとえば、誰かが .primaryLinks および .primaryLinks2 という名前のクラスを作成し、XPath を使用して .primaryLinks クラスを取得しているような状況に遭遇した場合、問題が発生する可能性があります。そのような愚かなことがない限り、おそらく XPath を使用するでしょう。しかし、悲しいことに、私は人々がそのような愚かなことをする場所で働いてきたことを報告します。 CSS と XPath を一緒に使用した別のデモを次に示します。これは、コードを使用してドキュメントのノードではないコンテキスト ノードで XPath を実行すると何が起こるかを示しています。 Bryan Rasmussen による Pen css と xpath を一緒に [フォークした] を参照してください。 CSS クエリは .relativearticles a で、 .relativearticles クラスが割り当てられた div 内の 2 つの a 要素を取得します。 その後に 3 つの「悪い」クエリが続きます。つまり、これらの要素をコンテキスト ノードとして実行したときに実行してもらいたいことを実行しないクエリです。 なぜ彼らがあなたの予想とは異なる行動をとるのか、私は説明できます。問題となっている 3 つの不正なクエリは次のとおりです。

//text(): ドキュメント内のすべてのテキストを返します。 //a/text(): ドキュメント内のリンク内のすべてのテキストを返します。 ./a/text(): 結果を返しません。

このような結果が生じる理由は、コンテキストが CSS クエリから返された要素である一方で、 // がドキュメント全体に反しているためです。これが XPath の強みです。 CSS は、ノードから上位の祖先に到達し、さらにその祖先の兄弟に到達し、その兄弟の子孫に到達することはできません。しかし、XPath ならそれが可能です。 一方、./ は現在のノードの子をクエリします。ドット (.) は現在のノードを表し、スラッシュ (/) は子ノードへの移動を表します。属性、要素、テキストのいずれであるかは、パスの次の部分によって決まります。しかし、CSS クエリによって選択された要素には子要素がないため、そのクエリも何も返しません。 最後のデモには 3 つの優れたクエリがあります。

.//text()、 ./text()、 正規化スペース(./text())。

空間正規化クエリは XPath 関数の使用法を示しますが、他のクエリに含まれる問題も修正します。 HTML は次のような構造になっています。

Selenium WebDriver を使用して機能テストを自動化する

クエリはテキスト ノードの先頭と末尾に改行を返します。そして、normalize-space はこれを削除します。 入力 XPath でブール値以外を返す XPath 関数の使用は、他の関数にも適用されます。次のデモでは、いくつかの例を示します。 Bryan Rasmussen による Pen xpath 関数の例 [フォーク] を参照してください。 最初の例は、注意すべき問題を示しています。具体的には、次のコードです。

document.queryXPaths("substring-after(//a/@href,'https://')");

…1 つの文字列を返します。

「www.smashingmagazine.com/2018/04/feature-testing-selenium-webdriver/」

それは当然ですよね?これらの関数は配列ではなく、単一の文字列または単一の数値を返します。複数の結果がある任意の場所で関数を実行すると、最初の結果のみが返されます。 2 番目の結果は、本当に必要なものを示しています。

document.queryCSSSelectors("a").queryXPaths("substring-after(./@href,'https://')");

これは 2 つの文字列の配列を返します。

["www.smashingmagazine.com/2018/04/feature-testing-selenium-webdriver/"、"www.smashingmagazine.com/2022/11/automated-test-results-improve-accessibility/"]

XPath 関数は、JavaScript の関数と同様にネストできます。したがって、Smashing Magazine の URL 構造がわかっていれば、次のことができます (テンプレート リテラルの使用をお勧めします)。 `翻訳( 部分文字列( substring-after(./@href, ‘www.smashingmagazine.com/’) 、9)、 '/','')`

これは、内容を説明するコメントが必要なほど少し複雑になりすぎています。www.smashingmagazine.com/ の後の href 属性からすべての URL を取得し、最初の 9 文字を削除し、その後、末尾のスラッシュを取り除くためにスラッシュ (/) 文字を何も変換しません。 結果の配列は次のようになります。

["機能テスト-Selenium-Webdriver","自動テスト結果-アクセシビリティの向上"]

XPath のその他の使用例 XPath はテストで真価を発揮します。その理由を理解するのは難しくありません。XPath を使用すると、DOM 内の任意の位置からすべての要素を取得できますが、CSS はそれができないからです。 最新のビルド システムの多くでは、CSS クラスの一貫性が保たれるとは期待できませんが、XPath を使用すると、DOM 構造の変化に関係なく、要素のテキスト コンテンツが何であるかについて、より堅牢な一致を行うことができます。 回復力のある XPath テストを可能にする技術についての研究が行われています。何かの名前が変更されたり削除されたりしたために CSS セレクターが機能しなくなったという理由だけで、テストが不安定になって失敗することほど悪いことはありません。 XPath は、複数のロケーターの抽出にも非常に優れています。 XPath クエリを使用して要素を照合する方法は複数あります。 CSS についても同様です。ただし、XPath クエリでは、返される内容を制限するより的を絞った方法で詳細を掘り下げることができるため、一致する可能性のあるものが複数ある場合でも、特定の一致を見つけることができます。 たとえば、XPath を使用して、兄弟 div の直後にある div 内に含まれる特定の h2 要素を返すことができます。この div には、data-testID="leader" 属性を持つ子イメージ要素が含まれています。

この見出しは理解できない

この見出しも理解できません

リーダー画像のヘッダー

これがクエリです: document.queryXPaths(` //div[ 次の兄弟::div[1] /img[@data-testID='リーダー'] 】 /h2/ テキスト() `);

デモを導入して、すべてがどのように行われるかを確認してみましょう。 Bryan Rasmussen による Pen Complex H2 クエリ [フォーク] を参照してください。 はい。 XPath を使用したテストでは、あらゆる要素への可能なパスが多数あります。 XSLT 1.0 の非推奨 冒頭で、Chrome チームがブラウザーから XSLT 1.0 サポートを削除する予定であると述べました。 XSLT 1.0 はドキュメント変換に XML に重点を置いたプログラミングを使用し、その結果、ほとんどのブラウザーに搭載されている XPath 1.0 に依存するため、これは重要です。 そうなると、XPath の重要なコンポーネントが失われます。しかし、XPath がテストを書くのに非常に優れているという事実を考えると、XPath 全体がすぐに消える可能性は低いと思います。 そうは言っても、人々はその機能が削除されると、その機能に興味を持つことに気づきました。 XSLT 1.0 が非推奨になる場合にも、それは確かに当てはまります。 Hacker News では、非推奨に反対する議論でいっぱいの議論が行われています。この投稿自体は、XSLT を使用してブログ フレームワークを作成する優れた例です。あなたディスカッションは自分で読むことができますが、この種のケースを処理するために JavaScript が XLST のシムとしてどのように使用されるかについて説明します。 また、ブラウザーは JavaScript の Saxon XSLT、XQUERY、および XPath エンジンへのポートである SaxonJS を使用するべきだという提案も目にしました。これは興味深いアイデアです。特に、Saxon-JS はこれらの仕様の現在のバージョンを実装していますが、1.0 以降のバージョンの XPath または XSLT を実装するブラウザは存在せず、XQuery を実装するブラウザも存在しません。 私は、SaxonJS およびその他のバージョンの Saxon エンジンを開発している会社、Saxonica の Norm Tovey-Walsh 氏に連絡を取りました。彼はこう言いました。 「最新の XML テクノロジーをブラウザーに統合するための出発点として SaxonJS を採用することに興味のあるブラウザー ベンダーがあれば、喜んで彼らと話し合うでしょう。」— Norm Tovey-Walsh

しかし、次のようにも付け加えました。 「SaxonJS を現在の形式で取り込み、変更せずにブラウザーのビルドに組み込むことが理想的なアプローチであると考える人がいたら、私は非常に驚きます。ブラウザー ベンダーは、ブラウザーを構築するという性質上、私たちが『外部から』できるよりもはるかに深いレベルで統合にアプローチできる可能性があります。」- Norm Tovey-Walsh

Tovey-Walsh のコメントが XSLT の非推奨の発表の約 1 週間前に発表されたことは注目に値します。 結論 ずっと続けることができました。しかし、これで XPath の威力が実証され、素晴らしいことを達成するために XPath を使用する方法を示す多くの例が示されたことを願っています。これは、ブラウザ スタックの古いテクノロジの好例であり、たとえその存在を知らなかったとしても、あるいは手に入れようと思ったこともなかったとしても、現在でも十分な有用性を持っています。 さらに読む

『Enhancing the Resiliency of Automated Web Tests with Natural Language』 (ACM Digital Library) Maroun Ayli、Youssef Bakuny、Nader Jalloul、Rima Kilany 著この記事では、回復力のあるテストを作成するための XPath の例を多数紹介します。 XPath (MDN)これは、XPath がどのように機能するかについて詳しく説明する技術的な説明が必要な場合に開始するのに最適な場所です。 XPath チュートリアル (ZVON) 豊富な例と明確な説明のおかげで、このチュートリアルが私自身の学習に最も役​​立つことがわかりました。 XPatherこの対話型ツールを使用すると、コードを直接操作できます。

You May Also Like

Enjoyed This Article?

Get weekly tips on growing your audience and monetizing your content — straight to your inbox.

No spam. Join 138,000+ creators. Unsubscribe anytime.

Create Your Free Bio Page

Join 138,000+ creators on Seemless.

Get Started Free