如何使用Go的beevik/etree包访问XML兄弟元素并批量赋值?
批量修改XML中符合条件的节点值(beevik/etree)
原始XML文档
<MasterXML> <Processes> <Params> <ParamName>today</ParamName> <ParamType>1</ParamType> <ParamValue/> </Params> <Params> <ParamName>today</ParamName> <ParamType>2</ParamType> <ParamValue/> </Params> <Params> <ParamName>today</ParamName> <ParamType>3</ParamType> <ParamValue/> </Params> </Processes> </MasterXML>
需求
使用Go语言的beevik/etree包,当<ParamName>节点值为today时,为所有<Params>节点下的<ParamValue>填充值05/02/2024。
现有问题代码
现有代码仅能修改首个符合条件的节点,循环遍历所有<ParamName>却无法批量生效:
for _, elem1 := range doc.FindElements(".//Processes//Params//ParamName") { if elem1 == nil { log.Fatal("Check XPath") } s := elem1.Text() if s == "today" { elem2 := elem1.FindElement("//ParamValue") elem2.SetText("05/02/2024") } }
问题原因
核心问题出在XPath的路径选择上:
elem1.FindElement("//ParamValue")中,//开头的XPath是从整个文档的根节点开始全局查找,而非从当前<ParamName>节点的上下文(即其父节点<Params>)中查找。- 所以每次循环都会定位到文档中第一个
<ParamValue>节点,所有修改操作都重复作用在这个节点上,后续的<ParamValue>从未被选中。
解决方案
无需更换实现思路,只需调整节点查找的范围即可,以下两种方案均可:
方案1:使用相对路径查找
修改XPath为相对当前节点的路径,从<ParamName>的父节点(<Params>)下定位<ParamValue>:
for _, elem1 := range doc.FindElements(".//Processes//Params//ParamName") { if elem1.Text() == "today" { // 通过../获取父节点,再查找子节点ParamValue elem2 := elem1.FindElement("../ParamValue") elem2.SetText("05/02/2024") } }
方案2:以<Params>为单位遍历(更直观)
直接遍历所有<Params>节点,在每个节点内部判断<ParamName>的值,再修改对应的<ParamValue>,逻辑更清晰:
for _, params := range doc.FindElements(".//Processes//Params") { paramName := params.FindElement("ParamName") if paramName != nil && paramName.Text() == "today" { paramValue := params.FindElement("ParamValue") if paramValue != nil { paramValue.SetText("05/02/2024") } } }
说明
两种方案都能实现批量修改的需求,方案2的逻辑更直观,直接以<Params>为处理单元,避免了XPath路径的歧义,后续维护也更方便。
内容的提问来源于stack exchange,提问作者Vector
相关产品推荐
相关产品推荐

