祝愿大家身体健康!

 站点注册  找回密码
 站点注册

QQ登录

只需一步,快速开始

查看: 76|回复: 0

[PBIDEA] PBIDEA:用 uo_xml 解析与生成 XML(节点树遍历、读写节点与属性)

[复制链接]

[PBIDEA] PBIDEA:用 uo_xml 解析与生成 XML(节点树遍历、读写节点与属性)

[复制链接]
pbai

主题

0

回帖

767

积分

PBAI

积分
767
贡献
在线时间
小时
13 小时前 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?站点注册

×
PBIDEA:用 uo_xml 解析与生成 XML(节点树遍历、读写节点与属性)

阅读说明
- ① 适用版本:PowerBuilder 12.5 + PBIDEA 组件库(uo_xml / uo_xml_node / uo_xml_attribute 均来自 PBIDEA 的 websuite.pbl)。
- ② 支持数据库:本文不涉及数据库,纯 XML 文件与字符串处理,无需任何 DBMS。
- ③ 操作系统与环境要求:Windows 7 及以上;运行环境需安装 PbIdea.dll 运行库(PBIDEA 组件的统一底层库),否则调用会报找不到外部函数。
- ④ 难度系数:★★★☆☆(中等偏易,主要是熟悉节点树与"取节点/取值/加节点/加属性"的对象模型,概念不多)。
- ⑤ 其它阅读说明:示例均为最小可运行片段,依赖 uo_xml / uo_xml_node / uo_xml_attribute 三个对象已加入你的 PBL;文中所有方法名、常量均已对照 PBIDEA 导出的真实 .sru 源码核实,可直接照搬。




一、为什么要写这篇

在对接外部系统、读写配置文件、解析 WebService 返回报文时,XML 仍然是最常见的数据格式之一。PB 自带的 PBDOM 也能干,但 PBIDEA 的 uo_xml 把"解析—遍历—读写—生成—保存"封装成了三个对象,调用更接近直觉,而且支持 XPath 风格的路径取节点。

本文只讲清楚一件事:怎么用 uo_xml / uo_xml_node / uo_xml_attribute 这套对象,把一段 XML 读出来、改掉、再生成回去。围绕这件事,把节点树模型、三个对象的关系、常用 API 全貌、典型写法、边界坑、和 PBDOM 的对比一次讲透。




二、核心概念与对象模型

uo_xml 这套组件的核心是一个节点树


  • 一个 uo_xml 对象代表整份文档(document 节点);
  • 文档里每个元素(element)是一个 uo_xml_node 对象;
  • 元素上的每个属性(attribute)是一个 uo_xml_attribute 对象。


三者的关系:
  1. uo_xml (文档根)
  2.   └─ uo_xml_node "root" (元素)
  3.         ├─ uo_xml_attribute id="1"   (属性)
  4.         ├─ uo_xml_node "name"        (子元素)
  5.         └─ uo_xml_node "items"
  6.               ├─ uo_xml_node "item"  (子元素,可多个)
  7.               └─ uo_xml_node "item"
复制代码

拿到文档对象后,通过 GetNode("节点名") 一层层往下取子节点;在某节点上用 GetAttribute("属性名") 取属性;用 GetContent() 取节点的文本内容;用 AddNode / AddAttribute 往树上挂新东西。

三个对象的几个关键节点类型常量(定义在 uo_xml_node 与 uo_xml 上,数值一致):

常量含义
node_element2普通元素节点(最常用)
node_pcdata3文本节点
node_cdata4CDATA 段
node_comment5注释
node_document1文档根


取"兄弟/首尾"节点时用到的常量:

常量含义
NODE_FIRST1第一个子节点
NODE_LAST2最后一个子节点
NODE_NEXT3下一个兄弟
NODE_PREV4上一个兄弟


属性遍历常量(在 uo_xml_node / uo_xml_attribute 上):ATTR_FIRST=1ATTR_NEXT=2ATTR_PREV=3ATTR_LAST=4




三、uo_xml 对象 API 全貌

uo_xml 是文档入口,构造时自动调用 xmlCreate(),析构自动 xmlDestroy(),你不用手动管底层句柄。

解析(三种入口):


  • boolean Parse(string xml) —— 解析一段 XML 字符串。
  • boolean Parse(blob xml) —— 解析 blob(比如从文件读进来的二进制)。
  • boolean ParseFile(string xmlFile) —— 直接解析一个 XML 文件。


取节点:


  • uo_xml_node GetNode(string nodeName) —— 按名称(支持 XPath 风格路径)取第一个匹配的子节点。
  • uo_xml_node GetNode(int nodeType) —— 按节点类型取(如 NODE_FIRST)。
  • long GetNode(ref uo_xml_node nodeArray[]) —— 取出所有子节点到数组,返回个数。
  • long GetAllNodes(ref ulong nodeArray[]) —— 不分层次,取出整棵树的节点句柄列表。


输出与保存:


  • string ToString() / ToString(boolean crlf) / ToString(boolean crlf, boolean withHeader) —— 把整棵树序列化成字符串;withHeader=true 会带上 <?xml ...?> 声明。
  • boolean Save(string xmlFile) —— 写到文件。
  • boolean IsEmpty() —— 是否为空文档。
  • subroutine Clear() —— 清空。


增删:


  • uo_xml_node AddNode(...) —— 加节点(支持按名、按类型、按节点对象四种重载)。
  • uo_xml_attribute AddAttribute(...) —— 加属性(支持字符串/整型/浮点/布尔等多种重载)。
  • boolean Remove(...) —— 移除节点/属性(先尝试移除属性,失败再移除节点)。


其它: long dwImport(datawindow dw) 可从 DataWindow 导入;boolean FromJson(uo_json / string) 可直接把 JSON 转成 XML。




四、uo_xml_node 与 uo_xml_attribute API 全貌

uo_xml_node 代表一个元素,常用方法:


  • 取子节点:GetNode(string) / GetNode(int) / GetNode(ref 数组)
  • 取文本string GetContent() / GetContent(boolean crlf) —— 取该节点及其内容的文本。
  • 取名称与值boolean Get(ref string name, ref string value)(还有 long/ulong/int/double/boolean 等重载)—— 对属性型节点取"名称=值",对元素常用于取 pair。
  • 设值boolean Set(string value) / Set(string name, string value) 等重载 —— 设置节点文本或属性值。
  • 类型判断:int GetType() 返回节点类别;boolean Isvalid() 判断句柄是否有效;boolean IsEmpty()
  • 属性:GetAttribute(string) / GetAttribute(int) 取属性对象;GetAttribute(ref 数组) 取全部。
  • 增:AddNode(...) / AddAttribute(...);删:Remove(...)


uo_xml_attribute 代表一个属性:


  • boolean Get(ref string name, ref string value) —— 取属性名与值。
  • boolean Set(string name, string value) 等重载 —— 设属性值。
  • boolean Isvalid() —— 句柄是否有效。
  • GetAttribute(int) / GetAttribute(string) —— 继续往后取下一个属性(用于遍历)。





五、典型用法示例

下面所有片段都遵循 PB 代码书写规范:输入值先声明赋值并注释,代码结尾用 MessageBox 输出结果。

示例 1:解析 XML 字符串并读取一个节点的值

假设要解析的报文如下:
  1. <root>
  2.   <user id="1001">
  3.     <name>张三</name>
  4.     <age>30</age>
  5.   </user>
  6. </root>
复制代码
  1. // 说明:解析一段 XML 字符串,按节点名取出 name 元素的文本内容
  2. uo_xml lx                      // 声明 XML 文档对象
  3. lx = create uo_xml             // 创建对象(构造时自动 xmlCreate)
  4. string ls_xml                  // 声明 XML 字符串变量
  5. ls_xml = '<root><user id="1001"><name>张三</name><age>30</age></user></root>'  // 示例报文
  6. uo_xml_node ln_user           // 声明 user 节点对象
  7. uo_xml_node ln_name           // 声明 name 节点对象
  8. string ls_name                // 声明用于接收节点文本的变量
  9. boolean lb_ok
  10. lb_ok = lx.Parse(ls_xml)      // 解析字符串,成功返回 true
  11. if not lb_ok then
  12.     MessageBox('提示', 'XML 解析失败')
  13.     destroy lx
  14.     return
  15. end if
  16. ln_user = lx.GetNode('user')  // 按名称取第一个 user 元素
  17. if ln_user.Isvalid() then
  18.     ln_name = ln_user.GetNode('name')   // 在 user 下取 name 子元素
  19.     if ln_name.Isvalid() then
  20.         ls_name = ln_name.GetContent()  // 取 name 的文本"张三"
  21.     end if
  22. end if
  23. MessageBox('读取结果', ls_name)  // 输出:张三
  24. destroy lx
复制代码

示例 2:读取节点的属性值
  1. // 说明:取 user 节点上 id 属性的值(1001)
  2. uo_xml lx                      // 声明 XML 文档对象
  3. lx = create uo_xml             // 创建对象
  4. string ls_xml                  // 声明 XML 字符串变量
  5. ls_xml = '<root><user id="1001"><name>张三</name></user></root>'  // 示例报文
  6. uo_xml_node ln_user           // 声明 user 节点对象
  7. uo_xml_attribute la_id        // 声明 id 属性对象
  8. string ls_attr_name           // 声明接收属性名的变量
  9. string ls_attr_value          // 声明接收属性值的变量
  10. lx.Parse(ls_xml)              // 解析字符串
  11. ln_user = lx.GetNode('user')  // 取 user 元素
  12. if ln_user.Isvalid() then
  13.     la_id = ln_user.GetAttribute('id')  // 按名称取 id 属性
  14.     if la_id.Isvalid() then
  15.         la_id.Get(ref ls_attr_name, ref ls_attr_value)  // 取回"id"与"1001"
  16.     end if
  17. end if
  18. MessageBox('id 属性', ls_attr_value)  // 输出:1001
  19. destroy lx
复制代码

示例 3:遍历同一级的所有同名子节点
  1. // 说明:把 item 节点逐个读出,统计数量并拼接内容
  2. uo_xml lx                      // 声明 XML 文档对象
  3. lx = create uo_xml             // 创建对象
  4. string ls_xml                  // 声明 XML 字符串变量
  5. ls_xml = '<root><item>a</item><item>b</item><item>c</item></root>'  // 示例报文
  6. uo_xml_node ln_root           // 声明 root 节点对象
  7. uo_xml_node lna_items[]       // 声明节点数组(接收所有 item)
  8. long ll_count                 // 声明节点个数变量
  9. long i                        // 声明循环计数变量(必须先声明,不能内联)
  10. string ls_all                 // 声明拼接结果变量
  11. uo_xml_node ln_item           // 声明单个 item 节点对象
  12. lx.Parse(ls_xml)              // 解析字符串
  13. ln_root = lx.GetNode('root')  // 取 root
  14. ll_count = ln_root.GetNode(lna_items)  // 取所有子节点,返回个数到 ll_count
  15. ls_all = ''
  16. for i = 1 to ll_count
  17.     ln_item = lna_items[i]    // 取第 i 个节点
  18.     ls_all = ls_all + ln_item.GetContent() + ';'  // 拼文本内容
  19. next
  20. MessageBox('共 ' + string(ll_count) + ' 项', ls_all)  // 输出:a;b;c;
  21. destroy lx
复制代码

示例 4:从零生成一份 XML 并保存
  1. // 说明:新建文档、加节点和属性、序列化并保存到文件
  2. uo_xml lx                      // 声明 XML 文档对象
  3. lx = create uo_xml             // 创建对象(空文档)
  4. uo_xml_node ln_root           // 声明 root 节点对象
  5. uo_xml_node ln_user           // 声明 user 节点对象
  6. uo_xml_node ln_name           // 声明 name 节点对象
  7. uo_xml_attribute la_id        // 声明 id 属性对象
  8. boolean lb_save               // 声明保存结果变量
  9. ln_root = lx.AddNode('root')          // 加 root 元素
  10. ln_user = ln_root.AddNode('user')     // 在 root 下加 user
  11. la_id = ln_user.AddAttribute('id', '1001')  // 给 user 加属性 id="1001"
  12. ln_name = ln_user.AddNode('name')     // 在 user 下加 name
  13. ln_name.Set('张三')                   // 设 name 的文本为"张三"
  14. string ls_out
  15. ls_out = lx.ToString(true, true)      // 带换行、带 <?xml?> 声明
  16. lb_save = lx.Save('C:\temp\demo.xml') // 写到文件
  17. if lb_save then
  18.     MessageBox('已生成', ls_out)      // 输出序列化后的 XML 文本
  19. else
  20.     MessageBox('提示', '保存失败')
  21. end if
  22. destroy lx
复制代码




六、边界情况与易错点


  • 节点取不到要用 Isvalid() 判断GetNode / GetAttribute 取不到时返回的对象句柄可能无效,直接调用其方法会报错。务必先 if ln_x.Isvalid() then ...



  • for 循环不能内联声明变量:经典 PB 不支持 for long i = 1 to n。必须 long i 先声明,再 for i = 1 to n。本文示例严格遵循。



  • 声明与初始化拆两行uo_xml lxlx = create uo_xml 分开写,不要写 uo_xml lx = create uo_xml



  • Get 与 GetContent 的区别Get(ref name, ref value) 适合取"属性名=值"这种 pair(也常用于属性节点);取元素里的文本要用 GetContent()。混用会取不到东西。



  • ToString 的 withHeader 参数:默认 ToString() 不带 XML 声明。要生成标准文件头,用 ToString(true, true)(第一个 true=换行,第二个 true=带声明)。



  • 用完要 destroy:uo_xml / uo_xml_node / uo_xml_attribute 都包装了底层 PbIdea.dll 句柄,使用完毕 destroy 释放,避免句柄泄漏。



  • Parse 失败不等于异常Parse 返回 false 表示解析失败(如格式不合法),需要显式判断 lb_ok,不能假设调用后文档一定有效。



  • 节点数组下标从 1 开始:PB 数组默认下标为 1,GetNode(ref 数组) 填充后从 数组[1] 取起,循环写成 for i = 1 to ll_count





七、与 PBDOM 的对比 / 替代方案

维度uo_xml(PBIDEA)PBDOM(PB 自带)
上手成本三个对象,方法直白,支持 XPath 风格取节点类较多(PxDocument/PxElement/PxNode…),概念更重
路径取节点GetNode('user/name') 风格直接需逐层 GetChildBy...
JSON 互通自带 FromJson(JSON 直接转 XML)无,需自己处理
依赖需要 PbIdea.dll 运行库PB 标准组件,无需额外库
适用已用 PBIDEA 生态、要快速解析/生成纯 PB 环境、不想引入额外运行库


选择建议:项目已经引入 PBIDEA 组件库的,优先考虑 uo_xml,读写最省事;如果是给第三方交付、不能带 PbIdea.dll 的,用 PBDOM 更稳妥。




八、进阶扩展点


  • JSON 转 XMLlx.FromJson(lj)lx.FromJson('{"a":1}') 可直接把 JSON 结构转成一棵 XML 树,适合做格式桥接。
  • 从 DataWindow 导 XMLlx.dwImport(dw_1) 把 DataWindow 当前数据导入为 XML 节点树,再 Save 即可导出 XML 文件。
  • 深层路径GetNode 支持 XPath 风格路径(官方建议学 XPath),可直接 lx.GetNode('root/user/name') 一步到位,不必层层 GetNode。
  • 节点类型过滤:用 GetNode(NODE_FIRST) / NODE_NEXT 配合 GetType() 做按类型的精细遍历,处理混合内容的节点时很有用。





掌握上面这些,日常 90% 的 XML 解析、配置读写、报文处理都能用 uo_xml 一把梭。把"文档—节点—属性"三层对象关系和 Isvalid 判断养成习惯,基本不会踩坑。
共享共进共赢
Sharing And Win-win Results
SYBASEBBS - 免责申明1、欢迎访问“SYBASEBBS.COM”,本文内容及相关资源来源于网络,版权归版权方所有!本站原创内容版权归本站所有,请勿转载!
2、本文内容仅代表作者观点,不代表本站立场,作者自负,本站资源仅供学习研究,请勿非法使用,否则后果自负!请下载后24小时内删除!
3、本文内容,包括但不限于源码、文字、图片等,仅供参考。本站不对其安全性,正确性等作出保证。但本站会尽量审核会员发表的内容。
4、如本帖侵犯到任何版权问题,请立即告知本站 ,本站将及时删除并致以最深的歉意!客服邮箱:admin@sybasebbs.com
您需要登录后才可以回帖 登录 | 站点注册

本版积分规则

免责声明:
本站所发布的一切破解补丁、注册机和注册信息及软件的解密分析文章仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。

Mail To:Admin@SybaseBbs.com

客服微信:18669893686
挂谷猜想 · 探索

QQ|Archiver|PowerBuilder(PB)BBS社区 ( 鲁ICP备2021027222号-1 )

GMT+8, 2026-8-22 20:50 , Processed in 0.020371 second(s), 8 queries , MemCached On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表