在下面的函数中,当 $keyword 中的字符串包含双引号时,它会创建一个 “Warning: DOMXPath::evaluate(): Invalid expression”:
$keyword = 'This is "causing" an error';
$xPath->evaluate('boolean(//img[contains(@alt, "'.$keyword.'")])');
我应该做什么来准备
$keyword
来评估 xpath 表达式?
完整功能代码:
$keyword = trim(strtolower(rseo_getKeyword($post)));
function sx_function($heading, $post){
$content = $post->post_content;
if($content=="" || !class_exists('DOMDocument')) return false;
$keyword = trim(strtolower(rseo_getKeyword($post)));
@$dom = new DOMDocument;
@$dom->loadHTML(strtolower($post->post_content));
$xPath = new DOMXPath(@$dom);
switch ($heading)
{
case "img-alt": return $xPath->evaluate('boolean(//img[contains(@alt, "'.$keyword.'")])');
default: return $xPath->evaluate('boolean(/html/body//'.$heading.'[contains(.,"'.$keyword.'")])');
}
}
PHP 有 Xpath 1.0,如果您有一个带有双引号和单引号的字符串,解决方法是使用 Xpath
concat()
函数。辅助函数可以决定何时使用什么。示例/用法:
xpath_string('I lowe "double" quotes.');
// xpath: 'I lowe "double" quotes.'
xpath_string('It\'s my life.');
// xpath: "It's my life."
xpath_string('Say: "Hello\'sen".');
// xpath: concat('Say: "Hello', "'", "'sen".')
辅助功能:
/**
* xpath string handling xpath 1.0 "quoting"
*
* @param string $input
* @return string
*/
function xpath_string($input) {
if (false === strpos($input, "'")) {
return "'$input'";
}
if (false === strpos($input, '"')) {
return "\"$input\"";
}
return "concat('" . strtr($input, array("'" => '\', "\'", \'')) . "')";
}
要转义 XPath 2.0 字符串文字中的字符串分隔符,您需要将每个分隔符替换为两个,因此
"
需要替换为 ""
:
[74] StringLiteral ::= ('"' (EscapeQuot | [^"])* '"') | ("'" (EscapeApos | [^'])* "'") /* ws: explicit */ [75] EscapeQuot ::= '""' [76] EscapeApos ::= "''"
我不确定是否已经有一个函数可以做到这一点,但你可以使用这个函数:
function xpath_quote($str, $quotation='"') {
if ($quotation != '"' && $quotation != "'") return false;
return str_replace($quotation, $quotation.$quotation, $str);
}
用法:
'boolean(/html/body//'.$heading.'[contains(.,"'.xpath_quote($keyword).'")])'
即将推出的 PHP8.4.0 将具有 DOMXPath::quote() (我编写的 https://github.com/php/php-src/pull/13456 ),因此从 PHP8.4.0 开始:
case "img-alt": return $xPath->evaluate('boolean(//img[contains(@alt, '.$xPath->quote($keyword).')])');
default: return $xPath->evaluate('boolean(/html/body//'.$heading.'[contains(.,'.$xPath->quote($keyword).')])');
PHP8.4.0之前,可以使用
function UserlandDOMXPathQuote(string $string): string {
{
if (false === \strpos($string, '\'')) {
return '\'' . $string . '\'';
}
if (false === \strpos($string, '"')) {
return '"' . $string . '"';
}
// if the string contains both single and double quotes, construct an
// expression that concatenates all non-double-quote substrings with
// the quotes, e.g.:
// 'foo'"bar => concat("'foo'", '"bar")
$sb = [];
while ($string !== '') {
$bytesUntilSingleQuote = \strcspn($string, '\'');
$bytesUntilDoubleQuote = \strcspn($string, '"');
$quoteMethod = ($bytesUntilSingleQuote > $bytesUntilDoubleQuote) ? "'" : '"';
$bytesUntilQuote = \max($bytesUntilSingleQuote, $bytesUntilDoubleQuote);
$sb[] = $quoteMethod . \substr($string, 0, $bytesUntilQuote) . $quoteMethod;
$string = \substr($string, $bytesUntilQuote);
}
$sb = \implode(',', $sb);
return 'concat(' . $sb . ')';
}