使用xmlstarlet复制XML元素内容至Title时的重复值问题
解决XMLStarlet批量修改Product Title时重复内容的问题
问题场景
需求是将XML中每个<product>节点下的Dimensions和Size元素内容,追加到同节点的Title元素末尾。
原XML结构:
<products> <product> <id>01</id> <Title><![CDATA[ Product 1 Title ]]></Title> <Dimensions><![CDATA[ S ]]></Dimensions> <Size><![CDATA[ for Adult ]]></Size> </product> <product> <id>02</id> <Title><![CDATA[ Product 2 Title ]]></Title> <Dimensions><![CDATA[ Medium ]]></Dimensions> <Size><![CDATA[ for Kids ]]></Size> </product> </products>
最初执行的命令:
xmlstarlet ed -u /products/product/Title -x "concat(/products/product/Title,' ',/products/product/Dimensions/text(),' ',/products/product/Size)" sourcefile.xml > outputfile.xml
出现的问题:所有产品的Title都被替换为第一个产品的拼接内容,而非对应自身的Dimensions和Size。
问题原因
原命令中的XPath使用了绝对路径(/products/product/Title),每次计算时都会选取文档中第一个匹配的节点值,导致所有Title都复用了第一个产品的内容。
解决方案
改用相对路径,基于当前被修改的Title节点来定位同层级的Dimensions和Size:
.代表当前正在处理的Title节点../代表当前节点的父节点(即<product>),通过它可以获取同节点下的Dimensions和Size
正确的XMLStarlet命令
xmlstarlet ed -u "/products/product/Title" -x "concat(., ' ', ../Dimensions, ' ', ../Size)" sourcefile.xml > outputfile.xml
执行后得到的期望结果:
<Title><![CDATA[ Product 1 Title S for Adult]]></Title> <Title><![CDATA[ Product 2 Title Medium for Kids]]></Title>
可选:用yq实现(v4+版本)
如果使用支持XML处理的yq v4+,也可以用以下命令实现:
yq eval '.products.product[] |= (.Title |= . + " " + .Dimensions + " " + .Size)' sourcefile.xml > outputfile.xml
内容的提问来源于stack exchange,提问作者weby
相关产品推荐
相关产品推荐

