news 2026/9/29 23:35:55

一段XML少了前后文字:HarmonyOS 7修复混合内容解析后,正文提取和快照测试一起改

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
一段XML少了前后文字:HarmonyOS 7修复混合内容解析后,正文提取和快照测试一起改

一段XML少了前后文字:HarmonyOS 7修复混合内容解析后,正文提取和快照测试一起改

阅读器导入一段带强调标记的说明,“请先”在标记前,“再继续”在标记后。旧版本导入结果只剩中间的强调词,界面看起来像内容缺了一半。升级后文字恢复了,原来的快照测试却开始失败,原因不是新的解析器把顺序弄乱,而是旧代码和测试一起接受了错误结果。

HarmonyOS 7修复了ConvertXML.fastConvertToJSObject解析混合内容时丢失同级文本节点的问题。本文把升级拆成两个不同任务:普通正文要按文档顺序保留文字;结构化记录不能继续假定_elements[0]一定是子元素。

官方Beta1变更页更新于2026年8月19日,9月28日再次核对。本文对文档给出的解析结果结构编写遍历代码并执行宿主断言,没有在本机运行HarmonyOS ConvertXML,也没有把Node.js测试说成API26编译或设备结果。

修复的不是整个XML标准,而是一个具体丢字问题

对于“文本、子元素、文本”混排的内容,变更前子元素旁边的文本可能丢失;变更后同级文本会保留。接口从API14提供,本次修复不是新增加一个转换器。官方汇总将此项列为全部生效,不能只靠降低targetSdkVersion回避测试。

可以在支持环境中用以下自写输入观察结果:

import { convertxml } from '@kit.ArkTS'; const converter = new convertxml.ConvertXML(); const xml = '<notice>请先<strong>保存</strong>再继续</notice>'; const result = converter.fastConvertToJSObject(xml); console.info(JSON.stringify(result));

这段输入没有文件访问或网络请求。输出应包含notice内部前、中、后三段文字对应的节点。若工程使用了ConvertOptions,应把选项与结果一起保存;本文后续适配针对官方变更示例中的非紧凑_elements结构,不声称适用于所有自定义转换选项。

案例一:提取可阅读正文,但不要破坏空白

常见错误是只遍历_type为element的节点,然后取它们的文本。修复后新出现的同级text节点仍然会被应用代码忽略。另一种错误是每个文本节点先trim,再拼接,结果英文词之间的空格消失。

下面把输出节点建模为最小结构。输入来自转换器输出适配,不是在手写XML解析器:

type XmlNode = { _type: string; _name?: string; _text?: string; _elements?: XmlNode[] }; function plainText(nodes: XmlNode[]): string { const pieces: string[] = []; for (const node of nodes) { if (node._type === 'text') pieces.push(node._text ?? ''); else if (node._type === 'element') pieces.push(plainText(node._elements ?? [])); } return pieces.join(''); } function assertEqual(actual: unknown, expected: unknown): void { if (JSON.stringify(actual) !== JSON.stringify(expected)) throw new Error('assertion failed'); } const mixed: XmlNode[] = [ { _type:'text', _text:'请先' }, { _type:'element', _name:'strong', _elements:[{ _type:'text', _text:'保存' }] }, { _type:'text', _text:'再继续' } ]; assertEqual(plainText(mixed), '请先保存再继续'); const english: XmlNode[] = [ { _type:'text', _text:'read ' }, { _type:'element', _name:'b', _elements:[{ _type:'text', _text:'this' }] }, { _type:'text', _text:' first' } ]; assertEqual(plainText(english), 'read this first');

这里不逐段trim,因为相邻标签之间的空格也可能有语义。如果产品只需要搜索索引,可以在最终文本上另做空白规范化,但应明确这是搜索层策略,不能回写替换原始正文。

本文两个案例只处理text与element,不处理CDATA、注释和处理指令。需要这些节点时,应按当前转换选项的实际输出另加适配和样本,不能把这个最小结构当成完整的XML数据模型。

递归遍历适合受控的小型说明文档。面对不可信、可能极深的结构,需要输入大小和深度约束,避免递归栈被耗尽。本文不会以“几行递归”声称解决了全部XML安全问题。

同一段内容,需要保留强调样式怎么办

纯文本不是富文本。提取成字符串后,strong这样的语义已经丢失。若阅读器需要保留样式,应在遍历时产生有序片段,而不是先拼接再根据关键词重新定位:

type Run = { text: string; strong: boolean }; function textRuns(nodes: XmlNode[], strong = false): Run[] { const result: Run[] = []; for (const node of nodes) { if (node._type === 'text') { result.push({ text:node._text ?? '', strong }); } else if (node._type === 'element') { result.push(...textRuns(node._elements ?? [], strong || node._name === 'strong')); } } return result; } assertEqual(textRuns(mixed), [ {text:'请先',strong:false}, {text:'保存',strong:true}, {text:'再继续',strong:false} ]);

片段结果可以再转换为ArkUI可渲染内容。这里仅支持strong演示语义,未知标签被作为容器继续遍历,没有执行标签携带的脚本或外部资源。链接、图片、列表等需要各自定义白名单和资源处理,不能直接把所有节点塞进HTML执行。

案例二:配置记录前多了空白,首元素不再是记录

另一个场景不是正文,而是应用导入的结构化条目。历史代码把root._elements[0]当成record,升级后首项可能变成前导文本节点。更隐蔽的是,某份文件没有空白所以正常,另一份经过格式化就失败。

正确的选择应按节点类型和名称,不靠数组位置:

function childElements(nodes: XmlNode[], name: string): XmlNode[] { return nodes.filter(node => node._type === 'element' && node._name === name); } const records: XmlNode[] = [ {_type:'text',_text:'\n '}, {_type:'element',_name:'record',_elements:[{_type:'text',_text:'甲'}]}, {_type:'text',_text:'\n '}, {_type:'element',_name:'record',_elements:[{_type:'text',_text:'乙'}]}, {_type:'text',_text:'\n'} ]; assertEqual(childElements(records,'record').map(x=>plainText(x._elements ?? [])), ['甲','乙']); assertEqual(childElements(records,'missing'), []); assertEqual(records[0]._type, 'text');

这不意味着可以全局删除所有text节点。配置读取器只是在当前位置寻找record;正文读取器仍需要保留文本。把两种目的封装成不同函数,比给一个通用函数加多个含糊开关更不容易误用。

快照测试失败,先判断差异属于哪一类

升级时不要直接把新JSON覆盖成“正确快照”。至少应做三件事:原始XML中确有这些文字;新节点顺序与原文顺序一致;业务最终输出保留了应有内容。满足这三项,才可以把丢失文字的旧快照视作需要修正的基线。

变化应如何处理
多出原文确实存在的同级text更新结构与正文断言,检查旧代码是否按下标取元素
只有空白节点变化明确正文与配置场景各自是否保留空白
丢失子元素内容或顺序颠倒不能直接接受,核对转换选项和适配层
业务输出相同但序列化不同分离结构快照与语义断言,避免只比较JSON字符串

我更倾向保留少量结构快照,加上明确的语义断言:混合段落的完整文本、强调范围、记录数量、记录顺序。只看结构会对实现细节过敏,只看拼接文本又可能漏掉样式丢失,两者需要互补。

把变化关在一个适配层里

迁移时可以按“ConvertXML原始结果 → 应用XmlNode结构 → 正文/记录读取器”组织。边界层校验字段类型和深度,业务层只处理已知结构。这样未来转换选项或输出形式再变化,影响范围不会扩散到每个页面。

不要把转换器的结果强行断言为完整业务对象后直接读字段。类型断言不执行运行时验证。本文为了说明节点顺序,测试输入是手写的有效结构;生产导入需要增加unknown输入校验,并将格式错误作为可恢复错误返回给界面。

升级验收顺序

先准备纯文本、纯子元素、混合内容三份最小XML,再加入空白、嵌套强调和空记录。用旧环境与API26环境分别保存原始转换输出,检查与官方说明是否一致;随后运行本文业务遍历断言,最后检查页面是否保留文字与样式。

本文宿主测试覆盖的是后半段“转换结果到业务输出”,不是前半段系统转换器实现。真实设备补测时,应把系统版本、SDK版本、ConvertOptions和输入样本一起记录,这比一句“升级后好了”更能帮助下一次排查。

这次修复带来的价值不是多了几个JSON节点,而是应用终于能拿到原文完整的表达。接下来要做的是删掉对旧缺陷的依赖,而不是再写一层过滤把新保留的文字丢掉。

参考资料

  • 官方ConvertXML混合内容解析修复说明
  • API26行为变更汇总
  • 升级适配指导
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/29 23:35:53

Day19 小程序应用解包反编译动态调试抓包静态分析源码架构

⚠️ 免责声明本文所涉及的技术、工具及方法仅供网络安全研究、授权测试及学习交流使用。严禁非法使用&#xff1a;未经目标系统所有者明确书面授权&#xff0c;任何利用本文所述技术对他人系统进行渗透、爆破、数据窃取或破坏的行为&#xff0c;均属违法行为。法律责任自担&am…

作者头像 李华
网站建设 2026/9/29 23:34:37

零信任架构实战:基于海宇学历核验版构建自动化大学生专属权益网关

破解电商学生专区痛点&#xff1a;从人工资质校验到数据直连 在针对高校群体的综合电商大促及专属数字产品订阅业务中&#xff0c;确保“大学生专享折扣”切实落到符合资格的用户手中&#xff0c;是平台精细化运营的核心前提。传统模式下&#xff0c;平台通常需要引导学生用户手…

作者头像 李华
网站建设 2026/9/29 23:33:44

影刀RPA实操指南:企业内部系统数据补录——老ERP没有接口怎么办

影刀RPA实操指南&#xff1a;企业内部系统数据补录——老ERP没有接口怎么办 公司那套用了八年的老ERP没有开放接口&#xff0c;财务和业务系统之间的数据要靠人工一条条敲进去&#xff0c;月底对账前几天全员变录入员。这篇讲怎么用影刀RPA做老系统数据补录&#xff1a;从Excel…

作者头像 李华
网站建设 2026/9/29 23:33:08

影刀RPA实操指南:变量命名与流程注释规范——三个月后还看得懂

影刀RPA实操指南&#xff1a;变量命名与流程注释规范——三个月后还看得懂 你有没有接过自己三个月前写的影刀RPA流程&#xff0c;盯着变量面板里x1、a2、临时3这些名字发呆&#xff0c;完全想不起哪个是店铺ID哪个是价格&#xff1f;我就干过这事——一个拼多多采集流程改需求…

作者头像 李华
网站建设 2026/9/29 23:32:32

工厂车间可视化电子看板:多屏同步与MES数据采集落地实践

1. 项目缘起与整体设计思路1.1 为什么要在工厂里搞可视化电子看板我在制造业信息化这行摸爬滚打十来年&#xff0c;进过汽车零部件厂、电子代工厂、精密五金厂&#xff0c;几乎每一家做到一定规模之后都会遇到同一个问题&#xff1a;车间里的数据是"死"的。生产进度靠…

作者头像 李华