Mar*_*tin 7 html php string dom annotate
我正在尝试在字符串中的单词之间添加HTML标签(通过html标签即HTML注释包装单词)。HTML标记应写入的位置由偏移量数组界定,例如:
//array(Start offset, End offset) in characters
//Note that annotation starts in the Start offset number and ends before the End offset number
$annotationCharactersPositions= array(
0=>array(0,3),
1=>array(2,6),
2=>array(8,10)
);
Run Code Online (Sandbox Code Playgroud)
因此,要使用以下HTML标记($ tag)注释以下HTML文本($ source)。包裹由$ annotationPositions数组定界的字符(不考虑源的HTML标记)。
$source="<div>This is</div> only a test for stackoverflow";
$tag="<span class='annotation n-$cont'>";
Run Code Online (Sandbox Code Playgroud)
结果应为以下内容(https://jsfiddle.net/cotg2pn1/):
charPos =--------------------------------- 01---------------------------- 2-------------------------------------------3------------------------------------------45-------67-----------------------------89-------10,11,12,13......
$output = "<div><span class='annotation n-1'>Th<span class='annotation n-2'>i</span></span><span class='annotation n-2'>s</span><span class='annotation n-2'> i</span>s</div> <span class='annotation n-3'>on</span>ly a test for stackoverflow"
Run Code Online (Sandbox Code Playgroud)
我如何编程下一个功能:
$cont=0;
$myAnnotationClass="placesOfTheWorld";
for ($annotationCharactersPositions as $position) {
$tag="<span class='annotation $myAnnotationClass'>";
$source=addHTMLtoString($source,$tag,$position);
$cont++;
}
Run Code Online (Sandbox Code Playgroud)
考虑到在计数$ annotationCharactersPositions数组中描述的字符时,必须不考虑输入字符串的HTML标记,并且必须考虑到 $ source文本中每次插入注释(即$ tag)的情况。以下注释的封装/注释。
整个过程的想法是,给定输入文本(可能包含或不包含HTML标签),将对一组字符进行注释(属于一个或多个单词),以便结果将具有选定的字符(通过数组)定义了每个注释的起始和结束位置),该标记由HTML标记包裹,该标记可以随可变数量的html属性(名称,类,id,data- *)而变化(a,span,mark)。此外,结果必须是格式正确的有效HTML文档,这样,如果在多个注释之间有任何注释,则html应该相应地写入输出中。
您知道执行此操作的任何库或解决方案吗?也许PHP DOMDocument功能有用吗?但是如何将偏移量应用于php DomDocument函数?任何想法或帮助都受到好评。
注1:输入的文本是UTF-8原始文本,其中嵌入了任何类型的HTML实体(0-n)。
注2:输入标签可以是具有可变数量的属性(0-n)的任何HTML标签。
注3:初始位置必须是包容性的,而最终位置必须是排斥性的。即1º注释开始于第二个字符(包括2个字符“ i”)之前,结束于第6个字符(不包括6个字符“ s”)之前
将HTML加载到DOM文档中之后,您可以.//text()在可迭代列表中获取带有Xpath表达式()的元素节点的任何文本节点后代。这使您可以跟踪当前文本节点之前的字符。在文本节点上,检查是否必须将文本内容(或其一部分)包装到注释标记中。如果是这样,将其分离并创建一个最多包含3个节点的片段。(前文字,注释,后文字)。用片段替换文本节点。
function annotate(
\DOMElement $container, int $start, int $end, string $name
) {
$document = $container->ownerDocument;
$xpath = new DOMXpath($document);
$currentOffset = 0;
// fetch and iterate all text node descendants
$textNodes = $xpath->evaluate('.//text()', $container);
foreach ($textNodes as $textNode) {
$text = $textNode->textContent;
$nodeLength = grapheme_strlen($text);
$nextOffset = $currentOffset + $nodeLength;
if ($currentOffset > $end) {
// after annotation: break
break;
}
if ($start >= $nextOffset) {
// before annotation: continue
$currentOffset = $nextOffset;
continue;
}
// make string offsets relative to node start
$relativeStart = $start - $currentOffset;
$relativeLength = $end - $start;
if ($relativeStart < 0) {
$relativeLength -= $relativeStart;
$relativeStart = 0;
}
$relativeEnd = $relativeStart + $relativeLength;
// create a fragment for the annotation nodes
$fragment = $document->createDocumentFragment();
if ($relativeStart > 0) {
// append string before annotation as text node
$fragment->appendChild(
$document->createTextNode(grapheme_substr($text, 0, $relativeStart))
);
}
// create annotation node, configure and append
$span = $document->createElement('span');
$span->setAttribute('class', 'annotation '.$name);
$span->textContent = grapheme_substr($text, $relativeStart, $relativeLength);
$fragment->appendChild($span);
if ($relativeEnd < $nodeLength) {
// append string after annotation as text node
$fragment->appendChild(
$document->createTextNode(grapheme_substr($text, $relativeEnd))
);
}
// replace current text node with new fragment
$textNode->parentNode->replaceChild($fragment, $textNode);
$currentOffset = $nextOffset;
}
}
$html = <<<'HTML'
<div><div>This is</div> only a test for stackoverflow</div>
HTML;
$annotations = [
0 => [0, 3],
1 => [2, 6],
2 => [8, 10]
];
$document = new DOMDocument();
$document->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
foreach ($annotations as $index => $offsets) {
annotate($document->documentElement, $offsets[0], $offsets[1], 'n-'.$index);
}
echo $document->saveHTML();
Run Code Online (Sandbox Code Playgroud)
输出:
<div><div><span class="annotation n-0">Th<span class="annotation n-1">i</span></span><span class="annotation n-1">s is</span></div> <span class="annotation n-2">on</span>ly a test for stackoverflow</div>
Run Code Online (Sandbox Code Playgroud)