You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP实现XML转HTML并保留强调格式的技术问题

解决SimpleXML解析DocBook XML丢失强调内容并转为HTML的问题

问题分析

你当前的代码存在两个核心问题:

  1. 错误使用$xml_data['para']访问元素——这是XML属性的调用语法,而<para>是<article>的子元素,正确写法应为$xml_data->para。
  2. SimpleXML直接输出元素时仅提取纯文本节点,会忽略<emphasis>这类子元素,导致强调内容丢失,也无法完成DocBook标签到HTML标签的转换。

解决方案

推荐使用DOMDocument配合XPath处理,它能精准遍历混合内容(文本+子元素),完美完成标签转换:

$filedata = '<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE article>
<article
  xmlns="http://docbook.org/ns/docbook" version="5.0"
  xmlns:xlink="http://www.w3.org/1999/xlink" >
<para>
This is an <emphasis role="strong">test</emphasis> sentence.
</para>
</article>';

// 初始化DOM和XPath
$dom = new DOMDocument();
$dom->loadXML($filedata);
$xpath = new DOMXPath($dom);
// 注册DocBook命名空间(匹配XML中的xmlns属性)
$xpath->registerNamespace('db', 'http://docbook.org/ns/docbook');

// 定位所有para元素
$paraNodes = $xpath->query('//db:para');
foreach ($paraNodes as $paraNode) {
    $htmlOutput = '';
    // 遍历para下的所有子节点
    foreach ($paraNode->childNodes as $node) {
        if ($node instanceof DOMText) {
            // 处理文本节点,转义特殊字符避免XSS
            $htmlOutput .= htmlspecialchars(trim($node->nodeValue));
        } elseif ($node instanceof DOMElement && $node->tagName === 'emphasis') {
            // 根据role属性转换为对应HTML标签
            if ($node->getAttribute('role') === 'strong') {
                $htmlOutput .= '<b>' . $node->nodeValue . '</b>';
            } else {
                // 非strong的emphasis默认转为em标签,可按需调整
                $htmlOutput .= '<em>' . $node->nodeValue . '</em>';
            }
        }
    }
    echo trim($htmlOutput);
}

代码说明

  • 命名空间注册:DocBook XML带有xmlns属性,必须通过XPath注册才能正确定位元素。
  • 节点类型区分:分别处理文本节点和元素节点,文本节点做HTML转义,元素节点根据属性转换为对应HTML标签。
  • 混合内容处理:DOM可以完整保留文本与子元素的结构,不会丢失任何内容。

替代方案(SimpleXML)

如果坚持使用SimpleXML,需手动遍历子元素并拼接内容,但处理混合内容的直观性不如DOM:

$xml_data = simplexml_load_string($filedata);
$para = $xml_data->para;
$output = '';

// 处理para开头的文本
$output .= trim((string)$para);

// 遍历para下的子元素
foreach ($para->children() as $child) {
    if ($child->getName() === 'emphasis' && (string)$child['role'] === 'strong') {
        $output .= '<b>' . (string)$child . '</b>';
    }
    // 处理子元素后的文本
    $output .= $child->nextSibling;
}

echo trim($output);

内容的提问来源于stack exchange,提问作者Christophe Gratessolle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 22:15:38