PHP提取带标签的TMX内容遇阻,求解决方案
基于浏览器的TMX编辑器标签提取异常问题解决
问题背景
我正在开发一款基于浏览器的TMX(翻译记忆库)编辑器,当源或目标文本段包含<bpt>/<ept>这类标签时,内容提取脚本出现异常。
包含标签的源/目标字符串示例:
<tuv xml:lang="BG"> <seg><bpt x="1" i="1" type="italic"/>Формантът -лар/-лар- (от тюрк. -lar) е слабо представен в българската словообразувателна система.<ept i="1"/></seg> </tuv> <tuv xml:lang="EN-GB"> <seg><bpt x="1" i="1" type="italic"/>The -lar/-lar- formant (from the Turkic -lar) is sparsely represented in the Bulgarian word-building system.<ept i="1"/></seg> </tuv>
如果源/目标段无标签,提取逻辑很简单:
$sourceText = $TU['tuv'][0]['seg']; $targetText = $TU['tuv'][1]['seg'];
但当<seg>内包含标签时,seg会被解析为数组,无法直接提取文本+标签的完整内容,最终需要保留文本与标签的结构,方便用户编辑文本、移动或删除标签。
测试代码
我的测试代码如下:
$uploadedFile = "user_files/sample_tmx.tmx"; $xmlStr = file_get_contents($uploadedFile); $xmlObj = simplexml_load_string($xmlStr); $arrXml = $util->objectsIntoArray($xmlObj); $TUs = $arrXml['body']['tu']; $pattern = '~<.*?>~'; foreach($TUs as $TU) { if(is_array($TU['tuv'][0]['seg'])) { var_dump($TU['tuv'][0]['seg']); $pattern = '~<.*?>~'; $uncleanSource = $TU['tuv'][0]['seg']; $uncleanTarget = $TU['tuv'][1]['seg']; foreach($uncleanSource as $unclean) { //var_dump($unclean); } //$sourceText = preg_replace($pattern, "<TAG>", $uncleanSource); //$targetText = preg_replace($pattern, "<TAG>", $uncleanTarget); } else { $sourceText = $TU['tuv'][0]['seg']; $targetText = $TU['tuv'][1]['seg']; } echo "<p>".$sourceText." = ".$targetText."</p>"; }
示例TMX文件
测试用的sample_tmx.tmx内容:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE tmx SYSTEM "tmx14.dtd" > <tmx version="1.4"> <header creationtool="TDC Analysis Package" creationtoolversion="org.gs4tr.tm3.tmx.Version" segtype="sentence" o-tmf="unknown" adminlang="EN-US" srclang="BG" datatype="unknown" creationdate="20221006T184234Z" > </header> <body> <tu creationdate="20201101T133734Z" creationid="Cheeseus" changedate="20201103T151745Z" changeid="Cheeseus" usagecount="0"> <prop type="nextMd5Checksum">e82d0ed6d711aa59310d1e8f4478537e</prop> <prop type="previousMd5Checksum">39b279e324e9f6cd27351287502eefcb</prop> <tuv xml:lang="BG"> <seg><bpt x="1" i="1" type="italic"/>Формантът -лар/-лар- (от тюрк. -lar) е слабо представен в българската словообразувателна система.<ept i="1"/></seg> </tuv> <tuv xml:lang="EN-GB"> <seg><bpt x="1" i="1" type="italic"/>The -lar/-lar- formant (from the Turkic -lar) is sparsely represented in the Bulgarian word-building system.<ept i="1"/></seg> </tuv> </tu> <tu creationdate="20080812T111221Z" creationid="Cheeseus" changedate="20190825T065920Z" changeid="Cheeseus" usagecount="0"> <tuv xml:lang="BG"> <seg>ПАРТНЬОРИ</seg> </tuv> <tuv xml:lang="EN-GB"> <seg>PARTNERS</seg> </tuv> </tu> </body> </tmx>
解决方案
方法1:直接获取<seg>的原始XML内容
SimpleXMLElement自带asXML()方法,可以直接获取节点的完整XML内容,无需转数组处理:
$uploadedFile = "user_files/sample_tmx.tmx"; $xmlStr = file_get_contents($uploadedFile); $xmlObj = simplexml_load_string($xmlStr); // 遍历所有tu节点 foreach($xmlObj->body->tu as $tu) { // 获取源语言和目标语言的seg节点 $sourceSeg = $tu->tuv[0]->seg; $targetSeg = $tu->tuv[1]->seg; // 获取seg的完整XML内容,包含标签和文本 $sourceText = $sourceSeg->asXML(); $targetText = $targetSeg->asXML(); // 可选:去掉外层的<seg>标签,只保留内部内容 $sourceText = preg_replace('/^<seg>|<\/seg>$/', '', $sourceText); $targetText = preg_replace('/^<seg>|<\/seg>$/', '', $targetText); echo "<p>".$sourceText." = ".$targetText."</p>"; }
这种方法能直接保留所有标签和文本的原始结构,避免转数组带来的结构丢失问题,更适合后续编辑操作。
方法2:处理转数组后的seg内容
如果必须使用objectsIntoArray转成数组处理,可以遍历seg的子元素,拼接标签和文本:
function parseSegArray($segArray) { $result = ''; foreach($segArray as $key => $value) { if(is_array($value)) { // 构建标签字符串,比如<bpt x="1" i="1" type="italic"/> $tag = "<{$key}"; foreach($value['@attributes'] as $attrKey => $attrVal) { $tag .= " {$attrKey}=\"{$attrVal}\""; } $tag .= "/>"; $result .= $tag; } else { // 普通文本直接拼接 $result .= $value; } } return $result; } // 在循环中调用 if(is_array($TU['tuv'][0]['seg'])) { $sourceText = parseSegArray($TU['tuv'][0]['seg']); $targetText = parseSegArray($TU['tuv'][1]['seg']); } else { $sourceText = $TU['tuv'][0]['seg']; $targetText = $TU['tuv'][1]['seg']; }
这个函数会遍历seg数组的每个元素,将数组类型的标签转为XML字符串,文本直接拼接,最终得到完整的带标签内容。
总结
推荐使用第一种方法,直接利用SimpleXML的asXML()获取完整内容,代码更简洁,也能避免转数组带来的结构丢失问题,更适合后续的编辑操作。
内容的提问来源于stack exchange,提问作者cheeseus
相关产品推荐
相关产品推荐

