如何用Groovy脚本拆分多值Filter标签为多个XML片段
Groovy脚本实现Filter标签拆分方案
以下是直接可用的Groovy脚本,实现将单个<v1:Filter>拆分为多个,每个ActivityObjectId最多包含5个值,同时保留ActivityCodeTypeName过滤条件:
@Grab('org.codehaus.groovy:groovy-xml:3.0.17') import groovy.xml.XmlSlurper import groovy.xml.XmlUtil // 输入XML内容(也可从文件读取:new File('input.xml').text) def inputXml = '''<?xml version="1.0" encoding="UTF-8"?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v1="http://xmlns.XXXX.com/YY/X6/WS/ActivityCodeAssignment/V1"> <soapenv:Header> <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" soapenv:mustUnderstand="1"> <wsu:Timestamp wsu:Id="TS-d0ce0b7b-c4b2-416c-b2dc-ac95015ffcb9"> <wsu:Created>2023-06-27T18:30:28.298Z</wsu:Created> <wsu:Expires>2023-06-28T11:10:28.298Z</wsu:Expires> </wsu:Timestamp> <wsse:UsernameToken wsu:Id="UsernameToken-d3376a72-8584-4a4c-8929-c84c710ea7eb"> <wsse:Username>XXX</wsse:Username> <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">XXXX</wsse:Password> <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">AAAA</wsse:Nonce> <wsu:Created>2023-06-27T18:30:28.298Z</wsu:Created> </wsse:UsernameToken> </wsse:Security> </soapenv:Header> <soapenv:Body> <v1:ReadActivityCodeAssignments> <v1:Field>ActivityCodeObjectId</v1:Field> <v1:Field>ActivityObjectId</v1:Field> <v1:Field>ActivityCodeValue</v1:Field> <v1:Field>ActivityCodeTypeName</v1:Field> <v1:Field>ActivityCodeTypeObjectId</v1:Field> <v1:Filter>ActivityObjectId IN (6507036,6507037,6507038,6507039,6507040,6507041,6507042,6507043,6507044,6507045,6507046,6507047,6507048) AND ActivityCodeTypeName IN ('SAP Network','SAP Activity','SAP Transfer','SAP WBS Custos','SAP Transfer (PEP)')</v1:Filter> </v1:ReadActivityCodeAssignments> </soapenv:Body> </soapenv:Envelope>''' // 解析XML并启用命名空间支持 def slurper = new XmlSlurper(false, false) def envelope = slurper.parseText(inputXml) envelope.declareNamespace(soapenv: 'http://schemas.xmlsoap.org/soap/envelope/', v1: 'http://xmlns.XXXX.com/YY/X6/WS/ActivityCodeAssignment/V1') // 获取原Filter节点及文本内容 def originalFilter = envelope.Body.ReadActivityCodeAssignments.Filter[0] def filterText = originalFilter.text().trim() // 正则提取ActivityObjectId的ID列表和ActivityCodeTypeName条件 def activityObjectIdPattern = /ActivityObjectId IN\s*\(([^)]+)\)/ def activityCodeTypePattern = /AND\s*(ActivityCodeTypeName IN\s*\([^)]+\))/ def idMatcher = filterText =~ activityObjectIdPattern def codeTypeMatcher = filterText =~ activityCodeTypePattern if (!idMatcher.matches() || !codeTypeMatcher.matches()) { throw new IllegalArgumentException("Filter格式不符合预期") } def idList = idMatcher[0][1].split(/\s*,\s*/).collect { it.trim() } def codeTypeCondition = codeTypeMatcher[0][1].trim() // 将ID列表按每组最多5个拆分 def groupedIds = idList.collate(5) // 删除原Filter节点 originalFilter.replaceNode {} // 为每个ID组创建新的Filter节点 def parentNode = envelope.Body.ReadActivityCodeAssignments groupedIds.each { ids -> def filterContent = """ActivityObjectId IN (${ids.join(',')}) AND ${codeTypeCondition}""" parentNode.appendNode { 'v1:Filter'(filterContent) } } // 格式化输出XML,调整缩进匹配示例风格 def outputXml = XmlUtil.serialize(envelope) outputXml = outputXml.replaceAll(/(?m)^ {8}/, ' ') println(outputXml)
关键逻辑说明
- 命名空间处理:通过
declareNamespace指定XML命名空间,确保节点定位准确。 - 正则提取:用两个正则分别匹配ID集合和类型条件,避免硬编码依赖格式。
- 列表拆分:Groovy内置的
collate(5)方法快速将ID分组,自动处理剩余不足5个的情况。 - 节点替换:删除原Filter后,为每个ID组生成新的
<v1:Filter>节点,保持原XML结构完整。 - 格式化调整:对序列化后的XML缩进进行微调,匹配示例的排版风格。
内容的提问来源于stack exchange,提问作者user1916896
相关产品推荐
相关产品推荐

