简介:xmlstarlet是面向命令行环境的XML处理工具集,此压缩包为1.6.1版本的Windows 32位可执行程序,适合需要批量解析、校验、编辑XML的开发与运维人员。包内共15个文件,约1.48MB,除主程序xmlstarlet.exe外,还包含PDF、HTML格式的使用手册,以及txt说明、readme、ChangeLog、版权声明、News等文档,涵盖txt、pdf、html、ps、css等多种格式,方便查阅与打印。目前已有279人浏览学习。借助XPath支持,可完成节点查询、XSD及Relax NG校验、节点增删改、格式化输出以及向HTML、JSON等格式转换等常见需求,并可在批处理或脚本中组合使用,实现XML数据的自动化处理,减少手工编辑的重复劳动。附带的PDF/HTML手册和示例对快速上手与排查报错很有帮助,对经常处理XML数据或编写自动化脚本的读者来说,这是一款轻量但功能完整的实用工具。
1. 拿到 xmlstarlet-1.6.1-win32.zip 之前,先想清楚它能不能解决你的 XML 解析问题
说实话,我第一次在 Windows 机器上做 XML 解析时,第一反应是装 Python、装 lxml,直到有人甩给我一个 xmlstarlet 的压缩包。xmlstarlet 是纯粹的命令行 XML 工具集,1.6.1 是修过一批历史 bug 的版本,win32 后缀对应 32 位 Windows 环境,整个包解压后不到 1MB,不写注册表,不依赖重型运行时。你拿它查节点、改字段、转格式、验 schema,全都在一条命令里完成。它解决的是那种「就一段 XML,要取两个值,又嫌写脚本麻烦」的中间态问题。适合运维、测试、做数据交换的从业者,也适合在受限环境里只能靠命令行干活的人。
2. sel、ed、fo、val、tr:五个核心子命令的分工与选型理由
XMLStarlet 的设计思路和 Git 很像:一个可执行文件,内部按子命令拆功能。你不需要一次性学会全部,日常 80% 的操作落在 sel(查询)和 fo(格式化)上,剩下三个命令按场景补位。先把每个子命令的边界讲清楚,再给一个串联使用的例子,这样你在实际干活时才知道该用哪一个,而不是五个命令挨个试。
2.1 sel:XPath 查询是理解 XMLStarlet 的钥匙
sel 是 select 的缩写,负责「按 XPath 把节点取出来」。它也是第一个值得花时间研究的命令,因为它的参数写法比 grep 多一层模板概念,刚上手容易懵。
xmlstarlet sel -t -m "//book" -v "title" -o "|" -v "price" -n books.xml这里的 -t 表示进入模板模式,-m "//book" 是匹配所有 book 节点并对每个节点执行一次模板,-v "title" 取当前节点的 title 子节点文本,-o "|" 输出一个普通字符串做分隔,-n 输出换行。逻辑上就是「对每本书,打印标题、竖线、价格,然后换行」。
参数越简单越容易误用,关键点有三个:-t 必须出现在 -m 之前,-m 后面跟的是 XPath 而不是文件路径;-v 取的是文本值,想要属性要写 -v "@id" 这种带 @ 的 XPath;还有一个 -c 是复制整个节点(含子节点和属性),-x 是取 XPath 表达式的结果而不是模板输出。这三个取值参数分工不同,新手最容易把 -v 和 -c 混用,导致想取整个节点内容却只拿到一行文本。
sel 的另一个高频场景是统计,xmlstarlet sel -t -v "count(//item)" file.xml一行就能数出节点个数,比写 Python 快得多。配合 -m 和 -b 还能做简单的分组汇总,但遇到复杂聚合还是别硬撑,导出以后交给脚本处理更合适。
2.2 ed:不打开文件就改 XML,适合脚本化修改
ed 是 edit 的缩写,做的事情是在内存里对 XML 做增删改,然后把结果输出到标准输出。它有两个关键操作:-u 更新已有节点文本,-d 删除节点,-a 在锚点节点之后插入,-i 在锚点节点之前插入。
xmlstarlet ed -u "/config/timeout" -v "300" app.xml这条命令把 /config/timeout 节点的文本改成 300。两点必须注意:第一,ed 默认不会覆盖原文件,它把改完的 XML 打印出来,你要么用重定向 > 保存到新文件,要么用 -L 或 --inplace 直接写回原文件。第二,如果 XPath 匹配到多个节点,-u 会全部更新,想只改第一个要写成 /config/timeout[1]。
增删节点时,-a 和 -i 需要配合 -t 指定节点类型,例如xmlstarlet ed -a "/config" -t "elem" -n "debug" -v "false" app.xml表示在 config 末尾追加一个 debug 节点。这一串参数第一次看很绕,但多练两次就顺了。我一般会把 ed 和 sel 连起来用:先 sel 确认 XPath 能取到值,再 ed 去改,能避免「XPath 写错但命令还是成功执行」的静默问题。
2.3 fo:格式化与标准化,接手别人 XML 的第一件事
fo 是 format 的缩写,同时具备缩进重排和序列化输出两个能力。拿到一个被压缩成一行、或者缩进混乱的 XML,第一条命令永远是 fo。
xmlstarlet fo -t -n messy.xml > clean.xml-t 表示输出缩进,-n 表示输出换行,把「一行流」展开成可读的多行结构。还有一个重要参数 -R,全称 --recover,它让解析器进入容错模式,遇到非法字符或标签不闭合时尽量恢复而不是直接报错。这个参数在解析爬虫抓下来的半残 XML 时非常有用,但输出不保证语义正确,只能作为抢救手段,恢复正常后的 XML 还是要用 val 校验一遍。
fo 还有一个容易被忽略的用途:统一换行符和引号风格。它会把属性值的单引号统一成双引号,把换行符按当前平台处理。这样一来,两个来源不同的 XML 放到 diff 工具里对比时,不会被换行符差异刷屏,diff 结果干净很多。
2.4 tr 与 val:XSLT 转换和 schema 校验的兜底
tr 是 transform 的缩写,执行 XSLT 1.0 转换,把 XML 按样式表变成 HTML、文本或另一种结构的 XML。它适合「同一个数据源要输出多种视图」的场景,比如把配置文件转成文档。val 是 validate 的缩写,支持 DTD、XSD、Relax NG 三种校验方式。
xmlstarlet val -e -s schema.xsd app.xml-e 表示出错时打印详细错误信息,-s 指定 schema 文件。如果 app.xml 不符合 schema,命令会输出行号和元素路径。上线前用 val 跑一遍,比在业务代码里被解析器报错再回头查要省心得多。这两个命令的定位是「兜底」,日常改动 XML 之后顺手跑一次,能挡住大部分低级错误。
2.5 一次完整的改配置流程:sel 确认、ed 修改、fo 整理、val 收尾
把上面四个命令串成一个真实场景:某个服务的配置文件 config.xml 里,timeout 节点需要从 120 改成 300,而且文件本身是压缩成一行的那种。
xmlstarlet sel -t -v "/config/timeout" config.xml xmlstarlet ed -u "/config/timeout" -v "300" config.xml > config.new.xml xmlstarlet fo -t -n config.new.xml > config.pretty.xml xmlstarlet val -e -s config.xsd config.pretty.xml第一行确认当前值是 120,第二行把值改成 300 并输出到新文件,第三行把新文件格式化,第四行用 schema 校验。每一步都能看到中间结果,出错能定位到具体命令,不用把整个流程当成黑匣子。实际工作中,我会把第二行的结果先落到临时文件,检查无误后再替换原文件,等于给自己留了后悔药。
3. win32 版本在 Windows 上的安装、环境变量与编码实战
3.1 安装包解压、目录结构与 PATH 配置
xmlstarlet-1.6.1-win32.zip 解压后,目录里会有 xmlstarlet.exe 和若干运行时 DLL,没有安装程序,这一点和大多数 Windows 软件不一样。它的运行不依赖注册表,拷贝到任意目录都能跑。我习惯放在 C:\tools\xmlstarlet-1.6.1 下,然后把该目录加进系统 PATH,这样在任意路径下直接敲 xmlstarlet 都能识别,不用每次带全路径。
配置 PATH 分三步:Win+R 打开运行,输入 sysdm.cpl 回车,切到「高级」选项卡,点「环境变量」;在「系统变量」里找到 Path,编辑,新建一行,填入 C:\tools\xmlstarlet-1.6.1;重新打开一个 cmd 窗口,执行下面的命令验证。
xmlstarlet --version输出里会带 XMLStarlet 1.6.1 和编译平台信息。如果提示「不是内部或外部命令」,说明 PATH 没配好,或者当前 cmd 是配置之前打开的,重开窗口通常能解决。这里有个容易踩的细节:32 位程序在 64 位 Windows 上运行没有问题,但安装路径建议避开空格和中文,因为 cmd 解析带空格的路径容易翻车,写成 Program Files 目录时尤其明显。
3.2 编码是第一道坎:UTF-8 文件与 GBK 控制台的错位
Windows 中文版 cmd 默认代码页是 GBK(936),而绝大多数 XML 文件声明的是 UTF-8。XMLStarlet 按 XML 声明的编码读取文件,输出时却按控制台代码页写,于是你经常看到「中文变成问号」或者输出乱码。
解决有三个层次。第一层是改控制台代码页:
chcp 65001执行后当前窗口切到 UTF-8 代码页,再次运行 xmlstarlet 输出就正常了。但 chcp 只对当前窗口生效,关掉重开就失效。
提示:chcp 65001 只对当前窗口生效,别把它写进系统级的启动脚本里,否则某些老程序会跟着乱码。
第二层是不依赖控制台显示,直接把输出重定向到文件:
xmlstarlet sel -t -m "//book" -v "title" -n books.xml > titles.txt此时 XMLStarlet 的输出直接写进文件,不受控制台代码页影响。第三层是强制指定输入编码,如果 XML 文件没有声明 encoding,或者声明与真实编码不一致,XMLStarlet 可能按错误方式解析,这时用 --encoding 显式指定:
xmlstarlet fo --encoding "UTF-8" messy.xml > clean.xml--encoding 同时影响读取和输出。但如果文件本身是 GBK 编码且没有声明,显式指定 UTF-8 会报错或产生乱码。遇到这种文件,先用文本编辑器确认真实编码,再决定参数,不要猜。
3.3 实战:解析一份接口返回的 XML 响应
模拟一个真实场景:某服务返回的 resp.xml 里,需要提取所有 order 节点的 id 和 amount,并统计总金额。
xmlstarlet sel -t -m "//order" -v "concat(@id, ',', amount)" -n resp.xml xmlstarlet sel -t -v "sum(//order/amount)" resp.xml第一条命令输出每个订单的 id 和金额,逗号分隔;第二条直接用 XPath 的 sum 函数累加所有 amount 节点的文本值。这个场景里,-m 循环遍历每个 order,-v 内部可以用 XPath 函数 concat 做字符串拼接,比用多个 -o 更紧凑。注意 amount 节点必须包含可解析的数值文本,否则 sum 会静默返回 0,这一点要靠看输出结果来确认,命令本身不报错。
3.4 配合其他 Windows 命令做管道处理
XMLStarlet 和 findstr、more 等 Windows 原生命令配合也能干活,但有一个坑:管道传递时编码会经过 cmd 的代码页转换。
xmlstarlet sel -t -m "//error" -v "@code" -n resp.xml | findstr "500"如果 resp.xml 是 UTF-8 而 findstr 期望 GBK 环境,输出可能对不上。我的经验是:在 Windows cmd 里,能不过管道就不过,正确的做法是先把 xmlstarlet 的结果重定向到临时文件,再用 findstr 读文件。这比折腾管道编码省事得多,尤其是处理中文环境下的日志时。
4. 常见问题与避坑:error 1935、路径转义与乱码排查
这一节全是血泪经验,大部分问题集中在三件事:运行时组件缺失、Windows 路径转义、编码混乱。每条按「现象 → 原因 → 解决」的顺序写,你可以直接对照自己的报错信息定位。
4.1 安装或首次运行时遇到 error 1935
现象:在某些 Windows 机器上,首次运行 xmlstarlet.exe 或安装相关组件时弹出错误提示,提到 error 1935,伴随「安装程序集 microsoft.vc8o.atl, type=win32, version=8.0.5072...」这样的描述。
原因:1.6.1 是较早期版本,依赖 Visual C++ 2005(VC8)运行库,其中 ATL 程序集对应 C++ 的 Active Template Library 组件。这台机器恰好没有装相应的 VC8 运行库,或者系统里残留的版本损坏,导致 Windows Installer 无法完成程序集注册。能不能装上有时带点玄学,同一台机器换个用户身份可能结果不同。
解决:安装 VC++ 2005 SP1 可再发行组件(x86 版本),装完重开命令行再试。如果安装过程本身报 error 1935,用静默方式安装:
VC2005SP1_x86.exe /quiet /norestart静默安装完成后,重新打开 cmd 执行 xmlstarlet --version 验证。
注意:64 位 Windows 自带的 VC 运行库通常是 x64,解决不了 32 位程序的依赖。x86 版本必须单独装。
如果还是报同样的错,检查系统里是否残留旧版本运行库,卸载后重新装一遍。
4.2 Windows 路径里的反斜杠导致 XPath 取不到值
现象:运行xmlstarlet sel -t -v "/config/setting[1]/@name"时,命令没有报错但没有任何输出。把文件路径写成 D:\data\app.xml 传给命令,偶尔也出问题。
原因:XPath 表达式里的路径分隔符必须用正斜杠 /,与文件系统无关。另外 cmd 对反斜杠的转义规则很诡异,参数里出现 \ 时可能被吞掉或转义,导致整个表达式失效。
解决:XPath 内一律用正斜杠;文件路径推荐用正斜杠或者用双引号包住完整路径。
xmlstarlet sel -t -v "/config/setting[1]/@name" "D:/data/app.xml"注意双引号在 cmd 里不是消灭转义问题的万能药。如果路径本身带空格,还要多包一层;如果路径里出现 %USERPROFILE% 这类环境变量,XMLStarlet 不会自动展开,稳妥做法是先用 set 赋值再用,或者直接用绝对路径。
4.3 带 BOM 的 UTF-8 文件解析报错或首个节点取不到
现象:解析同事导出的 XML,命令报错指向文件开头,或者 sel 取第一个节点时结果里出现一个不可见字符。
原因:文件开头有 UTF-8 BOM 头。XML 规范允许解析器识别 BOM,但 1.6.1 的解析器在某些操作上对 BOM 处理不干净,尤其容易把它当成文本内容的一部分送进模板输出。
解决:先格式化重写一次文件,让 XMLStarlet 自己序列化一遍:
xmlstarlet fo -t -n input.xml > input.clean.xml如果 fo 也报错,用文本编辑器把文件另存为「UTF-8 无 BOM」,再跑 fo。从那以后,我只要拿到外部来的 XML 第一件事就是 fo 一遍,既整理了缩进又清掉了 BOM,一举两得。
4.4 sel 查不到任何值,但退出码仍然是 0
现象:跑完xmlstarlet sel ... -v "//nonexistent" file.xml,没有任何输出,但命令执行是成功的,退出码 0。在脚本里用 errorlevel 判断是否成功,结果误判。
原因:XMLStarlet 的 sel 设计如此,XPath 匹配不到节点会被当作「合法空结果」,不是错误。这在命令行交互时无所谓,但放进批处理脚本里就会埋雷,脚本会以为查询成功,继续往下走。
解决:脚本里不要只用退出码判断,要结合输出内容,或者先跑一个 count 探测节点数量:
xmlstarlet sel -t -v "count(//order)" resp.xml把它放进 if 条件判断,数量为 0 时走另一条分支。另一种做法是先跑 val -e 确认文档结构合法,再跑 sel,两件事分开,错误定位就清楚了。
4.5 大文件解析慢得离谱,先确认是不是单线程瓶颈
现象:解析一个 200MB 的 XML,命令执行时间长到像卡死,进度半天不动。
原因:XMLStarlet 是单线程的,而且内部是基于 DOM 构建的,32 位进程的地址空间有限,大文件既慢又容易触发内存不足。
解决:超过 100MB 的 XML 不建议用 1.6.1 硬扛,改用流式处理工具,或者先按顶层元素把文件切割成小块再逐个交给 XMLStarlet。如果只是取个别字段,可以用 grep 先粗筛再精解析,别让一个 DOM 把内存撑爆。命令行小工具再方便,也有能力边界。
5. 进阶技巧:用 sel 的模板输出把 XML 批量转成 CSV
最后分享一个我一直在用的技巧:用 sel 的 -m、-o、-v 组合,把嵌套的 XML 拍平成 CSV,省掉中间写脚本的步骤。原理是模板模式本身就像一个小型循环,对每个匹配节点执行一组固定的输出动作。
xmlstarlet sel -t -m "//book" -v "@id" -o "," -v "title" -o "," -v "substring(price, 1, 5)" -n books.xml > books.csv这条命令把每本书的 id、书名、截断后的价格拼成一行 CSV,-n 在每行末尾换行。XPath 函数可以直接写进 -v,格式化都在表达式里完成,不需要额外脚本。批量处理多个文件时,用 for 循环包一层:
for %f in (*.xml) do xmlstarlet sel -t -m "//book" -v "@id" -o "," -v "title" -n "%f" >> all_books.csv在 cmd 里跑要写单百分号 %f,在批处理文件里要写双百分号 %%f。这个区别我至少翻过两次车,现在每次写循环前都会提醒自己检查当前是命令行还是脚本文件。
输出重定向用 >> 追加而不是 > 覆盖,多个文件的结果才能合到同一个 CSV。字段内容如果本身包含逗号,先看数据里是否出现分隔符,必要时改用 -o "|" 做竖线分隔。最后打开文件确认行数与源节点数一致,数量对不上就回头查 XPath 里的匹配条件。
从那以后,我每次拿到新的 XML 数据源,都强制走一遍「fo 看结构、sel 拍平、val 验证」的流程,三个命令各管一段,基本没有返工过。xmlstarlet 这套工具链虽然老,但在 Windows 32 位环境里依然是把好手,如果你是同样环境又要经常碰 XML,直接下载这份 xmlstarlet-1.6.1-win32.zip 就能用,希望这份经验帮到你。
本文还有配套的精品资源,点击获取