为了账号安全,请及时绑定邮箱和手机立即绑定

用 xml 元素环绕文本位

用 xml 元素环绕文本位

PHP
白猪掌柜的 2021-11-26 15:46:00
我正在寻找一种基于正则表达式用 XML 节点动态包围文本部分的方法。考虑下面的例子<speak>The test number is 123456789, and some further block of text.</speak>现在假设我有一个针对数字的正则表达式,可以有选择地用一个新标签将其包围,这样它就会变成:<speak>The test number is <say-as interpret-as="characters">123456789</say-as>, and some further block of text.</speak>我想过使用 DomDocument 来创建标签,但不确定替换部分。有什么建议吗?
查看完整描述

3 回答

?
12345678_0001

TA贡献1802条经验 获得超5个赞

这可以使用xsl:analyze-stringXSLT 2.0 中的指令方便地处理。例如,您可以定义规则:


<xsl:template match="speak">

  <xsl:analyze-string select="." regex="\d+">

    <xsl:matching-substring>

      <say-as interpret-as="characters">

        <xsl:value-of select="."/>

      </say-as>

    </xsl:matching-substring>

  </xsl:analyze-string>

</xsl:template>


查看完整回答
反对 回复 2021-11-26
?
杨__羊羊

TA贡献1943条经验 获得超7个赞

DOM 是正确的方法。它允许您查找和遍历文本节点。对这些节点的内容使用 RegEx 并将新节点构建为片段。


function wrapMatches(\DOMNode $node, string $pattern, string $tagName, $tagAttributes = []) {

    $document = $node instanceof DOMDocument ? $node : $node->ownerDocument;

    $xpath = new DOMXpath($document);

    // iterate all descendant text nodes

    foreach ($xpath->evaluate('.//text()', $node) as $textNode) {

        $content = $textNode->textContent;

        $found = preg_match_all($pattern, $content, $matches, PREG_OFFSET_CAPTURE);

        $offset = 0;

        if ($found) {

            // fragments allow to treat multiple nodes as one

            $fragment = $document->createDocumentFragment();

            foreach ($matches[0] as $match) {

                list($matchContent, $matchStart) = $match;

                // add text from last match to current

                $fragment->appendChild(

                  $document->createTextNode(substr($content, $offset, $matchStart - $offset))

                );

                // add wrapper element, ...

                $wrapper = $fragment->appendChild($document->createElement($tagName));

                // ... set its attributes ...

                foreach ($tagAttributes as $attributeName => $attributeValue) {

                    $wrapper->setAttribute($attributeName, $attributeValue);

                }

                // ... and add the text content

                $wrapper->textContent = $matchContent;

                $offset = $matchStart + strlen($matchContent);

            }

            // add text after last match

            $fragment->appendChild($document->createTextNode(substr($content, $offset)));

            // replace the text node with the new fragment

            $textNode->parentNode->replaceChild($fragment, $textNode);

        }

    }

}



$xml = <<<'XML'

<speak>The test number is 123456789, and some further block of text.</speak>

XML;


$document = new DOMDocument();

$document->loadXML($xml);


wrapMatches($document, '(\d+)u', 'say-as', ['interpret-as' => 'characters']);


echo $document->saveXML();


查看完整回答
反对 回复 2021-11-26
?
慕尼黑的夜晚无繁华

TA贡献1864条经验 获得超6个赞

你可以使用preg_replace这样的东西:


$str = '<speak>The test number is 123456789, and some further block of text.</speak>';

echo preg_replace('/(\d+)/','<say-as interpret-as="characters">$1</say-as>',$str);

输出将是:


<speak>The test number is <say-as interpret-as="characters">123456789</say-as>, and some further block of text.</speak>



查看完整回答
反对 回复 2021-11-26
  • 3 回答
  • 0 关注
  • 175 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信