SimpleXML 的 Xpath 不太适合完成整个工作。尤其是不区分大小写的搜索非常尴尬-实际上您在相关问题中遇到了太多问题。
简化工作的一种方法是将其划分。例如,首先获取所有有趣元素/属性的列表,然后过滤它们,然后获取它们的所有父元素。
这可以通过将 xpath 结果(它是一个数组)转换为Iterator
$string   = "sample";
$names    = $xml->xpath('//ITEM/@NAME');
$filtered = new LaxStringFilterIterator($names, $string);
$items    = new SimpleXMLParentNodesIterator($filtered);
foreach ($items as $item) {
    echo $item->asXML(), "\n";
}
这将输出搜索到的节点(示例):
<ITEM NAME="Sample">
   ..some other node here
</ITEM>
<ITEM NAME="SamPlE lorem">
   ..some other node here
</ITEM>
<ITEM NAME="Sam Ple lorem ipsum">
   ..some other node here
</ITEM>
<ITEM NAME="sample">
   ..some other node here
</ITEM>
<ITEM NAME="SAMPLE">
   ..some other node here
</ITEM>
以及基于字符串值过滤数组的分离解决方案:
/**
 * Class LaxStringFilterIterator
 *
 * Search for needle in case-insensitive manner on a subject
 * with spaces removed.
 */
class LaxStringFilterIterator extends FilterIterator
{
    private $quoted;
    /**
     * @param Traversable|Array|Object $it
     * @param string $needle
     */
    public function __construct($it, $needle) {
        parent::__construct($it instanceof Traversable ? new IteratorIterator($it) : new ArrayIterator($it));
        $this->quoted = preg_quote($needle);
    }
    public function accept() {
        $pattern = sprintf('/%s/i', $this->quoted);
        $subject = preg_replace('/\s+/', '', trim(parent::current()));
        return preg_match($pattern, $subject);
    }
}
和父节点装饰器:
/**
 * Class SimpleXMLParentNodesIterator
 *
 * Return parent nodes instead of current SimpleXMLElement Nodes,
 * for example the element of an attribute.
 */
class SimpleXMLParentNodesIterator extends IteratorIterator
{
    public function current() {
        $current = parent::current();
        list($parent) = $current[0]->xpath('..');
        return $parent;
    }
}