可以在XPath或XQuery中使用这个preg_place_allback方法吗?
下面的脚本接受$myContent块并对$myKeyword值执行doReplace()函数。我的问题是,它不知道替换文本是否已经在标记中。
我需要修改doReplace()函数,以便它不会触及命名标记(h1、h2、h3、i、u、b、strong、em、img)内或作为其属性的任何文本。
我认为最好将其转换为XPath方法,并寻求有关如何使用XPath完成此操作的建议。所以问题是:"您将如何将其转换为XPath"?
注意:Replace函数中的count变量在那里,因为我只替换关键字的前三次出现。第一次显示为粗体,下次显示为斜体,第三次显示时,显示下划线。$myKeyword = "test keyword";
$myContent = "My content contains the "test keyword".
Don't do the replace if the test keyword is inside:
h1, h2, h3, i, u, b, strong, em, tags.
<h1>This test keyword would not be replaced</h1>";
$myContent = preg_replace_callback("/($mykeyword)/i","doReplace", $myContent);
function doReplace($matches)
{
static $count = 0;
switch($count++) {
case 0: return ' <b>'.trim($matches[1]).'</b>';
case 1: return ' <em>'.trim($matches[1]).'</em>';
case 2: return ' <u>'.trim($matches[1]).'</u>';
default: return $matches[1];
}
}
解决方案
您不能在XPath 1.0或2.0中使用,因为您需要递归来表示该算法。当然,您可以使用扩展函数。
此XQuery:
declare variable $match as xs:string external;
declare variable $replace as xs:string external;
declare variable $preserve as xs:string external;
declare variable $vPreserve := tokenize($preserve,',');
declare function local:copy-replace($element as element()) {
element {node-name($element)}
{$element/@*,
for $child in $element/node()
return if ($child instance of element())
then local:copy-replace($child)
else if ($child instance of text() and
not(name($element)=$vPreserve))
then replace($child,$match,$replace)
else $child
}
};
local:copy-replace(/*)
使用此输入:
<html>
<h1>This test keyword would not be replaced</h1>
<p>This test keyword should be replaced</p>
</html>
输出:
<html>
<h1>This test keyword would not be replaced</h1>
<p>This replaced should be replaced</p>
</html>
也是此样式表:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"/>
<xsl:param name="pMatch" select="'test keyword'"/>
<xsl:param name="pReplace" select="'replaced'"/>
<xsl:param name="pPreserve" select="'h1,h2,h3,i,u,b,strong,em'"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()">
<xsl:choose>
<xsl:when test="contains(concat(',',$pPreserve,','),
concat(',',name(..),','))">
<xsl:value-of select="."/>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="replace"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="replace">
<xsl:param name="pString" select="."/>
<xsl:choose>
<xsl:when test="contains($pString,$pMatch)">
<xsl:value-of
select="concat(substring-before($pString,
$pMatch),
$pReplace)"/>
<xsl:call-template name="replace">
<xsl:with-param name="pString"
select="substring-after($pString,
$pMatch)"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$pString"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
编辑:更好的XQuery。
相关文章