如何使用xmlstarlet提取ApexClass类型的members值为逗号分隔列表
问题背景
现有如下结构的Salesforce元数据XML文件:
<?xml version="1.0" encoding="UTF-8"?> <Package xmlns="http://soap.sforce.com/2006/04/metadata"> <types> <members>B2B_ProductDetailDesktop</members> <name>ApexComponent</name> </types> <types> <members>Class1</members> <members>Class2</members> <name>ApexClass</name> </types> <version>54.0</version> </Package>
需求为仅提取<name>节点值为ApexClass的<types>节点下所有<members>的取值,输出为逗号分隔列表。以上述示例文件为例,期望输出为:
Class1,Class2
尝试使用如下xmlstarlet命令完成提取:
xmlstarlet sel -N d=http://soap.sforce.com/2006/04/metadata -t -m "//d:Package/d:types" -v "d:members" temp/package/package.xml
执行后仅输出B2B_ProductDetailDesktopClass1,不符合预期,需要确认该需求是否可实现,以及正确的命令写法。
问题原因
原命令无法得到正确结果,核心问题有两点:
- 匹配
d:types节点时未加筛选条件,会选中所有types节点(包括示例中name为ApexComponent的节点),把无关的members值也提取出来 - 未指定多值输出的分隔规则,xmlstarlet默认会将匹配到的节点值直接拼接,不会自动添加分隔符,部分版本下甚至不会输出同一父节点下的多个同级members值,导致结果粘连、缺失。
正确实现方案
该需求完全可以通过xmlstarlet实现,推荐使用XPath内置函数完成筛选和拼接,命令如下:
xmlstarlet sel -N d="http://soap.sforce.com/2006/04/metadata" \ -t -v "string-join(//d:types[d:name='ApexClass']/d:members, ',')" \ -n temp/package/package.xml
参数说明:
-N d="http://soap.sforce.com/2006/04/metadata":声明XML默认命名空间前缀,解决带默认命名空间的节点无法直接匹配的问题- XPath表达式
//d:types[d:name='ApexClass']/d:members:通过谓词[d:name='ApexClass']过滤出目标types节点,再选中该节点下所有members子节点,从根源上排除无关节点 string-join(节点集, ','):调用XPath 2.0内置的字符串拼接函数,直接把所有匹配到的members值用逗号连接成单个字符串输出,不需要额外处理分隔符-n:在输出结果末尾追加换行符,适配终端使用习惯
执行上述命令,针对示例XML会直接输出期望结果Class1,Class2。
如果使用的xmlstarlet版本较低不支持XPath 2.0的string-join函数,可以使用兼容旧版本的写法,最后通过sed去掉末尾多余的逗号:
xmlstarlet sel -N d="http://soap.sforce.com/2006/04/metadata" \ -t -m "//d:types[d:name='ApexClass']/d:members" -v "." -o "," \ temp/package/package.xml | sed 's/,$//'
内容的提问来源于stack exchange,提问作者Double Jo
相关产品推荐
相关产品推荐

