首页 > 解决方案 > 使用 Xpath 进行部分匹配

问题描述

我正在尝试创建一个搜索功能,允许使用 Xpath 按歌曲标题或流派进行部分匹配。

这是我的 XML 文件:

<?xml version="1.0" encoding="UTF-8"?>
<playlist>
  <item>
    <songid>USAT29902236</songid>
    <songtitle>I Say a Little Prayer</songtitle>
    <artist>Aretha Franklin</artist>
    <genre>Soul</genre>
    <link>https://www.amazon.com/I-Say-a-Little-Prayer/dp/B001BZD6KO</link>
    <releaseyear>1968</releaseyear>
  </item>
  <item>
    <songid>GBAAM8300001</songid>
    <songtitle>Every Breath You Take</songtitle>
    <artist>The Police</artist>
    <genre>Pop/Rock</genre>
    <link>https://www.amazon.com/Every-Breath-You-Take-Police/dp/B000008JI6</link>
    <releaseyear>1983</releaseyear>
  </item>
  <item>
    <songid>GBBBN7902002</songid>
    <songtitle>London Calling</songtitle>
    <artist>The Clash</artist>
    <genre>Post-punk</genre>
    <link>https://www.amazon.com/London-Calling-Remastered/dp/B00EQRJNTM</link>
    <releaseyear>1979</releaseyear>
  </item>
</playlist>

到目前为止,这是我的搜索功能:

function searchSong($words){
    global $xml;

    if(!empty($words)){
        foreach($words as $word){
            //$query = "//playlist/item[contains(songtitle/genre, '{$word}')]";
            $query = "//playlist/item[(songtitle[contains('{$word}')]) and (genre[contains('{$word}')])]";
            $result = $xml->xpath($query);
        }
    }

    print_r($result);
}

调用该函数searchSong(array("take", "soul"))应该从 XML 文件中返回第二首和第一首歌曲,但数组始终为空。

标签: phpxmlxpath

解决方案


这里有一些错误:使用 ofand而不是or,假设搜索不区分大小写,并且将错误数量的参数传递给contains. 如果您正在寻找它们,最后一个会触发 PHP 警告。此外,您只会返回您搜索的最后一个项目。

XPath 1.0(这是所有 PHP 支持的)中不区分大小写的搜索是一件非常痛苦的事情:

$result = $xml->query(
    "//playlist/item[(songtitle[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '{$word}')]) or (genre[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '{$word}')])]"
);

这假设您已经获取了搜索词并将它们转换为小写。例如:

<?php

function searchSong($xpath, ...$words)
{
    $return = [];
    foreach($words as $word) {
        $word = strtolower($word);
        $q = "//playlist/item[(songtitle[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '{$word}')]) or (genre[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '{$word}')])]";
        $result = $xpath->query($q);
        foreach($result as $node) {
            $return[] = $node;
        }
    }
    return $return;
}

推荐阅读