Можно ли сделать этот метод preg_replace_callback в xPath или XQuery? - PullRequest
0 голосов
/ 02 ноября 2010

Сценарий ниже принимает блок $ myContent и выполняет функцию doReplace () для значения $ myKeyword. У меня проблема в том, что он не знает, находится ли текст замены внутри тега или нет.

Мне нужно изменить функцию doReplace (), чтобы она не касалась текста внутри или в качестве атрибутов именованных тегов (h1, h2, h3, i, u, b, strong, em, img).

Я думаю, что было бы лучше преобразовать это в метод xPath и искать предложения о том, как это можно сделать с помощью xPath. Итак, вопрос: «Как бы вы преобразовали это в xPath»?

Примечание. Переменная 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("/\b($mykeyword)\b/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];
    }
}

1 Ответ

1 голос
/ 02 ноября 2010

Вы не можете в 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.

...