DomdocumentとDomxPathは、XMLデータを処理するためにPHPを使用する場合、2つの非常に強力なツールです。特に複雑なXMLクエリが必要な場合、名前空間を使用するとXpath式を使用すると、柔軟性と精度が大幅に向上する可能性があります。この記事では、 RegisterXPathNamesPaceメソッドとカスタムXPath関数を組み合わせて、XMLクエリ機能を拡張および強化する方法を紹介します。
多くのXMLドキュメントでは、要素と属性には通常、名前空間プレフィックスがあります。例えば:
<span><span><span class="hljs-tag"><<span class="hljs-name">root</span></span></span><span> </span><span><span class="hljs-attr">xmlns:h</span></span><span>=</span><span><span class="hljs-string">"http://www.w3.org/TR/html4/"</span></span><span>>
</span><span><span class="hljs-tag"><<span class="hljs-name">h:table</span></span></span><span>>
</span><span><span class="hljs-tag"><<span class="hljs-name">h:tr</span></span></span><span>>
</span><span><span class="hljs-tag"><<span class="hljs-name">h:td</span></span></span><span>>Apples</span><span><span class="hljs-tag"></<span class="hljs-name">h:td</span></span></span><span>>
</span><span><span class="hljs-tag"><<span class="hljs-name">h:td</span></span></span><span>>Bananas</span><span><span class="hljs-tag"></<span class="hljs-name">h:td</span></span></span><span>>
</span><span><span class="hljs-tag"></<span class="hljs-name">h:tr</span></span></span><span>>
</span><span><span class="hljs-tag"></<span class="hljs-name">h:table</span></span></span><span>>
</span><span><span class="hljs-tag"></<span class="hljs-name">root</span></span></span><span>>
</span></span>
<h:td>などのノードを正しく照会するには、xpath式は、接頭辞hに対応する名前空間URIを知る必要があります。これは、 RegisterXPathNamesSpaceが役立つときです。
<span><span><span class="hljs-variable">$xml</span></span><span> = </span><span><span class="hljs-keyword">new</span></span><span> </span><span><span class="hljs-title class_">DOMDocument</span></span><span>();
</span><span><span class="hljs-variable">$xml</span></span><span>-></span><span><span class="hljs-title function_ invoke__">loadXML</span></span><span>(</span><span><span class="hljs-variable">$yourXmlString</span></span><span>);
</span><span><span class="hljs-variable">$xpath</span></span><span> = </span><span><span class="hljs-keyword">new</span></span><span> </span><span><span class="hljs-title class_">DOMXPath</span></span><span>(</span><span><span class="hljs-variable">$xml</span></span><span>);
</span><span><span class="hljs-variable">$xpath</span></span><span>-></span><span><span class="hljs-title function_ invoke__">registerNamespace</span></span><span>(</span><span><span class="hljs-string">"h"</span></span><span>, </span><span><span class="hljs-string">"http://www.w3.org/TR/html4/"</span></span><span>);
</span><span><span class="hljs-variable">$tds</span></span><span> = </span><span><span class="hljs-variable">$xpath</span></span><span>-></span><span><span class="hljs-title function_ invoke__">query</span></span><span>(</span><span><span class="hljs-string">"//h:td"</span></span><span>);
</span></span>
XPath言語自体は強力ですが、一部のビジネスロジックシナリオでは、組み込みのXPath関数はニーズを満たしていない場合があります。たとえば、関数を使用して、要素の値がデータベースまたは配列に表示されるかどうかを判断するか、より複雑な文字列処理を実行することをお勧めします。
PHPは、カスタム関数をXPathに注入することをサポートしませんが、クエリの結果を追跡するときにロジックを実装するためにPHP関数を呼び出すなど、回避策によって部分的にシミュレートできます。
ただし、XPathクエリを使用する前に名前空間を登録してXMLを事前に処理し、カスタム関数でノードセットを操作することがより一般的です。
名前空間を備えた複数の<item>ノードを含む次のXMLドキュメントがあるとします。
<span><span><span class="hljs-tag"><<span class="hljs-name">catalog</span></span></span><span> </span><span><span class="hljs-attr">xmlns:bk</span></span><span>=</span><span><span class="hljs-string">"http://example.com/book"</span></span><span>>
</span><span><span class="hljs-tag"><<span class="hljs-name">bk:item</span></span></span><span>>
</span><span><span class="hljs-tag"><<span class="hljs-name">bk:title</span></span></span><span>>PHP プログラミング</span><span><span class="hljs-tag"></<span class="hljs-name">bk:title</span></span></span><span>>
</span><span><span class="hljs-tag"><<span class="hljs-name">bk:price</span></span></span><span>>45</span><span><span class="hljs-tag"></<span class="hljs-name">bk:price</span></span></span><span>>
</span><span><span class="hljs-tag"></<span class="hljs-name">bk:item</span></span></span><span>>
</span><span><span class="hljs-tag"><<span class="hljs-name">bk:item</span></span></span><span>>
</span><span><span class="hljs-tag"><<span class="hljs-name">bk:title</span></span></span><span>>Java プログラミング</span><span><span class="hljs-tag"></<span class="hljs-name">bk:title</span></span></span><span>>
</span><span><span class="hljs-tag"><<span class="hljs-name">bk:price</span></span></span><span>>55</span><span><span class="hljs-tag"></<span class="hljs-name">bk:price</span></span></span><span>>
</span><span><span class="hljs-tag"></<span class="hljs-name">bk:item</span></span></span><span>>
</span><span><span class="hljs-tag"></<span class="hljs-name">catalog</span></span></span><span>>
</span></span>
50元未満の価格ですべての本のタイトルを照会したいと思います。 Xpath自体は数値比較をサポートしています:
<span><span><span class="hljs-variable">$xpath</span></span><span>-></span><span><span class="hljs-title function_ invoke__">registerNamespace</span></span><span>(</span><span><span class="hljs-string">"bk"</span></span><span>, </span><span><span class="hljs-string">"http://example.com/book"</span></span><span>);
</span><span><span class="hljs-variable">$nodes</span></span><span> = </span><span><span class="hljs-variable">$xpath</span></span><span>-></span><span><span class="hljs-title function_ invoke__">query</span></span><span>(</span><span><span class="hljs-string">"//bk:item[bk:price < 50]/bk:title"</span></span><span>);
</span><span><span class="hljs-keyword">foreach</span></span><span> (</span><span><span class="hljs-variable">$nodes</span></span><span> </span><span><span class="hljs-keyword">as</span></span><span> </span><span><span class="hljs-variable">$node</span></span><span>) {
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-variable">$node</span></span><span>->nodeValue . </span><span><span class="hljs-string">"\n"</span></span><span>;
}
</span></span>
より複雑なロジックを実装したい場合(50未満の価格とタイトルには「PHP」が含まれています)。複数のXPath条件を組み合わせることができます。
<span><span><span class="hljs-variable">$nodes</span></span><span> = </span><span><span class="hljs-variable">$xpath</span></span><span>-></span><span><span class="hljs-title function_ invoke__">query</span></span><span>(</span><span><span class="hljs-string">"//bk:item[bk:price < 50 and contains(bk:title, 'PHP')]/bk:title"</span></span><span>);
</span></span>
ただし、「キーワードテーブルに単語を含むタイトルを使用してノードのみを保持する」など、ロジックがより複雑な場合は、クエリの後にカスタム関数で結果をフィルタリングする必要があります。
<span><span><span class="hljs-variable">$keywords</span></span><span> = [</span><span><span class="hljs-string">'PHP'</span></span><span>, </span><span><span class="hljs-string">'MySQL'</span></span><span>, </span><span><span class="hljs-string">'Laravel'</span></span><span>];
</span><span><span class="hljs-variable">$nodes</span></span><span> = </span><span><span class="hljs-variable">$xpath</span></span><span>-></span><span><span class="hljs-title function_ invoke__">query</span></span><span>(</span><span><span class="hljs-string">"//bk:item/bk:title"</span></span><span>);
</span><span><span class="hljs-keyword">foreach</span></span><span> (</span><span><span class="hljs-variable">$nodes</span></span><span> </span><span><span class="hljs-keyword">as</span></span><span> </span><span><span class="hljs-variable">$node</span></span><span>) {
</span><span><span class="hljs-keyword">foreach</span></span><span> (</span><span><span class="hljs-variable">$keywords</span></span><span> </span><span><span class="hljs-keyword">as</span></span><span> </span><span><span class="hljs-variable">$word</span></span><span>) {
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-title function_ invoke__">stripos</span></span><span>(</span><span><span class="hljs-variable">$node</span></span><span>->nodeValue, </span><span><span class="hljs-variable">$word</span></span><span>) !== </span><span><span class="hljs-literal">false</span></span><span>) {
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-variable">$node</span></span><span>->nodeValue . </span><span><span class="hljs-string">"\n"</span></span><span>;
</span><span><span class="hljs-keyword">break</span></span><span>;
}
}
}
</span></span>
これはXPathクエリの結果の外側の論理処理ですが、基本的にXPathクエリ機能とPHPカスタムロジックを組み合わせています。
実際にPHP関数をXPathロジックに埋め込む必要がある場合は、 XSLTProcessorとPHP拡張機能を組み合わせることを検討してください。たとえば、論理的判断は、拡張機能( PHP:functionstring( 'your_function' 'などなど)を登録することによって実装されます。これは高次の使用法であり、PHPでXSL拡張機能を有効にし、セキュリティに注意を払う必要があります。