-HTMLおよびXMLドキュメントは、Web開発者にとってパンとバターのようなものです。 毎日、多くのHTMLドキュメントを作成する可能性があります。 Webサービスを使用して情報を抽出するため、適切なWebページからデータを取得するため、または単にWebサイトの機能テストを作成するために、それらの一部を時々解析する必要があります。 コンテンツの取得は簡単ですが、必要な情報を強調表示するためにどのように解析するのですか?
PHPには、XMLドキュメントを解析するための多くのツール(SimpleXML、DOM、XMLReaderなど)がすでに付属しています。 しかし、ドキュメントの構造に深く結び付けられた情報を抽出する必要があるとすぐに、すべてが必要なほど簡単ではありません。 もちろん、アイテムを選択する必要がある場合、XPathはあなたの親友ですが、学習曲線は非常に急です。 単純である必要がある表現でさえ面倒です。 たとえば、クラス「foo」を持つすべてのh1タグを見つけるためのXPath式は次のとおりです。
h1[contains(concat( ' ' , normalize-space(@ class ), ' ' ), ' foo ' )]
タグは複数のクラスを持つことができるため、式は複雑であることが判明しました。
式は、最初の2つのh1タグを選択しますが、3番目のタグは選択しません。< h1 class ="foo" > Foo </ h1 >
< h1 class ="foo bar" > Foo </ h1 >
< h1 class ="foobar bar" > Foo </ h1 >
もちろん、誰もがcssで同じことを行うと梨を砲撃するのと同じくらい簡単であることを知っています。
h1.foo
Symfony 2の機能テストでは、既にPHPにあるツールを使用してCSSセレクターのパワーと表現力を高める方法を探していました。 私が思いついた最初のアイデアは、CSSセレクターを同等のXPathに変換することでした。 しかし、それは可能ですか? 答えはむしろ「はい」です。
John Resigは、ほとんど同じトピックについて彼の投稿で次のように書いています。
CSSセレクターを同等のXPathに変換できるトークナイザー、パーサー、およびリンカーを作成するのは簡単な作業ではありません。 したがって、車輪を発明する代わりに、私は既存のライブラリを見ました。 すぐに、Pythonライブラリーであるlxmlに出会いました。 lxmlライブラリーのlxml.cssselectモジュールは必要なことを行います。 だから私は、PythonからPHP言語へのコードの翻訳に時間を費やし、いくつかのユニットテストを追加しました。
参考:symfony 1にはsfDomCssSelectorクラスがありますが、CSSセレクターをXPathに変換しません。 これはロボットに適していますが、非常に単純なCSSセレクターに限定されており、標準のXMLツールでは使用できません。
Symfony 2 CSS Selectorコンポーネントは、たった1つのことを行い、それをうまくやろうとします: CSSセレクターをXPath式に変換します 。 その使用は非常に簡単です。
use Symfony\Components\CssSelector\Parser;
$xpath = Parser::cssToXpath( 'h1.foo' );
現在、$ xpath変数には「h1 [contains(concat( ''、normalize-space(@class)、 '')、 'foo')]」が含まれています。
コンポーネントの使用方法の例を示しましょう。 私のブログのすべての投稿名とURLを取得したいとします(情報はfabien.potencier.org/articlesで入手可能です)。
use Symfony\Components\CssSelector\Parser;
$document = new \DOMDocument();
$document->loadHTMLFile( 'http://fabien.potencier.org/articles' );
$xpath = new \DOMXPath($document);
foreach ($xpath->query(Parser::cssToXpath( 'div.item > h4 > a' )) as $node)
{
printf( "%s (%s)\n" , $node->nodeValue, $node->getAttribute( 'href' ));
}
コードは非常に単純で、XPath式を使用する代わりに、パーサークラスにCSSセレクターをXPath式に変換させます。
$xpath->query(Parser::cssToXpath( 'div.item > h4 > a' ))
XMLドキュメントで作業している場合は、使用する名前空間を宣言する必要があることに注意してください。 整形式のXMLドキュメントのみを理解するSimpleXMLElementを使用してみましょう。
お気づきかもしれませんが、CSSセレクターは名前空間(xhtml | div)をサポートしています。$document = new \SimpleXMLElement( 'http://fabien.potencier.org/articles' , 0, true );
$document->registerXPathNamespace( 'xhtml' , 'http://www.w3.org/1999/xhtml' );
foreach ($document->xpath(Parser::cssToXpath( 'xhtml|div.item > xhtml|h4 > xhtml|a' )) as $node)
{
printf( "%s (%s)\n" , $node, $node[ 'href' ]);
}
この新しいCSS Selectorコンポーネントは、機能テストのためにSymfony 2で使用されます(ただし、今後数週間でわかるように、symfony 1とはまったく異なります)。
コンポーネントコードは良好なコードカバレッジで単体テストされているので、自由に使用してください (コードはSymfony \ Components \ CssSelector名前空間の Github: github.com/fabpot/symfonyにあります )。フィードバックを残してください。